Modified: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/src/java/org/apache/fop/render/ps/ResourceHandler.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/src/java/org/apache/fop/render/ps/ResourceHandler.java?rev=727405&r1=727404&r2=727405&view=diff ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/src/java/org/apache/fop/render/ps/ResourceHandler.java (original) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/src/java/org/apache/fop/render/ps/ResourceHandler.java Wed Dec 17 07:01:21 2008 @@ -21,7 +21,6 @@ import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; -import java.awt.image.RenderedImage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -29,27 +28,22 @@ import java.util.Map; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; -import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; -import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; -import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; -import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; -import org.apache.xmlgraphics.image.loader.impl.ImageRendered; -import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.ps.DSCConstants; import org.apache.xmlgraphics.ps.FormGenerator; -import org.apache.xmlgraphics.ps.ImageEncoder; -import org.apache.xmlgraphics.ps.ImageFormGenerator; import org.apache.xmlgraphics.ps.PSGenerator; -import org.apache.xmlgraphics.ps.PSProcSets; +import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.DSCException; import org.apache.xmlgraphics.ps.dsc.DSCFilter; +import org.apache.xmlgraphics.ps.dsc.DSCListener; import org.apache.xmlgraphics.ps.dsc.DSCParser; import org.apache.xmlgraphics.ps.dsc.DSCParserConstants; import org.apache.xmlgraphics.ps.dsc.DefaultNestedDocumentHandler; @@ -59,17 +53,21 @@ import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentNeededResources; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentSuppliedResources; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentIncludeResource; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentLanguageLevel; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages; import org.apache.xmlgraphics.ps.dsc.events.DSCEvent; import org.apache.xmlgraphics.ps.dsc.events.DSCHeaderComment; import org.apache.xmlgraphics.ps.dsc.events.PostScriptComment; +import org.apache.xmlgraphics.ps.dsc.events.PostScriptLine; import org.apache.xmlgraphics.ps.dsc.tools.DSCTools; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.ImageHandlerRegistry; /** * This class is used when two-pass production is used to generate the PostScript file (setting @@ -79,28 +77,79 @@ */ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { + /** logging instance */ + private static Log log = LogFactory.getLog(ResourceHandler.class); + + private FOUserAgent userAgent; + private FontInfo fontInfo; + + private ResourceTracker resTracker; + + //key: URI, values PSImageFormResource + private Map globalFormResources = new java.util.HashMap(); + //key: PSResource, values PSImageFormResource + private Map inlineFormResources = new java.util.HashMap(); + /** - * Rewrites the temporary PostScript file generated by PSRenderer adding all needed resources - * (fonts and images). + * Main constructor. * @param userAgent the FO user agent - * @param in the InputStream for the temporary PostScript file - * @param out the OutputStream to write the finished file to * @param fontInfo the font information * @param resTracker the resource tracker to use * @param formResources Contains all forms used by this document (maintained by PSRenderer) + */ + public ResourceHandler(FOUserAgent userAgent, FontInfo fontInfo, + ResourceTracker resTracker, Map formResources) { + this.userAgent = userAgent; + this.fontInfo = fontInfo; + this.resTracker = resTracker; + determineInlineForms(formResources); + } + + /** + * This method splits up the form resources map into two. One for global forms which + * have been referenced more than once, and one for inline forms which have only been + * used once. The latter is to conserve memory in the PostScript interpreter. + * @param formResources the original form resources map + */ + private void determineInlineForms(Map formResources) { + if (formResources == null) { + return; + } + Iterator iter = formResources.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + PSResource res = (PSResource)entry.getValue(); + long count = resTracker.getUsageCount(res); + if (count > 1) { + //Make global form + this.globalFormResources.put(entry.getKey(), res); + } else { + //Inline resource + this.inlineFormResources.put(res, res); + resTracker.declareInlined(res); + } + } + } + + /** + * Rewrites the temporary PostScript file generated by PSRenderer adding all needed resources + * (fonts and images). + * @param in the InputStream for the temporary PostScript file + * @param out the OutputStream to write the finished file to * @param pageCount the number of pages (given here because PSRenderer writes an "(atend)") * @param documentBoundingBox the document's bounding box * (given here because PSRenderer writes an "(atend)") * @throws DSCException If there's an error in the DSC structure of the PS file * @throws IOException In case of an I/O error */ - public static void process(FOUserAgent userAgent, InputStream in, OutputStream out, - FontInfo fontInfo, ResourceTracker resTracker, Map formResources, + public void process(InputStream in, OutputStream out, int pageCount, Rectangle2D documentBoundingBox) throws DSCException, IOException { DSCParser parser = new DSCParser(in); + PSGenerator gen = new PSGenerator(out); - parser.setNestedDocumentHandler(new DefaultNestedDocumentHandler(gen)); + parser.addListener(new DefaultNestedDocumentHandler(gen)); + parser.addListener(new IncludeResourceListener(gen)); //Skip DSC header DSCHeaderComment header = DSCTools.checkAndSkipDSC30Header(parser); @@ -140,7 +189,7 @@ new DSCCommentHiResBoundingBox(documentBoundingBox).generate(gen); PSFontUtils.determineSuppliedFonts(resTracker, fontInfo, fontInfo.getUsedFonts()); - registerSuppliedForms(resTracker, formResources); + registerSuppliedForms(resTracker, globalFormResources); //Supplied Resources DSCCommentDocumentSuppliedResources supplied @@ -174,7 +223,7 @@ throw new DSCException("Didn't find %FOPFontSetup comment in stream"); } PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts()); - generateForms(resTracker, userAgent, formResources, gen); + generateForms(globalFormResources, gen); //Skip the prolog and to the first page DSCComment pageOrTrailer = parser.nextDSCComment(DSCConstants.PAGE, gen); @@ -218,115 +267,64 @@ } } - private static void generateForms(ResourceTracker resTracker, FOUserAgent userAgent, - Map formResources, PSGenerator gen) throws IOException { + private void generateForms(Map formResources, PSGenerator gen) throws IOException { if (formResources == null) { return; } Iterator iter = formResources.values().iterator(); while (iter.hasNext()) { PSImageFormResource form = (PSImageFormResource)iter.next(); - final String uri = form.getImageURI(); + generateFormForImage(gen, form); + } + } - ImageManager manager = userAgent.getFactory().getImageManager(); - ImageInfo info = null; - try { - ImageSessionContext sessionContext = userAgent.getImageSessionContext(); - info = manager.getImageInfo(uri, sessionContext); - - ImageFlavor[] flavors; - if (gen.getPSLevel() >= 3) { - flavors = LEVEL_3_FLAVORS_FORM; - } else { - flavors = LEVEL_2_FLAVORS_FORM; - } - Map hints = ImageUtil.getDefaultHints(sessionContext); - org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, flavors, hints, sessionContext); - - String imageDescription = info.getMimeType() + " " + info.getOriginalURI(); - final Dimension2D dimensionsPt = info.getSize().getDimensionPt(); - final Dimension2D dimensionsMpt = info.getSize().getDimensionMpt(); - - if (img instanceof ImageGraphics2D) { - final ImageGraphics2D imageG2D = (ImageGraphics2D)img; - FormGenerator formGen = new FormGenerator( - form.getName(), imageDescription, dimensionsPt) { - - protected void generatePaintProc(PSGenerator gen) - throws IOException { - gen.getResourceTracker().notifyResourceUsageOnPage( - PSProcSets.EPS_PROCSET); - gen.writeln("BeginEPSF"); - PSGraphics2DAdapter adapter = new PSGraphics2DAdapter(gen, false); - adapter.paintImage(imageG2D.getGraphics2DImagePainter(), - null, - 0, 0, - (int)Math.round(dimensionsMpt.getWidth()), - (int)Math.round(dimensionsMpt.getHeight())); - gen.writeln("EndEPSF"); - } + private void generateFormForImage(PSGenerator gen, PSImageFormResource form) + throws IOException { + final String uri = form.getImageURI(); + + ImageManager manager = userAgent.getFactory().getImageManager(); + ImageInfo info = null; + try { + ImageSessionContext sessionContext = userAgent.getImageSessionContext(); + info = manager.getImageInfo(uri, sessionContext); + + //Create a rendering context for form creation + PSRenderingContext formContext = new PSRenderingContext( + userAgent, gen, fontInfo, true); + + ImageFlavor[] flavors; + ImageHandlerRegistry imageHandlerRegistry + = userAgent.getFactory().getImageHandlerRegistry(); + flavors = imageHandlerRegistry.getSupportedFlavors(formContext); + + Map hints = ImageUtil.getDefaultHints(sessionContext); + org.apache.xmlgraphics.image.loader.Image img = manager.getImage( + info, flavors, hints, sessionContext); + + ImageHandler basicHandler = imageHandlerRegistry.getHandler(formContext, img); + if (basicHandler == null) { + throw new UnsupportedOperationException( + "No ImageHandler available for image: " + + img.getInfo() + " (" + img.getClass().getName() + ")"); + } - }; - formGen.generate(gen); - } else if (img instanceof ImageRendered) { - ImageRendered imgRend = (ImageRendered)img; - RenderedImage ri = imgRend.getRenderedImage(); - FormGenerator formGen = new ImageFormGenerator( - form.getName(), imageDescription, - info.getSize().getDimensionPt(), - ri, false); - formGen.generate(gen); - } else if (img instanceof ImageXMLDOM) { - throw new UnsupportedOperationException( - "Embedding an ImageXMLDOM as a form isn't supported, yet"); - } else if (img instanceof ImageRawStream) { - final ImageRawStream raw = (ImageRawStream)img; - if (raw instanceof ImageRawEPS) { - final ImageRawEPS eps = (ImageRawEPS)raw; - throw new UnsupportedOperationException( - "Embedding EPS as forms isn't supported, yet"); - /* - InputStream in = eps.createInputStream(); - try { - FormGenerator formGen = new EPSFormGenerator(form.getName(), - imageDescription, dimensions, in); - formGen.generate(gen); - } finally { - IOUtils.closeQuietly(in); - }*/ - } else if (raw instanceof ImageRawCCITTFax) { - ImageRawCCITTFax jpeg = (ImageRawCCITTFax)raw; - ImageEncoder encoder = new ImageEncoderCCITTFax(jpeg); - FormGenerator formGen = new ImageFormGenerator( - form.getName(), imageDescription, - info.getSize().getDimensionPt(), - info.getSize().getDimensionPx(), - encoder, - jpeg.getColorSpace(), 1, false); - formGen.generate(gen); - } else if (raw instanceof ImageRawJPEG) { - ImageRawJPEG jpeg = (ImageRawJPEG)raw; - ImageEncoder encoder = new ImageEncoderJPEG(jpeg); - FormGenerator formGen = new ImageFormGenerator( - form.getName(), imageDescription, - info.getSize().getDimensionPt(), - info.getSize().getDimensionPx(), - encoder, - jpeg.getColorSpace(), jpeg.isInverted()); - formGen.generate(gen); - } else { - throw new UnsupportedOperationException("Unsupported raw image: " + info); - } - } else { - throw new UnsupportedOperationException("Unsupported image type: " + img); - } - } catch (ImageException ie) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - userAgent.getEventBroadcaster()); - eventProducer.imageError(resTracker, (info != null ? info.toString() : uri), - ie, null); + if (!(basicHandler instanceof PSImageHandler)) { + throw new IllegalStateException( + "ImageHandler implementation doesn't behave properly." + + " It should have returned false in isCompatible(). Class: " + + basicHandler.getClass().getName()); } + PSImageHandler handler = (PSImageHandler)basicHandler; + if (log.isTraceEnabled()) { + log.trace("Using ImageHandler: " + handler.getClass().getName()); + } + handler.generateForm(formContext, img, form); + + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + userAgent.getEventBroadcaster()); + eventProducer.imageError(resTracker, (info != null ? info.toString() : uri), + ie, null); } } @@ -354,4 +352,50 @@ return formGen; } + private class IncludeResourceListener implements DSCListener { + + private PSGenerator gen; + + public IncludeResourceListener(PSGenerator gen) { + this.gen = gen; + } + + /** {...@inheritdoc} */ + public void processEvent(DSCEvent event, DSCParser parser) + throws IOException, DSCException { + if (event.isDSCComment() && event instanceof DSCCommentIncludeResource) { + DSCCommentIncludeResource include = (DSCCommentIncludeResource)event; + PSResource res = include.getResource(); + if (res.getType().equals(PSResource.TYPE_FORM)) { + if (inlineFormResources.containsValue(res)) { + PSImageFormResource form = (PSImageFormResource) + inlineFormResources.get(res); + //Create an inline form + //Wrap in save/restore pair to release memory + gen.writeln("save"); + generateFormForImage(gen, form); + boolean execformFound = false; + DSCEvent next = parser.nextEvent(); + if (next.isLine()) { + PostScriptLine line = next.asLine(); + if (line.getLine().endsWith(" execform")) { + line.generate(gen); + execformFound = true; + } + } + if (!execformFound) { + throw new IOException( + "Expected a PostScript line in the form: <form> execform"); + } + gen.writeln("restore"); + } else { + //Do nothing + } + parser.next(); + } + } + } + + } + }
Added: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java?rev=727405&view=auto ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java (added) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java Wed Dec 17 07:01:21 2008 @@ -0,0 +1,139 @@ +/* + * 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.ps; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.MissingResourceException; + +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; + +import junit.framework.TestCase; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.ps.PSResource; +import org.apache.xmlgraphics.ps.dsc.DSCException; +import org.apache.xmlgraphics.ps.dsc.DSCParser; +import org.apache.xmlgraphics.ps.dsc.events.AbstractResourceDSCComment; +import org.apache.xmlgraphics.ps.dsc.events.DSCComment; +import org.apache.xmlgraphics.ps.dsc.events.DSCEvent; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; + +/** + * Abstract base class for PostScript verification tests. + */ +public abstract class AbstractPostScriptTestCase extends TestCase { + + /** the JAXP TransformerFactory */ + protected TransformerFactory tFactory = TransformerFactory.newInstance(); + /** the FopFactory */ + protected FopFactory fopFactory = FopFactory.newInstance(); + + /** + * Renders a test file. + * @param ua the user agent (with override set!) + * @param resourceName the resource name for the FO file + * @param suffix a suffix for the output filename + * @return the output file + * @throws Exception if an error occurs + */ + protected File renderFile(FOUserAgent ua, String resourceName, String suffix) + throws Exception { + File outputFile = new File("build/test-results/" + resourceName + suffix + ".ps"); + File outputDir = outputFile.getParentFile(); + FileUtils.forceMkdir(outputDir); + + // Prepare input file + InputStream in = getClass().getResourceAsStream(resourceName); + if (in == null) { + throw new MissingResourceException(resourceName + " not found in resources", + getClass().getName(), null); + } + try { + Source src = new StreamSource(in); + + // Create PostScript + OutputStream out = new java.io.FileOutputStream(outputFile); + out = new java.io.BufferedOutputStream(out); + try { + Fop fop = fopFactory.newFop(MimeConstants.MIME_POSTSCRIPT, ua, out); + SAXResult res = new SAXResult(fop.getDefaultHandler()); + + Transformer transformer = tFactory.newTransformer(); + transformer.transform(src, res); + } finally { + IOUtils.closeQuietly(out); + } + } finally { + IOUtils.closeQuietly(in); + } + return outputFile; + } + + /** + * Scans for a certain resource DSC comment and checks against a given resource. + * @param parser the DSC parser + * @param comment the comment to scan for + * @param resource the resource to check against + * @throws IOException if an I/O error occurs + * @throws DSCException if a DSC error occurs + */ + protected void checkResourceComment(DSCParser parser, String comment, PSResource resource) + throws IOException, DSCException { + AbstractResourceDSCComment resComment; + resComment = (AbstractResourceDSCComment)gotoDSCComment(parser, comment); + assertEquals(resource, resComment.getResource()); + } + + /** + * Advances the DSC parser to a DSC comment with the given name. + * @param parser the DSC parser + * @param name the name of the DSC comment + * @return the DSC comment + * @throws IOException if an I/O error occurs + * @throws DSCException if a DSC error occurs + */ + protected static DSCComment gotoDSCComment(DSCParser parser, String name) + throws IOException, DSCException { + while (parser.hasNext()) { + DSCEvent event = parser.nextEvent(); + if (event.isDSCComment()) { + DSCComment comment = event.asDSCComment(); + if (comment.getName().equals(name)) { + return comment; + } + } + } + return null; + } + +} Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java ------------------------------------------------------------------------------ svn:keywords = Id Added: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java?rev=727405&view=auto ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java (added) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java Wed Dec 17 07:01:21 2008 @@ -0,0 +1,188 @@ +/* + * 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.ps; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.ps.DSCConstants; +import org.apache.xmlgraphics.ps.PSResource; +import org.apache.xmlgraphics.ps.dsc.DSCException; +import org.apache.xmlgraphics.ps.dsc.DSCParser; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentTitle; +import org.apache.xmlgraphics.ps.dsc.events.DSCEvent; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Tests the image handling in PostScript output. + */ +public class ImageHandlingTestCase extends AbstractPostScriptTestCase { + + /** + * Tests JPEG handling with the {...@link PSRenderer}. + * @throws Exception if an error occurs + */ + public void testJPEGImageWithRendererLevel3() throws Exception { + innerTestJPEGImageWithRenderer(3); + } + + /** + * Tests JPEG handling with the {...@link PSRenderer}. + * @throws Exception if an error occurs + */ + public void testJPEGImageWithRendererLevel2() throws Exception { + innerTestJPEGImageWithRenderer(2); + } + + /** + * Tests JPEG handling with the {...@link PSDocumentHandler}. + * @throws Exception if an error occurs + */ + public void testJPEGImageWithIFLevel3() throws Exception { + innerTestJPEGImageWithIF(3); + } + + /** + * Tests JPEG handling with the {...@link PSDocumentHandler}. + * @throws Exception if an error occurs + */ + public void testJPEGImageWithIFLevel2() throws Exception { + innerTestJPEGImageWithIF(2); + } + + private void innerTestJPEGImageWithRenderer(int level) throws Exception { + FOUserAgent ua = fopFactory.newFOUserAgent(); + PSRenderer renderer = new PSRenderer(); + renderer.setUserAgent(ua); + PSRenderingUtil psUtil = renderer.getPSUtil(); + psUtil.setLanguageLevel(level); + psUtil.setOptimizeResources(true); + ua.setRendererOverride(renderer); + + // Prepare output file + File outputFile = renderFile(ua, "ps-jpeg-image.fo", "-rend-l" + psUtil.getLanguageLevel()); + verifyPostScriptFile(outputFile, psUtil.getLanguageLevel()); + } + + private void innerTestJPEGImageWithIF(int level) throws Exception { + FOUserAgent ua = fopFactory.newFOUserAgent(); + PSDocumentHandler handler = new PSDocumentHandler(); + handler.setUserAgent(ua); + PSRenderingUtil psUtil = handler.getPSUtil(); + psUtil.setLanguageLevel(level); + psUtil.setOptimizeResources(true); + ua.setDocumentHandlerOverride(handler); + + // Prepare output file + File outputFile = renderFile(ua, "ps-jpeg-image.fo", "-if-l" + psUtil.getLanguageLevel()); + verifyPostScriptFile(outputFile, psUtil.getLanguageLevel()); + } + + private void verifyPostScriptFile(File psFile, int level) + throws IOException, DSCException { + InputStream in = new java.io.FileInputStream(psFile); + in = new java.io.BufferedInputStream(in); + try { + DSCParser parser = new DSCParser(in); + + DSCCommentPages pages = (DSCCommentPages)gotoDSCComment(parser, DSCConstants.PAGES); + assertEquals(1, pages.getPageCount()); + + //Skip procsets and encoding + gotoDSCComment(parser, DSCConstants.BEGIN_RESOURCE); + gotoDSCComment(parser, DSCConstants.BEGIN_RESOURCE); + gotoDSCComment(parser, DSCConstants.BEGIN_RESOURCE); + + PSResource form2 = new PSResource(PSResource.TYPE_FORM, "FOPForm:2"); + checkResourceComment(parser, DSCConstants.BEGIN_RESOURCE, form2); + DSCCommentTitle title = (DSCCommentTitle)parser.nextEvent().asDSCComment(); + assertEquals("image/jpeg test/resources/images/bgimg300dpi.jpg", title.getTitle()); + + String resourceContent = getResourceContent(parser); + + if (level == 3) { + assertContains(resourceContent, "/FOPForm:2"); + assertContains(resourceContent, "/DCTDecode filter"); + assertContains(resourceContent, "/ReusableStreamDecode filter"); + } else { + assertContains(resourceContent, "/FOPForm:2"); + assertContains(resourceContent, "/DCTDecode filter"); + assertAbsent(resourceContent, "/ReusableStreamDecode filter"); + } + + //---=== Page 1 ===--- + DSCCommentPage page = (DSCCommentPage)gotoDSCComment(parser, DSCConstants.PAGE); + assertEquals(1, page.getPagePosition()); + + PSResource form1 = new PSResource(PSResource.TYPE_FORM, "FOPForm:1"); + checkResourceComment(parser, DSCConstants.BEGIN_RESOURCE, form1); + title = (DSCCommentTitle)parser.nextEvent().asDSCComment(); + assertEquals("image/jpeg test/resources/images/bgimg72dpi.jpg", title.getTitle()); + resourceContent = getResourceContent(parser); + + if (level == 3) { + assertContains(resourceContent, "/FOPForm:1"); + assertContains(resourceContent, "/DCTDecode filter"); + assertContains(resourceContent, "/ReusableStreamDecode filter"); + } else { + assertContains(resourceContent, "/FOPForm:1"); + assertContains(resourceContent, "/DCTDecode filter"); + assertAbsent(resourceContent, "/ReusableStreamDecode filter"); + } + + } finally { + IOUtils.closeQuietly(in); + } + } + + private void assertMatches(String text, String regex) { + assertTrue("Text didn't match '" + regex + "'", text.matches(regex)); + } + + private void assertContains(String text, String searchString) { + assertTrue("Text doesn't contain '" + searchString + "'", text.indexOf(searchString) >= 0); + } + + private void assertAbsent(String text, String searchString) { + assertTrue("Text contains '" + searchString + "'", text.indexOf(searchString) < 0); + } + + private String getResourceContent(DSCParser parser) throws IOException, DSCException { + StringBuffer sb = new StringBuffer(); + while (parser.hasNext()) { + DSCEvent event = parser.nextEvent(); + if (event.isLine()) { + sb.append(event.asLine().getLine()).append('\n'); + } else if (event.isDSCComment()) { + if (DSCConstants.END_RESOURCE.equals(event.asDSCComment().getName())) { + break; + } + } + } + return sb.toString(); + } + +} Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java ------------------------------------------------------------------------------ svn:keywords = Id Added: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java?rev=727405&view=auto ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java (added) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java Wed Dec 17 07:01:21 2008 @@ -0,0 +1,222 @@ +/* + * 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.ps; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.ps.DSCConstants; +import org.apache.xmlgraphics.ps.PSResource; +import org.apache.xmlgraphics.ps.dsc.DSCException; +import org.apache.xmlgraphics.ps.dsc.DSCListener; +import org.apache.xmlgraphics.ps.dsc.DSCParser; +import org.apache.xmlgraphics.ps.dsc.DefaultNestedDocumentHandler; +import org.apache.xmlgraphics.ps.dsc.events.AbstractResourcesDSCComment; +import org.apache.xmlgraphics.ps.dsc.events.DSCAtend; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBeginDocument; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentNeededResources; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentSuppliedResources; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentEndOfFile; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentIncludeResource; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Tests the PostScript resource optimization (selective de-duplication of + * images that are used multiple times). + */ +public class ResourceOptimizationTestCase extends AbstractPostScriptTestCase { + + /** + * Tests resource optimization with the {...@link PSRenderer}. + * @throws Exception if an error occurs + */ + public void testResourceOptimizationWithRenderer() throws Exception { + FOUserAgent ua = fopFactory.newFOUserAgent(); + PSRenderer renderer = new PSRenderer(); + renderer.setUserAgent(ua); + // This is the important part: we're enabling resource optimization + renderer.getPSUtil().setOptimizeResources(true); + ua.setRendererOverride(renderer); + + // Prepare output file + File outputFile = renderFile(ua, "ps-resources.fo", + "-rend-l" + renderer.getPSUtil().getLanguageLevel()); + verifyPostScriptFile(outputFile); + } + + /** + * Tests resource optimization with the {...@link PSDocumentHandler}. + * @throws Exception if an error occurs + */ + public void testResourceOptimizationWithIF() throws Exception { + FOUserAgent ua = fopFactory.newFOUserAgent(); + PSDocumentHandler handler = new PSDocumentHandler(); + handler.setUserAgent(ua); + // This is the important part: we're enabling resource optimization + handler.getPSUtil().setOptimizeResources(true); + ua.setDocumentHandlerOverride(handler); + + // Prepare output file + File outputFile = renderFile(ua, "ps-resources.fo", + "-if-l" + handler.getPSUtil().getLanguageLevel()); + verifyPostScriptFile(outputFile); + } + + private void verifyPostScriptFile(File psFile) throws IOException, DSCException { + InputStream in = new java.io.FileInputStream(psFile); + in = new java.io.BufferedInputStream(in); + try { + DSCParser parser = new DSCParser(in); + + //The first form is for arrow_down_small.png (to be reused) + PSResource form1 = new PSResource(PSResource.TYPE_FORM, "FOPForm:1"); + PSResource helvetica = new PSResource(PSResource.TYPE_FONT, "Helvetica"); + PSResource helveticaBold = new PSResource(PSResource.TYPE_FONT, "Helvetica-Bold"); + + PSResource res; + DSCCommentPages pages = (DSCCommentPages)gotoDSCComment(parser, DSCConstants.PAGES); + assertEquals(2, pages.getPageCount()); + + DSCCommentDocumentSuppliedResources supplied + = (DSCCommentDocumentSuppliedResources)gotoDSCComment(parser, + DSCConstants.DOCUMENT_SUPPLIED_RESOURCES); + Set resources = supplied.getResources(); + assertEquals(4, resources.size()); + assertTrue(resources.contains(form1)); + assertTrue("Expected barcode.eps as supplied resource", + resources.contains(new PSResource(PSResource.TYPE_FILE, + "test/resources/images/barcode.eps"))); + + DSCCommentDocumentNeededResources needed + = (DSCCommentDocumentNeededResources)gotoDSCComment(parser, + DSCConstants.DOCUMENT_NEEDED_RESOURCES); + resources = needed.getResources(); + assertEquals(2, resources.size()); + assertTrue("Expected Helvetica as needed resource", + resources.contains(new PSResource(PSResource.TYPE_FONT, "Helvetica"))); + assertTrue("Expected Helvetica-Bold as needed resource", + resources.contains(new PSResource(PSResource.TYPE_FONT, "Helvetica-Bold"))); + + //Some document structure checking + assertNotNull(gotoDSCComment(parser, DSCConstants.BEGIN_DEFAULTS)); + assertNotNull(gotoDSCComment(parser, DSCConstants.END_DEFAULTS)); + assertNotNull(gotoDSCComment(parser, DSCConstants.BEGIN_PROLOG)); + assertNotNull(gotoDSCComment(parser, DSCConstants.END_PROLOG)); + assertNotNull(gotoDSCComment(parser, DSCConstants.BEGIN_SETUP)); + + //Check includes for the two referenced base 14 fonts + DSCCommentIncludeResource include; + Collection strings = new java.util.HashSet( + Arrays.asList(new String[] {"Helvetica", "Helvetica-Bold"})); + for (int i = 0; i < 2; i++) { + include = (DSCCommentIncludeResource)gotoDSCComment( + parser, DSCConstants.INCLUDE_RESOURCE); + res = include.getResource(); + assertEquals(PSResource.TYPE_FONT, res.getType()); + strings.remove(res.getName()); + } + assertEquals(0, strings.size()); + + checkResourceComment(parser, DSCConstants.BEGIN_RESOURCE, + new PSResource(PSResource.TYPE_ENCODING, "WinAnsiEncoding")); + + //Here, we encounter form 1 again + checkResourceComment(parser, DSCConstants.BEGIN_RESOURCE, form1); + + assertNotNull(gotoDSCComment(parser, DSCConstants.END_SETUP)); + //Now the actual pages begin + + //---=== Page 1 ===--- + DSCCommentPage page = (DSCCommentPage)gotoDSCComment(parser, DSCConstants.PAGE); + assertEquals(1, page.getPagePosition()); + + assertEquals(DSCAtend.class, + gotoDSCComment(parser, DSCConstants.PAGE_RESOURCES).getClass()); + assertNotNull(gotoDSCComment(parser, DSCConstants.BEGIN_PAGE_SETUP)); + assertNotNull(gotoDSCComment(parser, DSCConstants.END_PAGE_SETUP)); + + PSResource form2 = new PSResource(PSResource.TYPE_FORM, "FOPForm:2"); + checkResourceComment(parser, DSCConstants.BEGIN_RESOURCE, form2); + assertNotNull(gotoDSCComment(parser, DSCConstants.PAGE_TRAILER)); + + AbstractResourcesDSCComment pageResources; + pageResources = (AbstractResourcesDSCComment)gotoDSCComment( + parser, DSCConstants.PAGE_RESOURCES); + resources = pageResources.getResources(); + assertEquals(5, resources.size()); + assertTrue(resources.contains(form1)); + assertTrue(resources.contains(form2)); + assertTrue(resources.contains(helvetica)); + assertTrue(resources.contains(helveticaBold)); + + //---=== Page 2 ===--- + page = (DSCCommentPage)gotoDSCComment(parser, DSCConstants.PAGE); + assertEquals(2, page.getPagePosition()); + + assertEquals(DSCAtend.class, + gotoDSCComment(parser, DSCConstants.PAGE_RESOURCES).getClass()); + assertNotNull(gotoDSCComment(parser, DSCConstants.BEGIN_PAGE_SETUP)); + assertNotNull(gotoDSCComment(parser, DSCConstants.END_PAGE_SETUP)); + + DSCCommentBeginDocument beginDocument; + beginDocument = (DSCCommentBeginDocument)gotoDSCComment( + parser, DSCConstants.BEGIN_DOCUMENT); + assertEquals("test/resources/images/barcode.eps", + beginDocument.getResource().getName()); + DSCListener listener = new DefaultNestedDocumentHandler(null); + listener.processEvent(beginDocument, parser); + + //And again (the barcode is generated twice) + beginDocument = (DSCCommentBeginDocument)gotoDSCComment( + parser, DSCConstants.BEGIN_DOCUMENT); + assertEquals("test/resources/images/barcode.eps", + beginDocument.getResource().getName()); + listener.processEvent(beginDocument, parser); + + assertNotNull(gotoDSCComment(parser, DSCConstants.PAGE_TRAILER)); + pageResources = (AbstractResourcesDSCComment)gotoDSCComment( + parser, DSCConstants.PAGE_RESOURCES); + resources = pageResources.getResources(); + assertEquals(6, resources.size()); + assertTrue(resources.contains(form1)); + assertFalse(resources.contains(form2)); + assertTrue(resources.contains(helvetica)); + assertTrue(resources.contains(helveticaBold)); + assertTrue(resources.contains(beginDocument.getResource())); + + assertNotNull(gotoDSCComment(parser, DSCConstants.TRAILER)); + //No headers in between, as they should have been put at the beginning of the file + assertEquals(DSCCommentEndOfFile.class, parser.nextEvent().asDSCComment().getClass()); + + } finally { + IOUtils.closeQuietly(in); + } + } + +} Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java ------------------------------------------------------------------------------ svn:keywords = Id Added: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo?rev=727405&view=auto ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo (added) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo Wed Dec 17 07:01:21 2008 @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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$ --> +<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="A4"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>JPEG image:</fo:block> + <fo:block><fo:external-graphic src="test/resources/images/bgimg72dpi.jpg"/></fo:block> + <fo:block> + <fo:external-graphic src="test/resources/images/bgimg300dpi.jpg"/> + <fo:external-graphic src="test/resources/images/bgimg300dpi.jpg"/> + </fo:block> + </fo:flow> + </fo:page-sequence> +</fo:root> Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-jpeg-image.fo ------------------------------------------------------------------------------ svn:keywords = Id Added: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo?rev=727405&view=auto ============================================================================== --- xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo (added) +++ xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo Wed Dec 17 07:01:21 2008 @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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$ --> +<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="A4"> + <fo:flow flow-name="xsl-region-body"> + <fo:block font-weight="bold">PostScript Resource Optimization Test</fo:block> + <fo:block>Used again later:</fo:block> + <fo:block><fo:external-graphic src="test/resources/images/arrow_down_small.png"/></fo:block> + <fo:block>Used only once in the whole document:</fo:block> + <fo:block><fo:external-graphic src="test/resources/images/arrow_up_small.png"/></fo:block> + </fo:flow> + </fo:page-sequence> + <fo:page-sequence master-reference="A4"> + <fo:flow flow-name="xsl-region-body"> + <fo:block font-weight="bold">PostScript Resource Optimization Test</fo:block> + <fo:block>Image already used in previous page-sequence:</fo:block> + <fo:block> + <fo:external-graphic src="test/resources/images/arrow_down_small.png" content-width="80%"/> + <fo:external-graphic src="test/resources/images/arrow_down_small.png"/> + <fo:external-graphic src="test/resources/images/arrow_down_small.png" content-width="120%"/> + </fo:block> + <fo:block>Can't currently reuse EPS images:</fo:block> + <fo:block> + <fo:external-graphic src="test/resources/images/barcode.eps"/> + <fo:external-graphic src="test/resources/images/barcode.eps"/> + </fo:block> + </fo:flow> + </fo:page-sequence> +</fo:root> Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/test/java/org/apache/fop/render/ps/ps-resources.fo ------------------------------------------------------------------------------ svn:keywords = Id --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
