diff options
17 files changed, 545 insertions, 231 deletions
diff --git a/examples/embedding/java/embedding/ExampleFO2JPSPrint.java b/examples/embedding/java/embedding/ExampleFO2JPSPrint.java new file mode 100644 index 000000000..a67e2bdad --- /dev/null +++ b/examples/embedding/java/embedding/ExampleFO2JPSPrint.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package embedding; + +// Java +import java.io.File; +import java.io.IOException; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.ServiceUI; +import javax.print.SimpleDoc; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.render.print.PageableRenderer; + +/** + * This class demonstrates printing an FO file using JPS (Java Printing System). + */ +public class ExampleFO2JPSPrint { + + // configure fopFactory as desired + private FopFactory fopFactory = FopFactory.newInstance(); + + private DocPrintJob createDocPrintJob() { + PrintService[] services = PrintServiceLookup.lookupPrintServices( + DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); + PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet(); + PrintService printService = ServiceUI.printDialog(null, 50, 50, + services, services[0], null, attributes); + if (printService != null) { + return printService.createPrintJob(); + } else { + return null; + } + } + + /** + * Prints an FO file using JPS. + * @param fo the FO file + * @throws IOException In case of an I/O problem + * @throws FOPException In case of a FOP problem + * @throws TransformerException In case of a problem during XSLT processing + * @throws PrintException If an error occurs while printing + */ + public void printFO(File fo) + throws IOException, FOPException, TransformerException, PrintException { + + //Set up DocPrintJob instance + DocPrintJob printJob = createDocPrintJob(); + + //Set up a custom user agent so we can supply our own renderer instance + FOUserAgent userAgent = fopFactory.newFOUserAgent(); + + PageableRenderer renderer = new PageableRenderer(); + renderer.setUserAgent(userAgent); + userAgent.setRendererOverride(renderer); + + // Construct FOP with desired output format + Fop fop = fopFactory.newFop(userAgent); + + // Setup JAXP using identity transformer + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); // identity transformer + + // Setup input stream + Source src = new StreamSource(fo); + + // Resulting SAX events (the generated FO) must be piped through to FOP + Result res = new SAXResult(fop.getDefaultHandler()); + + // Start XSLT transformation and FOP processing + transformer.transform(src, res); + + Doc doc = new SimpleDoc(renderer, DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); + printJob.print(doc, null); + } + + /** + * Main method. + * @param args command-line arguments + */ + public static void main(String[] args) { + try { + System.out.println("FOP ExampleFO2JPSPrint\n"); + System.out.println("Preparing..."); + + //Setup directories + File baseDir = new File("."); + File outDir = new File(baseDir, "out"); + outDir.mkdirs(); + + //Setup input and output files + File fofile = new File(baseDir, "xml/fo/helloworld.fo"); + + System.out.println("Input: XSL-FO (" + fofile + ")"); + System.out.println("Output: JPS (Java Printing System)"); + System.out.println(); + System.out.println("Transforming..."); + + ExampleFO2JPSPrint app = new ExampleFO2JPSPrint(); + app.printFO(fofile); + + System.out.println("Success!"); + } catch (Exception e) { + e.printStackTrace(System.err); + System.exit(-1); + } + } +} diff --git a/src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory b/src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory index 9fa7b8d04..1ad959188 100644 --- a/src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory +++ b/src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory @@ -2,3 +2,4 @@ org.apache.fop.events.ValidationExceptionFactory org.apache.fop.events.PropertyExceptionFactory
org.apache.fop.events.UnsupportedOperationExceptionFactory
org.apache.fop.layoutmgr.LayoutException$LayoutExceptionFactory
+org.apache.fop.fo.pagination.PageProductionException$PageProductionExceptionFactory
diff --git a/src/java/org/apache/fop/apps/FOPException.java b/src/java/org/apache/fop/apps/FOPException.java index 851712b09..d8ac2e2f7 100644 --- a/src/java/org/apache/fop/apps/FOPException.java +++ b/src/java/org/apache/fop/apps/FOPException.java @@ -103,7 +103,7 @@ public class FOPException extends SAXException { * @param systemId the system id of the FO document which is associated with the exception; * may be null. * @param line line number in the FO document which is associated with the exception. - * @param column clolumn number in the line which is associated with the exception. + * @param column column number in the line which is associated with the exception. */ public void setLocation(String systemId, int line, int column) { this.systemId = systemId; diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index da7ef1def..745160d44 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -124,6 +124,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl if (original.extensionAttachments != null) { this.extensionAttachments = new java.util.ArrayList(original.extensionAttachments); } + this.pageIndex = original.pageIndex; this.pageNumber = original.pageNumber; this.pageNumberString = original.pageNumberString; this.page = (Page)original.page.clone(); diff --git a/src/java/org/apache/fop/area/RenderPagesModel.java b/src/java/org/apache/fop/area/RenderPagesModel.java index b21566902..64159cca7 100644 --- a/src/java/org/apache/fop/area/RenderPagesModel.java +++ b/src/java/org/apache/fop/area/RenderPagesModel.java @@ -31,6 +31,7 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererEventProducer; /** * This uses the AreaTreeModel to store the pages @@ -115,8 +116,12 @@ public class RenderPagesModel extends AreaTreeModel { String err = "Error while rendering page " + page.getPageNumberString(); log.error(err, re); throw re; - } catch (Exception e) { - //TODO use error handler to handle this FOP or IO Exception or propagate exception + } catch (IOException ioe) { + RendererEventProducer eventProducer = RendererEventProducer.Provider.get( + renderer.getUserAgent().getEventBroadcaster()); + eventProducer.ioError(this, ioe); + } catch (FOPException e) { + //TODO use error handler to handle this FOPException or propagate exception String err = "Error while rendering page " + page.getPageNumberString(); log.error(err, e); throw new IllegalStateException("Fatal error occurred. Cannot continue. " diff --git a/src/java/org/apache/fop/fo/pagination/PageProductionException.java b/src/java/org/apache/fop/fo/pagination/PageProductionException.java new file mode 100644 index 000000000..068e38ff8 --- /dev/null +++ b/src/java/org/apache/fop/fo/pagination/PageProductionException.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.pagination; + +import java.util.Locale; + +import org.xml.sax.Locator; +import org.xml.sax.helpers.LocatorImpl; + +import org.apache.fop.events.Event; +import org.apache.fop.events.EventFormatter; +import org.apache.fop.events.EventExceptionManager.ExceptionFactory; + +/** + * Exception thrown by FOP if there is a problem while producing new pages. + */ +public class PageProductionException extends RuntimeException { + + private static final long serialVersionUID = -5126033718398975158L; + + private String localizedMessage; + private Locator locator; + + /** + * Creates a new PageProductionException. + * @param message the message + * @param locator the optional locator that points to the error in the source file + */ + public PageProductionException(String message, Locator locator) { + super(message); + setLocator(locator); + } + + /** + * Set a location associated with the exception. + * @param locator the locator holding the location. + */ + public void setLocator(Locator locator) { + this.locator = new LocatorImpl(locator); + } + + + /** + * Returns the locattion associated with the exception. + * @return the locator or null if the location information is not available + */ + public Locator getLocator() { + return this.locator; + } + + /** + * Sets the localized message for this exception. + * @param msg the localized message + */ + public void setLocalizedMessage(String msg) { + this.localizedMessage = msg; + } + + /** {@inheritDoc} */ + public String getLocalizedMessage() { + if (this.localizedMessage != null) { + return this.localizedMessage; + } else { + return super.getLocalizedMessage(); + } + } + + /** Exception factory for {@link PageProductionException}. */ + public static class PageProductionExceptionFactory implements ExceptionFactory { + + /** {@inheritDoc} */ + public Throwable createException(Event event) { + Object obj = event.getParam("loc"); + Locator loc = (obj instanceof Locator ? (Locator)obj : null); + String msg = EventFormatter.format(event, Locale.ENGLISH); + PageProductionException ex = new PageProductionException(msg, loc); + if (!Locale.ENGLISH.equals(Locale.getDefault())) { + ex.setLocalizedMessage(EventFormatter.format(event)); + } + return ex; + } + + /** {@inheritDoc} */ + public Class getExceptionClass() { + return PageProductionException.class; + } + + } +} diff --git a/src/java/org/apache/fop/fo/pagination/PageSequence.java b/src/java/org/apache/fop/fo/pagination/PageSequence.java index 3d155a1da..3c7cfb197 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequence.java @@ -371,13 +371,13 @@ public class PageSequence extends AbstractPageSequence { * page sequence * @param isBlank indicator whether the page will be blank * @return the SimplePageMaster to use for this page - * @throws FOPException if there's a problem determining the page master + * @throws PageProductionException if there's a problem determining the page master */ public SimplePageMaster getNextSimplePageMaster(int page, boolean isFirstPage, boolean isLastPage, boolean isOnlyPage, - boolean isBlank) throws FOPException { + boolean isBlank) throws PageProductionException { if (pageSequenceMaster == null) { return simplePageMaster; diff --git a/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java b/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java index 4258a1139..b6c8c0f6b 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java @@ -189,14 +189,14 @@ public class PageSequenceMaster extends FObj { * @param isOnlyPage True if the next page is the only page * @param isBlankPage True if the next page is blank * @return the requested page master - * @throws FOPException if there's a problem determining the next page master + * @throws PageProductionException if there's a problem determining the next page master */ public SimplePageMaster getNextSimplePageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isOnlyPage, boolean isBlankPage) - throws FOPException { + throws PageProductionException { if (currentSubSequence == null) { currentSubSequence = getNextSubSequence(); if (currentSubSequence == null) { diff --git a/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java b/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java index 5da4945f1..0bad65a7c 100644 --- a/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java +++ b/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java @@ -19,7 +19,6 @@ package org.apache.fop.fo.pagination; -import org.apache.fop.apps.FOPException; /** * Classes that implement this interface can be added to a PageSequenceMaster, @@ -35,14 +34,14 @@ public interface SubSequenceSpecifier { * @param isOnlyPage True if the next page is the only page * @param isBlankPage True if the next page is blank * @return the page master name - * @throws FOPException if there's a problem determining the next page master + * @throws PageProductionException if there's a problem determining the next page master */ String getNextPageMasterName(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isOnlyPage, boolean isBlankPage) - throws FOPException; + throws PageProductionException; /** * Called before a new page sequence is rendered so subsequences can reset diff --git a/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java b/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java index c31a70477..b1dd7ef5d 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java @@ -21,9 +21,9 @@ package org.apache.fop.layoutmgr; import org.xml.sax.Locator; -import org.apache.fop.apps.FOPException; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.events.EventProducer; +import org.apache.fop.fo.pagination.PageProductionException; /** * Event producer interface for block-level layout managers. @@ -136,22 +136,22 @@ public interface BlockLevelEventProducer extends EventProducer { * @param pageSequenceMasterName the name of the page sequence master * @param canRecover indicates whether FOP can recover from this problem and continue working * @param loc the location of the error or null - * @throws FOPException the error provoked by the method call + * @throws PageProductionException the error provoked by the method call * @event.severity FATAL */ void pageSequenceMasterExhausted(Object source, String pageSequenceMasterName, - boolean canRecover, Locator loc) throws FOPException; + boolean canRecover, Locator loc) throws PageProductionException; /** * No subsequences in page sequence master. * @param source the event source * @param pageSequenceMasterName the name of the page sequence master * @param loc the location of the error or null - * @throws FOPException the error provoked by the method call + * @throws PageProductionException the error provoked by the method call * @event.severity FATAL */ void missingSubsequencesInPageSequenceMaster(Object source, String pageSequenceMasterName, - Locator loc) throws FOPException; + Locator loc) throws PageProductionException; /** * No single-page-master matching in page sequence master. @@ -159,10 +159,10 @@ public interface BlockLevelEventProducer extends EventProducer { * @param pageSequenceMasterName the name of the page sequence master * @param pageMasterName the name of the page master not matching * @param loc the location of the error or null - * @throws FOPException the error provoked by the method call + * @throws PageProductionException the error provoked by the method call * @event.severity FATAL */ void noMatchingPageMaster(Object source, String pageSequenceMasterName, - String pageMasterName, Locator loc) throws FOPException; + String pageMasterName, Locator loc) throws PageProductionException; } diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java index 037f02094..a7918db6e 100644 --- a/src/java/org/apache/fop/layoutmgr/PageProvider.java +++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java @@ -24,7 +24,6 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.apps.FOPException; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.Constants; import org.apache.fop.fo.pagination.PageSequence; @@ -196,10 +195,10 @@ public class PageProvider implements Constants { } /** - * - * @param isBlank true if the Page should be a blank one + * Returns a Page. + * @param isBlank true if the Page should be a blank one * @param index the Page's index - * @return a Page instance + * @return a Page instance */ protected Page getPage(boolean isBlank, int index) { boolean isLastPage = (lastPageIndex >= 0) && (index == lastPageIndex); @@ -251,31 +250,25 @@ public class PageProvider implements Constants { } private Page cacheNextPage(int index, boolean isBlank, boolean isLastPage) { - try { - String pageNumberString = pageSeq.makeFormattedPageNumber(index); - SimplePageMaster spm = pageSeq.getNextSimplePageMaster( - index, (startPageOfPageSequence == index), isLastPage, false, isBlank); - - Region body = spm.getRegion(FO_REGION_BODY); - if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) { - // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to - // any region), but we don't support it yet. - BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( - pageSeq.getUserAgent().getEventBroadcaster()); - eventProducer.flowNotMappingToRegionBody(this, - pageSeq.getMainFlow().getFlowName(), spm.getMasterName(), spm.getLocator()); - } - Page page = new Page(spm, index, pageNumberString, isBlank); - //Set unique key obtained from the AreaTreeHandler - page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey()); - page.getPageViewport().setForeignAttributes(spm.getForeignAttributes()); - cachedPages.add(page); - return page; - } catch (FOPException e) { - //TODO Maybe improve. It'll mean to propagate this exception up several - //methods calls. - throw new IllegalStateException(e.getMessage()); + String pageNumberString = pageSeq.makeFormattedPageNumber(index); + SimplePageMaster spm = pageSeq.getNextSimplePageMaster( + index, (startPageOfPageSequence == index), isLastPage, false, isBlank); + + Region body = spm.getRegion(FO_REGION_BODY); + if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) { + // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to + // any region), but we don't support it yet. + BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( + pageSeq.getUserAgent().getEventBroadcaster()); + eventProducer.flowNotMappingToRegionBody(this, + pageSeq.getMainFlow().getFlowName(), spm.getMasterName(), spm.getLocator()); } + Page page = new Page(spm, index, pageNumberString, isBlank); + //Set unique key obtained from the AreaTreeHandler + page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey()); + page.getPageViewport().setForeignAttributes(spm.getForeignAttributes()); + cachedPages.add(page); + return page; } - + }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index ca3d007d0..816fa4067 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -124,12 +124,19 @@ public abstract class AbstractRenderer /** {@inheritDoc} */ public FOUserAgent getUserAgent() { + if (userAgent == null) { + throw new IllegalStateException("FOUserAgent has not been set on Renderer"); + } return userAgent; } /** {@inheritDoc} */ public void startRenderer(OutputStream outputStream) - throws IOException { } + throws IOException { + if (userAgent == null) { + throw new IllegalStateException("FOUserAgent has not been set on Renderer"); + } + } /** {@inheritDoc} */ public void stopRenderer() diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 1f3194949..db8ed6250 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -198,6 +198,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem /** {@inheritDoc} */ public void startRenderer(OutputStream out) throws IOException { + super.startRenderer(out); // do nothing by default } @@ -232,7 +233,9 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem } /** + * Returns the number of pages available. This method is also part of the Pageable interface. * @return The 0-based total number of rendered pages + * @see java.awt.print.Pageable */ public int getNumberOfPages() { return pageViewportList.size(); @@ -250,7 +253,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem /** * This method override only stores the PageViewport in a List. No actual * rendering is performed here. A renderer override renderPage() to get the - * freshly produced PageViewport, and rendere them on the fly (producing the + * freshly produced PageViewport, and render them on the fly (producing the * desired BufferedImages by calling getPageImage(), which lazily starts the * rendering process). * @@ -260,12 +263,23 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem * @see org.apache.fop.render.Renderer */ public void renderPage(PageViewport pageViewport) throws IOException { - // TODO clone? - pageViewportList.add(pageViewport.clone()); + rememberPage((PageViewport)pageViewport.clone()); + //The clone() call is necessary as we store the page for later. Otherwise, the + //RenderPagesModel calls PageViewport.clear() to release memory as early as possible. currentPageNumber++; } /** + * Stores the pageViewport in a list of page viewports so they can be rendered later. + * Subclasses can override this method to filter pages, for example. + * @param pageViewport the page viewport + */ + protected void rememberPage(PageViewport pageViewport) { + assert pageViewport.getPageIndex() >= 0; + pageViewportList.add(pageViewport); + } + + /** * Generates a desired page from the renderer's page viewport list. * * @param pageViewport the PageViewport to be rendered @@ -362,17 +376,17 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem /** * Returns a page viewport. - * @param pageNum the page number + * @param pageIndex the page index (zero-based) * @return the requested PageViewport instance * @exception FOPException If the page is out of range. */ - public PageViewport getPageViewport(int pageNum) throws FOPException { - if (pageNum < 0 || pageNum >= pageViewportList.size()) { - throw new FOPException("Requested page number is out of range: " + pageNum + public PageViewport getPageViewport(int pageIndex) throws FOPException { + if (pageIndex < 0 || pageIndex >= pageViewportList.size()) { + throw new FOPException("Requested page number is out of range: " + pageIndex + "; only " + pageViewportList.size() + " page(s) available."); } - return (PageViewport) pageViewportList.get(pageNum); + return (PageViewport) pageViewportList.get(pageIndex); } /** diff --git a/src/java/org/apache/fop/render/print/PageableRenderer.java b/src/java/org/apache/fop/render/print/PageableRenderer.java new file mode 100644 index 000000000..947708cef --- /dev/null +++ b/src/java/org/apache/fop/render/print/PageableRenderer.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.print; + +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.io.IOException; +import java.util.Map; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.area.PageViewport; +import org.apache.fop.render.java2d.Java2DRenderer; + +/** + * Renderer that prints through java.awt.PrintJob. + * The actual printing is handled by Java2DRenderer + * since both PrintRenderer and AWTRenderer need to + * support printing. + */ +public class PageableRenderer extends Java2DRenderer implements Pageable { + + /** + * Printing parameter: the pages to be printed (all, even or odd), + * datatype: the strings "all", "even" or "odd" or one of PagesMode.* + */ + public static final String PAGES_MODE = "even-odd"; + + /** + * Printing parameter: the page number (1-based) of the first page to be printed, + * datatype: a positive Integer + */ + public static final String START_PAGE = "start-page"; + + /** + * Printing parameter: the page number (1-based) of the last page to be printed, + * datatype: a positive Integer + */ + public static final String END_PAGE = "end-page"; + + + /** first valid page number (1-based) */ + protected int startNumber = 0; + /** last valid page number (1-based) */ + protected int endNumber = -1; + + /** indicates which pages are valid: odd, even or all */ + protected PagesMode mode = PagesMode.ALL; + + private PageFilter pageFilter; + + /** + * Creates a new PageableRenderer. + */ + public PageableRenderer() { + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent agent) { + super.setUserAgent(agent); + + Map rendererOptions = agent.getRendererOptions(); + processOptions(rendererOptions); + this.pageFilter = new DefaultPageFilter(); + } + + private void processOptions(Map rendererOptions) { + Object o = rendererOptions.get(PageableRenderer.PAGES_MODE); + if (o != null) { + if (o instanceof PagesMode) { + this.mode = (PagesMode)o; + } else if (o instanceof String) { + this.mode = PagesMode.byName((String)o); + } else { + throw new IllegalArgumentException( + "Renderer option " + PageableRenderer.PAGES_MODE + + " must be an 'all', 'even', 'odd' or a PagesMode instance."); + } + } + + o = rendererOptions.get(PageableRenderer.START_PAGE); + if (o != null) { + this.startNumber = getPositiveInteger(o); + } + o = rendererOptions.get(PageableRenderer.END_PAGE); + if (o != null) { + this.endNumber = getPositiveInteger(o); + } + if (this.endNumber >= 0 && this.endNumber < this.endNumber) { + this.endNumber = this.startNumber; + } + } + + /** + * Converts an object into a positive integer value if possible. The method throws an + * {@link IllegalArgumentException} if the value is invalid. + * @param o the object to be converted + * @return the positive integer + */ + protected int getPositiveInteger(Object o) { + if (o instanceof Integer) { + Integer i = (Integer)o; + if (i.intValue() < 1) { + throw new IllegalArgumentException( + "Value must be a positive Integer"); + } + return i.intValue(); + } else if (o instanceof String) { + return Integer.parseInt((String)o); + } else { + throw new IllegalArgumentException( + "Value must be a positive integer"); + } + } + + /** {@inheritDoc} */ + public void stopRenderer() throws IOException { + super.stopRenderer(); + + if (endNumber == -1) { + // was not set on command line + endNumber = getNumberOfPages(); + } + } + + /** {@inheritDoc} */ + protected void rememberPage(PageViewport pageViewport) { + if (this.pageFilter.isValid(pageViewport)) { + super.rememberPage(pageViewport); + } + } + + private interface PageFilter { + boolean isValid(PageViewport page); + } + + private class DefaultPageFilter implements PageFilter { + + public boolean isValid(PageViewport page) { + int pageNum = page.getPageIndex() + 1; + assert pageNum >= 0; + if (pageNum < startNumber || (endNumber >= 0 && pageNum > endNumber)) { + return false; + } else if (mode != PagesMode.ALL) { + if (mode == PagesMode.EVEN && (pageNum % 2 != 0)) { + return false; + } else if (mode == PagesMode.ODD && (pageNum % 2 == 0)) { + return false; + } + } + return true; + } + } + + /** {@inheritDoc} */ + public PageFormat getPageFormat(int pageIndex) + throws IndexOutOfBoundsException { + try { + if (pageIndex >= getNumberOfPages()) { + return null; + } + + PageFormat pageFormat = new PageFormat(); + + Paper paper = new Paper(); + + Rectangle2D dim = getPageViewport(pageIndex).getViewArea(); + double width = dim.getWidth(); + double height = dim.getHeight(); + + // if the width is greater than the height assume landscape mode + // and swap the width and height values in the paper format + if (width > height) { + paper.setImageableArea(0, 0, height / 1000d, width / 1000d); + paper.setSize(height / 1000d, width / 1000d); + pageFormat.setOrientation(PageFormat.LANDSCAPE); + } else { + paper.setImageableArea(0, 0, width / 1000d, height / 1000d); + paper.setSize(width / 1000d, height / 1000d); + pageFormat.setOrientation(PageFormat.PORTRAIT); + } + pageFormat.setPaper(paper); + return pageFormat; + } catch (FOPException fopEx) { + throw new IndexOutOfBoundsException(fopEx.getMessage()); + } + } + + /** {@inheritDoc} */ + public Printable getPrintable(int pageIndex) + throws IndexOutOfBoundsException { + return this; + } +} diff --git a/src/java/org/apache/fop/render/print/PrintRenderer.java b/src/java/org/apache/fop/render/print/PrintRenderer.java index 2774b5373..888776ecb 100644 --- a/src/java/org/apache/fop/render/print/PrintRenderer.java +++ b/src/java/org/apache/fop/render/print/PrintRenderer.java @@ -19,20 +19,12 @@ package org.apache.fop.render.print; -import java.awt.geom.Rectangle2D; -import java.awt.print.PageFormat; -import java.awt.print.Pageable; -import java.awt.print.Paper; -import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.IOException; import java.util.Map; -import java.util.Vector; -import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.render.java2d.Java2DRenderer; /** * Renderer that prints through java.awt.PrintJob. @@ -40,7 +32,7 @@ import org.apache.fop.render.java2d.Java2DRenderer; * since both PrintRenderer and AWTRenderer need to * support printing. */ -public class PrintRenderer extends Java2DRenderer implements Pageable { +public class PrintRenderer extends PageableRenderer { /** * Printing parameter: the preconfigured PrinterJob to use, @@ -49,45 +41,21 @@ public class PrintRenderer extends Java2DRenderer implements Pageable { public static final String PRINTER_JOB = "printerjob"; /** - * Printing parameter: the pages to be printed (all, even or odd), - * datatype: the strings "all", "even" or "odd" or one of PagesMode.* - */ - public static final String PAGES_MODE = "even-odd"; - - /** - * Printing parameter: the page number (1-based) of the first page to be printed, - * datatype: a positive Integer - */ - public static final String START_PAGE = "start-page"; - - /** - * Printing parameter: the page number (1-based) of the last page to be printed, - * datatype: a positive Integer - */ - public static final String END_PAGE = "end-page"; - - /** * Printing parameter: the number of copies of the document to be printed, * datatype: a positive Integer */ public static final String COPIES = "copies"; - private int startNumber = 0; - private int endNumber = -1; - - private PagesMode mode = PagesMode.ALL; - private int copies = 1; private PrinterJob printerJob; /** - * Creates a new PrintRenderer with the options set from system properties if a custom + * Creates a new PrintRenderer with the options set through the renderer options if a custom * PrinterJob is not given in FOUserAgent's renderer options. */ public PrintRenderer() { - setupFromSystemProperties(); } /** @@ -117,18 +85,6 @@ public class PrintRenderer extends Java2DRenderer implements Pageable { } } - private void setupFromSystemProperties() { - //TODO Remove me! This is not a beautiful way to do this. - // read from command-line options - copies = getIntProperty("copies", 1); - startNumber = getIntProperty("start", 1); - endNumber = getIntProperty("end", -1); - String str = System.getProperty("even"); - if (str != null) { - mode = Boolean.valueOf(str).booleanValue() ? PagesMode.EVEN : PagesMode.ODD; - } - } - /** {@inheritDoc} */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); @@ -146,53 +102,13 @@ public class PrintRenderer extends Java2DRenderer implements Pageable { printerJob = (PrinterJob)printerJobO; printerJob.setPageable(this); } - Object o = rendererOptions.get(PrintRenderer.PAGES_MODE); - if (o != null) { - if (o instanceof PagesMode) { - this.mode = (PagesMode)o; - } else if (o instanceof String) { - this.mode = PagesMode.byName((String)o); - } else { - throw new IllegalArgumentException( - "Renderer option " + PrintRenderer.PAGES_MODE - + " must be an 'all', 'even', 'odd' or a PagesMode instance."); - } - } - - o = rendererOptions.get(PrintRenderer.START_PAGE); - if (o != null) { - this.startNumber = getPositiveInteger(o); - } - o = rendererOptions.get(PrintRenderer.END_PAGE); - if (o != null) { - this.endNumber = getPositiveInteger(o); - } - if (this.endNumber >= 0 && this.endNumber < this.endNumber) { - this.endNumber = this.startNumber; - } - o = rendererOptions.get(PrintRenderer.COPIES); + Object o = rendererOptions.get(PrintRenderer.COPIES); if (o != null) { this.copies = getPositiveInteger(o); } initializePrinterJob(); } - private int getPositiveInteger(Object o) { - if (o instanceof Integer) { - Integer i = (Integer)o; - if (i.intValue() < 1) { - throw new IllegalArgumentException( - "Value must be a positive Integer"); - } - return i.intValue(); - } else if (o instanceof String) { - return Integer.parseInt((String)o); - } else { - throw new IllegalArgumentException( - "Value must be a positive integer"); - } - } - /** @return the PrinterJob instance that this renderer prints to */ public PrinterJob getPrinterJob() { return this.printerJob; @@ -228,17 +144,6 @@ public class PrintRenderer extends Java2DRenderer implements Pageable { public void stopRenderer() throws IOException { super.stopRenderer(); - if (endNumber == -1) { - // was not set on command line - endNumber = getNumberOfPages(); - } - - Vector numbers = getInvalidPageNumbers(); - for (int i = numbers.size() - 1; i > -1; i--) { - int page = ((Integer)numbers.elementAt(i)).intValue(); - pageViewportList.remove(page - 1); - } - try { printerJob.print(); } catch (PrinterException e) { @@ -249,79 +154,4 @@ public class PrintRenderer extends Java2DRenderer implements Pageable { clearViewportList(); } - private static int getIntProperty(String name, int def) { - String propValue = System.getProperty(name); - if (propValue != null) { - try { - return Integer.parseInt(propValue); - } catch (Exception e) { - return def; - } - } else { - return def; - } - } - - private Vector getInvalidPageNumbers() { - Vector vec = new Vector(); - int max = getNumberOfPages(); - boolean isValid; - for (int i = 1; i <= max; i++) { - isValid = true; - if (i < startNumber || i > endNumber) { - isValid = false; - } else if (mode != PagesMode.ALL) { - if (mode == PagesMode.EVEN && (i % 2 != 0)) { - isValid = false; - } else if (mode == PagesMode.ODD && (i % 2 == 0)) { - isValid = false; - } - } - - if (!isValid) { - vec.add(new Integer(i)); - } - } - return vec; - } - - /** {@inheritDoc} */ - public PageFormat getPageFormat(int pageIndex) - throws IndexOutOfBoundsException { - try { - if (pageIndex >= getNumberOfPages()) { - return null; - } - - PageFormat pageFormat = new PageFormat(); - - Paper paper = new Paper(); - - Rectangle2D dim = getPageViewport(pageIndex).getViewArea(); - double width = dim.getWidth(); - double height = dim.getHeight(); - - // if the width is greater than the height assume lanscape mode - // and swap the width and height values in the paper format - if (width > height) { - paper.setImageableArea(0, 0, height / 1000d, width / 1000d); - paper.setSize(height / 1000d, width / 1000d); - pageFormat.setOrientation(PageFormat.LANDSCAPE); - } else { - paper.setImageableArea(0, 0, width / 1000d, height / 1000d); - paper.setSize(width / 1000d, height / 1000d); - pageFormat.setOrientation(PageFormat.PORTRAIT); - } - pageFormat.setPaper(paper); - return pageFormat; - } catch (FOPException fopEx) { - throw new IndexOutOfBoundsException(fopEx.getMessage()); - } - } - - /** {@inheritDoc} */ - public Printable getPrintable(int pageIndex) - throws IndexOutOfBoundsException { - return this; - } } diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index 88e34e17a..05aade551 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -242,9 +242,6 @@ public class RTFHandler extends FOEventHandler { bFooterSpecified = false; } catch (IOException ioe) { handleIOTrouble(ioe); - } catch (FOPException fope) { - // TODO could we throw Exception in all FOEventHandler events? - log.error("startPageSequence: " + fope.getMessage(), fope); } } diff --git a/status.xml b/status.xml index c2bb24a52..009c827c9 100644 --- a/status.xml +++ b/status.xml @@ -59,6 +59,10 @@ <action context="Renderers" dev="AC" importance="high" type="add"> Added de-duplication and externalization support for IOCA and GOCA data resource objects. </action> + <action context="Renderers" dev="JM" type="add"> + Added support for rendering pages using JPS (Java Printing System). See new example: + examples/embedding/java/ExamplesFO2JPSPrint.java + </action> <action context="Renderers" dev="JM" type="add" fixes-bug="41687"> Restored ability to specify from/to and odd/even pages as well as the number of copies for printing from the command-line. |