Browse Source

Added getUserAgent() to IFDocumentHandler (implemented by all implementations already).

Full image support for PSPainter.
PostScript output now uses the ImageHandler facility (IF and renderer) for both inline (ImageHandler interface) and form image production (PSImageHandler interface). No more hard-coded image flavor list.
Resource optimization extended so images that are only used once are inlined to lower memory requirements in the PostScript VM.
Added test cases using Commons' DSC parser to verify the new functionality.
Added IFDocumentHandler override possibility in FOUserAgent (just like for FOEventHandler and Renderer).
Subject support for PDF output.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@727405 13f79535-47bb-0310-9956-ffa450edef68
pull/17/head
Jeremias Maerki 15 years ago
parent
commit
903e5c9d80
25 changed files with 1929 additions and 292 deletions
  1. 6
    0
      src/java/META-INF/services/org.apache.fop.render.ImageHandler
  2. 38
    0
      src/java/org/apache/fop/apps/FOUserAgent.java
  3. 22
    22
      src/java/org/apache/fop/render/RendererFactory.java
  4. 1
    4
      src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java
  5. 28
    0
      src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
  6. 8
    1
      src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java
  7. 1
    0
      src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
  8. 23
    2
      src/java/org/apache/fop/render/ps/PSDocumentHandler.java
  9. 48
    0
      src/java/org/apache/fop/render/ps/PSImageHandler.java
  10. 107
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java
  11. 153
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
  12. 115
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java
  13. 115
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java
  14. 101
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
  15. 161
    0
      src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
  16. 88
    2
      src/java/org/apache/fop/render/ps/PSImageUtils.java
  17. 45
    3
      src/java/org/apache/fop/render/ps/PSPainter.java
  18. 28
    138
      src/java/org/apache/fop/render/ps/PSRenderer.java
  19. 44
    1
      src/java/org/apache/fop/render/ps/PSRenderingContext.java
  20. 163
    119
      src/java/org/apache/fop/render/ps/ResourceHandler.java
  21. 139
    0
      test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java
  22. 188
    0
      test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java
  23. 222
    0
      test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java
  24. 35
    0
      test/java/org/apache/fop/render/ps/ps-jpeg-image.fo
  25. 50
    0
      test/java/org/apache/fop/render/ps/ps-resources.fo

+ 6
- 0
src/java/META-INF/services/org.apache.fop.render.ImageHandler View File

@@ -7,3 +7,9 @@ org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage
org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D
org.apache.fop.render.pcl.PCLImageHandlerRenderedImage
org.apache.fop.render.pcl.PCLImageHandlerGraphics2D
org.apache.fop.render.ps.PSImageHandlerRenderedImage
org.apache.fop.render.ps.PSImageHandlerEPS
org.apache.fop.render.ps.PSImageHandlerRawCCITTFax
org.apache.fop.render.ps.PSImageHandlerRawJPEG
org.apache.fop.render.ps.PSImageHandlerGraphics2D
org.apache.fop.render.ps.PSImageHandlerSVG

+ 38
- 0
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -46,6 +46,7 @@ import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.render.intermediate.IFDocumentHandler;

/**
* This is the user agent for FOP.
@@ -92,6 +93,7 @@ public class FOUserAgent {
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private Map rendererOptions = new java.util.HashMap();
private File outputFile = null;
private IFDocumentHandler documentHandlerOverride = null;
private Renderer rendererOverride = null;
private FOEventHandler foEventHandlerOverride = null;
private boolean locatorEnabled = true; // true by default (for error messages).
@@ -116,6 +118,8 @@ public class FOUserAgent {
protected String author = null;
/** Title of the document. */
protected String title = null;
/** Subject of the document. */
protected String subject = null;
/** Set of keywords applicable to this document. */
protected String keywords = null;

@@ -158,6 +162,24 @@ public class FOUserAgent {

// ---------------------------------------------- rendering-run dependent stuff

/**
* Sets an explicit document handler to use which overrides the one that would be
* selected by default.
* @param documentHandler the document handler instance to use
*/
public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) {
this.documentHandlerOverride = documentHandler;

}

/**
* Returns the overriding {@link IFDocumentHandler} instance, if any.
* @return the overriding document handler or null
*/
public IFDocumentHandler getDocumentHandlerOverride() {
return this.documentHandlerOverride;
}

/**
* Sets an explicit renderer to use which overrides the one defined by the
* render type setting.
@@ -273,6 +295,22 @@ public class FOUserAgent {
return title;
}

/**
* Sets the subject of the document.
* @param subject of document
*/
public void setSubject(String subject) {
this.subject = subject;
}

/**
* Returns the subject of the document
* @return the subject
*/
public String getSubject() {
return subject;
}

/**
* Sets the keywords for the document.
* @param keywords for the document

+ 22
- 22
src/java/org/apache/fop/render/RendererFactory.java View File

@@ -231,7 +231,9 @@ public class RendererFactory {
*/
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat)
throws FOPException {
if (userAgent.getRendererOverride() != null) {
if (userAgent.getDocumentHandlerOverride() != null) {
return createRendererForDocumentHandler(userAgent.getDocumentHandlerOverride());
} else if (userAgent.getRendererOverride() != null) {
return userAgent.getRendererOverride();
} else {
AbstractRendererMaker maker = getRendererMaker(outputFormat);
@@ -247,12 +249,9 @@ public class RendererFactory {
AbstractIFDocumentHandlerMaker documentHandlerMaker
= getDocumentHandlerMaker(outputFormat);
if (documentHandlerMaker != null) {
IFRenderer rend = new IFRenderer();
rend.setUserAgent(userAgent);
IFDocumentHandler documentHandler = createDocumentHandler(
userAgent, outputFormat);
rend.setDocumentHandler(documentHandler);
return rend;
return createRendererForDocumentHandler(documentHandler);
} else {
throw new UnsupportedOperationException(
"No renderer for the requested format available: " + outputFormat);
@@ -261,6 +260,13 @@ public class RendererFactory {
}
}

private Renderer createRendererForDocumentHandler(IFDocumentHandler documentHandler) {
IFRenderer rend = new IFRenderer();
rend.setUserAgent(documentHandler.getUserAgent());
rend.setDocumentHandler(documentHandler);
return rend;
}

/**
* Creates FOEventHandler instances based on the desired output.
* @param userAgent the user agent for access to configuration
@@ -319,23 +325,17 @@ public class RendererFactory {
*/
public IFDocumentHandler createDocumentHandler(FOUserAgent userAgent, String outputFormat)
throws FOPException {
/*
if (userAgent.getIFDocumentHandlerOverride() != null) {
return userAgent.getIFDocumentHandlerOverride();
} else {
*/
AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat);
if (maker == null) {
throw new UnsupportedOperationException(
"No IF document handler for the requested format available: " + outputFormat);
}
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent);
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator();
if (configurator != null) {
configurator.configure(documentHandler);
}
return documentHandler;
//}
AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat);
if (maker == null) {
throw new UnsupportedOperationException(
"No IF document handler for the requested format available: " + outputFormat);
}
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent);
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator();
if (configurator != null) {
configurator.configure(documentHandler);
}
return documentHandler;
}

/**

+ 1
- 4
src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java View File

@@ -48,10 +48,7 @@ public abstract class AbstractIFDocumentHandler implements IFDocumentHandler {
this.userAgent = ua;
}

/**
* Returns the user agent.
* @return the user agent
*/
/** {@inheritDoc} */
public FOUserAgent getUserAgent() {
return this.userAgent;
}

+ 28
- 0
src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java View File

@@ -208,6 +208,34 @@ public abstract class AbstractIFPainter implements IFPainter {
handler.handleImage(context, effImage, rect);
}

/**
* Returns an ImageInfo instance for the given URI. If there's an error, null is returned.
* The caller can assume that any exceptions have already been handled properly. The caller
* simply skips painting anything in this case.
* @param uri the URI identifying the image
* @return the ImageInfo instance or null if there has been an error.
*/
protected ImageInfo getImageInfo(String uri) {
ImageManager manager = getFopFactory().getImageManager();
try {
ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
return manager.getImageInfo(uri, sessionContext);
} catch (ImageException ie) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageError(this, uri, ie, null);
} catch (FileNotFoundException fe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageNotFound(this, uri, fe, null);
} catch (IOException ioe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageIOError(this, uri, ioe, null);
}
return null;
}

/**
* Default drawing method for handling an image referenced by a URI.
* @param uri the image's URI

+ 8
- 1
src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java View File

@@ -81,6 +81,12 @@ public interface IFDocumentHandler {
*/
void setUserAgent(FOUserAgent userAgent);

/**
* Returns the associated user agent.
* @return the user agent
*/
FOUserAgent getUserAgent();

/**
* Sets the JAXP Result object to receive the generated content.
* @param result the JAXP Result object to receive the generated content
@@ -199,7 +205,8 @@ public interface IFDocumentHandler {
* @param size the size of the page (equivalent to the MediaBox in PDF)
* @throws IFException if an error occurs while handling this event
*/
void startPage(int index, String name, String pageMasterName, Dimension size) throws IFException;
void startPage(int index, String name, String pageMasterName, Dimension size)
throws IFException;

/**
* Indicates the end of a page

+ 1
- 0
src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java View File

@@ -234,6 +234,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants {
info.setCreationDate(userAgent.getCreationDate());
info.setAuthor(userAgent.getAuthor());
info.setTitle(userAgent.getTitle());
info.setSubject(userAgent.getSubject());
info.setKeywords(userAgent.getKeywords());
}


+ 23
- 2
src/java/org/apache/fop/render/ps/PSDocumentHandler.java View File

@@ -268,8 +268,9 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
in = new java.io.BufferedInputStream(in);
try {
try {
ResourceHandler.process(getUserAgent(), in, this.outputStream,
this.fontInfo, resTracker, this.formResources,
ResourceHandler handler = new ResourceHandler(getUserAgent(), this.fontInfo,
resTracker, this.formResources);
handler.process(in, this.outputStream,
this.currentPageNumber, this.documentBoundingBox);
this.outputStream.flush();
} catch (DSCException e) {
@@ -519,4 +520,24 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
return res;
}

/**
* Returns a PSResource instance representing a image as a PostScript form.
* @param uri the image URI
* @return a PSResource instance
*/
protected PSResource getFormForImage(String uri) {
if (uri == null || "".equals(uri)) {
throw new IllegalArgumentException("uri must not be empty or null");
}
if (this.formResources == null) {
this.formResources = new java.util.HashMap();
}
PSResource form = (PSResource)this.formResources.get(uri);
if (form == null) {
form = new PSImageFormResource(this.formResources.size() + 1, uri);
this.formResources.put(uri, form);
}
return form;
}

}

+ 48
- 0
src/java/org/apache/fop/render/ps/PSImageHandler.java View File

@@ -0,0 +1,48 @@
/*
* 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.IOException;

import org.apache.xmlgraphics.image.loader.Image;

import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;

/**
* Specialized image handler interface for PostScript output. Implementations can optionally
* support creating PostScript forms. The implementation shall check the rendering context
* to see if forms functionality is enabled in the
* {@link #isCompatible(org.apache.fop.render.RenderingContext, org.apache.xmlgraphics.image.loader.Image)}
* method.
*/
public interface PSImageHandler extends ImageHandler {

/**
* Generates a PostScript form for the given {@link Image} instance.
* @param context the rendering context
* @param image the image to be handled
* @param form the associated form resource
* @throws IOException if an I/O error occurs
*/
void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException;

}

+ 107
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java View File

@@ -0,0 +1,107 @@
/*
* 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.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.IOUtils;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSImageUtils;

import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;

/**
* Image handler implementation which handles EPS images for PostScript output.
*/
public class PSImageHandlerEPS implements ImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.RAW_EPS
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawEPS eps = (ImageRawEPS)image;

float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;

ImageInfo info = image.getInfo();
Rectangle2D bbox = eps.getBoundingBox();
if (bbox == null) {
bbox = new Rectangle2D.Double();
bbox.setFrame(new Point2D.Double(), info.getSize().getDimensionPt());
}
InputStream in = eps.createInputStream();
try {
String resourceName = info.getOriginalURI();
if (resourceName == null) {
resourceName = "inline image";
}
PSImageUtils.renderEPS(in, resourceName,
new Rectangle2D.Float(x, y, w, h),
bbox,
gen);
} finally {
IOUtils.closeQuietly(in);
}
}

/** {@inheritDoc} */
public int getPriority() {
return 200;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageRawEPS.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof PSRenderingContext) {
PSRenderingContext psContext = (PSRenderingContext)targetContext;
return !psContext.isCreateForms()
&& (image == null || image instanceof ImageRawEPS);
}
return false;
}

}

+ 153
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java View File

@@ -0,0 +1,153 @@
/*
* 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.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.FormGenerator;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSProcSets;

import org.apache.fop.render.RenderingContext;

/**
* Image handler implementation which handles vector graphics (Java2D) for PostScript output.
*/
public class PSImageHandlerGraphics2D implements PSImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.GRAPHICS2D
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
Graphics2DImagePainter painter = imageG2D.getGraphics2DImagePainter();

float fx = (float)pos.getX() / 1000f;
float fy = (float)pos.getY() / 1000f;
float fwidth = (float)pos.getWidth() / 1000f;
float fheight = (float)pos.getHeight() / 1000f;

// get the 'width' and 'height' attributes of the SVG document
Dimension dim = painter.getImageSize();
float imw = (float)dim.getWidth() / 1000f;
float imh = (float)dim.getHeight() / 1000f;

float sx = fwidth / (float)imw;
float sy = fheight / (float)imh;

gen.commentln("%FOPBeginGraphics2D");
gen.saveGraphicsState();
final boolean clip = false;
if (clip) {
// Clip to the image area.
gen.writeln("newpath");
gen.defineRect(fx, fy, fwidth, fheight);
gen.writeln("clip");
}

// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
gen.concatMatrix(sx, 0, 0, sy, fx, fy);

final boolean textAsShapes = false;
PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
AffineTransform transform = new AffineTransform();
// scale to viewbox
transform.translate(fx, fy);
gen.getCurrentState().concatMatrix(transform);
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(graphics, area);
gen.restoreGraphicsState();
gen.commentln("%FOPEndGraphics2D");
}

/** {@inheritDoc} */
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
final ImageGraphics2D imageG2D = (ImageGraphics2D)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
final Dimension2D dimensionsPt = info.getSize().getDimensionPt();
final Dimension2D dimensionsMpt = info.getSize().getDimensionMpt();

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");
}

};
formGen.generate(gen);
}
/** {@inheritDoc} */
public int getPriority() {
return 200;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageGraphics2D.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof PSRenderingContext) {
return (image == null || image instanceof ImageGraphics2D);
}
return false;
}

}

+ 115
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java View File

@@ -0,0 +1,115 @@
/*
* 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.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
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.PSImageUtils;

import org.apache.fop.render.RenderingContext;

/**
* Image handler implementation which handles CCITT fax images for PostScript output.
*/
public class PSImageHandlerRawCCITTFax implements PSImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.RAW_CCITTFAX
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;

float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
Rectangle2D targetRect = new Rectangle2D.Float(
x, y, w, h);

ImageInfo info = image.getInfo();

ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
info.getOriginalURI(), targetRect,
ccitt.getColorSpace(), 1, false, gen);
}

/** {@inheritDoc} */
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();

ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
FormGenerator formGen = new ImageFormGenerator(
form.getName(), imageDescription,
info.getSize().getDimensionPt(),
info.getSize().getDimensionPx(),
encoder,
ccitt.getColorSpace(), 1, false);
formGen.generate(gen);
}

/** {@inheritDoc} */
public int getPriority() {
return 200;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageRawCCITTFax.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof PSRenderingContext) {
PSRenderingContext psContext = (PSRenderingContext)targetContext;
//The filters required for this implementation need PS level 2 or higher
if (psContext.getGenerator().getPSLevel() >= 2) {
return (image == null || image instanceof ImageRawCCITTFax);
}
}
return false;
}

}

+ 115
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java View File

@@ -0,0 +1,115 @@
/*
* 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.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
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.PSImageUtils;

import org.apache.fop.render.RenderingContext;

/**
* Image handler implementation which handles undecoded JPEG images for PostScript output.
*/
public class PSImageHandlerRawJPEG implements PSImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.RAW_JPEG
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawJPEG jpeg = (ImageRawJPEG)image;

float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
Rectangle2D targetRect = new Rectangle2D.Float(
x, y, w, h);

ImageInfo info = image.getInfo();

ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
info.getOriginalURI(), targetRect,
jpeg.getColorSpace(), 8, jpeg.isInverted(), gen);
}

/** {@inheritDoc} */
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawJPEG jpeg = (ImageRawJPEG)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();

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);
}

/** {@inheritDoc} */
public int getPriority() {
return 200;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageRawJPEG.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof PSRenderingContext) {
PSRenderingContext psContext = (PSRenderingContext)targetContext;
//The filters required for this implementation need PS level 2 or higher
if (psContext.getGenerator().getPSLevel() >= 2) {
return (image == null || image instanceof ImageRawJPEG);
}
}
return false;
}

}

+ 101
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java View File

@@ -0,0 +1,101 @@
/*
* 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.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.io.IOException;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
import org.apache.xmlgraphics.ps.FormGenerator;
import org.apache.xmlgraphics.ps.ImageFormGenerator;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSImageUtils;

import org.apache.fop.render.RenderingContext;

/**
* Image handler implementation which handles RenderedImage instances for PostScript output.
*/
public class PSImageHandlerRenderedImage implements PSImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.BUFFERED_IMAGE,
ImageFlavor.RENDERED_IMAGE
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRendered imageRend = (ImageRendered)image;

float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;

RenderedImage ri = imageRend.getRenderedImage();
PSImageUtils.renderBitmapImage(ri, x, y, w, h, gen);
}

/** {@inheritDoc} */
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRendered imageRend = (ImageRendered)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();

RenderedImage ri = imageRend.getRenderedImage();
FormGenerator formGen = new ImageFormGenerator(
form.getName(), imageDescription,
info.getSize().getDimensionPt(),
ri, false);
formGen.generate(gen);
}

/** {@inheritDoc} */
public int getPriority() {
return 300;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageRendered.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
return (image == null || image instanceof ImageRendered)
&& targetContext instanceof PSRenderingContext;
}

}

+ 161
- 0
src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java View File

@@ -0,0 +1,161 @@
/*
* 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.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.gvt.GraphicsNode;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;

import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.svg.SVGEventProducer;
import org.apache.fop.svg.SVGUserAgent;

/**
* Image handler implementation which handles SVG images for PostScript output.
*/
public class PSImageHandlerSVG implements ImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
BatikImageFlavors.SVG_DOM
};

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageXMLDOM imageSVG = (ImageXMLDOM)image;

//Controls whether text painted by Batik is generated using text or path operations
boolean strokeText = false;
//TODO Configure text stroking

SVGUserAgent ua
= new SVGUserAgent(context.getUserAgent(), new AffineTransform());

PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

GVTBuilder builder = new GVTBuilder();
NativeTextHandler nativeTextHandler = null;
BridgeContext ctx = new BridgeContext(ua);
if (!strokeText) {
nativeTextHandler = new NativeTextHandler(graphics, psContext.getFontInfo());
graphics.setCustomTextHandler(nativeTextHandler);
PSTextPainter textPainter = new PSTextPainter(nativeTextHandler);
ctx.setTextPainter(textPainter);
PSTextElementBridge tBridge = new PSTextElementBridge(textPainter);
ctx.putBridge(tBridge);
}

GraphicsNode root;
try {
root = builder.build(ctx, imageSVG.getDocument());
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
return;
}
// get the 'width' and 'height' attributes of the SVG document
float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
float h = (float)ctx.getDocumentSize().getHeight() * 1000f;

float sx = pos.width / w;
float sy = pos.height / h;

ctx = null;
builder = null;

gen.commentln("%FOPBeginSVG");
gen.saveGraphicsState();
final boolean clip = false;
if (clip) {
/*
* Clip to the svg area.
* Note: To have the svg overlay (under) a text area then use
* an fo:block-container
*/
gen.writeln("newpath");
gen.defineRect(pos.getMinX() / 1000f, pos.getMinY() / 1000f,
pos.width / 1000f, pos.height / 1000f);
gen.writeln("clip");
}

// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
gen.concatMatrix(sx, 0, 0, sy, pos.getMinX() / 1000f, pos.getMinY() / 1000f);

AffineTransform transform = new AffineTransform();
// scale to viewbox
transform.translate(pos.getMinX(), pos.getMinY());
gen.getCurrentState().concatMatrix(transform);
try {
root.paint(graphics);
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
}

gen.restoreGraphicsState();
gen.commentln("%FOPEndSVG");
}

/** {@inheritDoc} */
public int getPriority() {
return 400;
}

/** {@inheritDoc} */
public Class getSupportedImageClass() {
return ImageXMLDOM.class;
}

/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof PSRenderingContext) {
PSRenderingContext psContext = (PSRenderingContext)targetContext;
return !psContext.isCreateForms()
&& (image == null || (image instanceof ImageXMLDOM
&& image.getFlavor().isCompatible(BatikImageFlavors.SVG_DOM)));
}
return false;
}

}

+ 88
- 2
src/java/org/apache/fop/render/ps/PSImageUtils.java View File

@@ -19,11 +19,97 @@

package org.apache.fop.render.ps;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

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.pipeline.ImageProviderPipeline;
import org.apache.xmlgraphics.ps.DSCConstants;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSResource;

import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RenderingContext;

/**
* Utility code for rendering images in PostScript.
* @deprecated Kept for compatibility with older FOP extensions (like Barcode4J). Use the
* super-class instead.
*/
public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {

/**
* Indicates whether the given image (identified by an {@link ImageInfo} object) shall be
* inlined rather than generated as a PostScript form.
* @param info the info object for the image
* @param renderingContext the rendering context
* @return true if the image shall be inlined, false if forms shall be used.
*/
public static boolean isImageInlined(ImageInfo info, PSRenderingContext renderingContext) {
String uri = info.getOriginalURI();
if (uri == null || "".equals(uri)) {
return true;
}
//Investigate choice for inline mode
ImageFlavor[] inlineFlavors = determineSupportedImageFlavors(renderingContext);
ImageManager manager = renderingContext.getUserAgent().getFactory().getImageManager();
ImageProviderPipeline[] inlineCandidates
= manager.getPipelineFactory().determineCandidatePipelines(
info, inlineFlavors);
ImageProviderPipeline inlineChoice = manager.choosePipeline(inlineCandidates);
ImageFlavor inlineFlavor = (inlineChoice != null
? inlineChoice.getTargetFlavor() : null);

//Create a rendering context for form creation
PSRenderingContext formContext = renderingContext.toFormContext();

//Investigate choice for form mode
ImageFlavor[] formFlavors = determineSupportedImageFlavors(formContext);
ImageProviderPipeline[] formCandidates
= manager.getPipelineFactory().determineCandidatePipelines(
info, formFlavors);
ImageProviderPipeline formChoice = manager.choosePipeline(formCandidates);
ImageFlavor formFlavor = (formChoice != null ? formChoice.getTargetFlavor() : null);

//Inline if form is not supported or if a better choice is available with inline mode
return formFlavor == null || !formFlavor.equals(inlineFlavor);
}

private static ImageFlavor[] determineSupportedImageFlavors(RenderingContext renderingContext) {
ImageFlavor[] inlineFlavors;
ImageHandlerRegistry imageHandlerRegistry
= renderingContext.getUserAgent().getFactory().getImageHandlerRegistry();
inlineFlavors = imageHandlerRegistry.getSupportedFlavors(renderingContext);
return inlineFlavors;
}

/**
* Draws a form at a given location.
* @param form the form resource
* @param info the image info object representing the image in the form
* @param rect the target rectangle (coordinates in millipoints)
* @param generator the PostScript generator
* @throws IOException if an I/O error occurs
*/
public static void drawForm(PSResource form, ImageInfo info, Rectangle rect,
PSGenerator generator) throws IOException {
Rectangle2D targetRect = new Rectangle2D.Double(
rect.getMinX() / 1000.0,
rect.getMinY() / 1000.0,
rect.getWidth() / 1000.0,
rect.getHeight() / 1000.0);
generator.saveGraphicsState();
translateAndScale(generator,
info.getSize().getDimensionPt(), targetRect);

//The following %%IncludeResource marker is needed later by ResourceHandler!
generator.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, form);
generator.getResourceTracker().notifyResourceUsageOnPage(form);

generator.writeln(form.getName() + " execform");
generator.restoreGraphicsState();
}


}

+ 45
- 3
src/java/org/apache/fop/render/ps/PSPainter.java View File

@@ -33,6 +33,10 @@ import org.w3c.dom.Document;
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.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageProcessingHints;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSResource;

@@ -135,19 +139,57 @@ public class PSPainter extends AbstractIFPainter {
}

/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException {
//TODO Implement me
protected Map createDefaultImageProcessingHints(ImageSessionContext sessionContext) {
Map hints = super.createDefaultImageProcessingHints(sessionContext);

//PostScript doesn't support alpha channels
hints.put(ImageProcessingHints.TRANSPARENCY_INTENT,
ImageProcessingHints.TRANSPARENCY_INTENT_IGNORE);
//TODO We might want to support image masks in the future.
return hints;
}

/** {@inheritDoc} */
protected RenderingContext createRenderingContext() {
PSRenderingContext psContext = new PSRenderingContext(
getUserAgent(), getFontInfo());
getUserAgent(), getGenerator(), getFontInfo());
return psContext;
}

/** {@inheritDoc} */
protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect)
throws ImageException, IOException {
if (!getPSUtil().isOptimizeResources()
|| PSImageUtils.isImageInlined(info,
(PSRenderingContext)createRenderingContext())) {
super.drawImageUsingImageHandler(info, rect);
} else {
if (log.isDebugEnabled()) {
log.debug("Image " + info + " is embedded as a form later");
}
//Don't load image at this time, just put a form placeholder in the stream
PSResource form = documentHandler.getFormForImage(info.getOriginalURI());
PSImageUtils.drawForm(form, info, rect, getGenerator());
}
}

/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException {
try {
endTextObject();
} catch (IOException ioe) {
throw new IFException("I/O error in drawImage()", ioe);
}
drawImageUsingURI(uri, rect);
}

/** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException {
try {
endTextObject();
} catch (IOException ioe) {
throw new IFException("I/O error in drawImage()", ioe);
}
drawImageUsingDocument(doc, rect);
}


+ 28
- 138
src/java/org/apache/fop/render/ps/PSRenderer.java View File

@@ -21,6 +21,7 @@ package org.apache.fop.render.ps;

// Java
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
@@ -36,6 +37,7 @@ import java.util.Map;

import javax.xml.transform.Source;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -45,21 +47,11 @@ 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.pipeline.ImageProviderPipeline;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.ps.DSCConstants;
import org.apache.xmlgraphics.ps.ImageEncoder;
import org.apache.xmlgraphics.ps.PSDictionary;
import org.apache.xmlgraphics.ps.PSDictionaryFormatException;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSImageUtils;
import org.apache.xmlgraphics.ps.PSPageDeviceDictionary;
import org.apache.xmlgraphics.ps.PSProcSets;
import org.apache.xmlgraphics.ps.PSResource;
@@ -97,6 +89,8 @@ import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.ImageAdapter;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererEventProducer;
import org.apache.fop.render.ps.extensions.PSCommentAfter;
@@ -350,50 +344,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer
}
}

/**
* Indicates whether an image should be inlined or added as a PostScript form.
* @param uri the URI of the image
* @return true if the image should be inlined rather than added as a form
*/
protected boolean isImageInlined(String uri) {
return !isOptimizeResources() || uri == null || "".equals(uri);
}

/**
* Indicates whether an image should be inlined or added as a PostScript form.
* @param info the ImageInfo object of the image
* @return true if the image should be inlined rather than added as a form
*/
protected boolean isImageInlined(ImageInfo info) {
if (isImageInlined(info.getOriginalURI())) {
return true;
}

if (!isOptimizeResources()) {
throw new IllegalStateException("Must not get here if form support is enabled");
}

//Investigate choice for inline mode
ImageFlavor[] inlineFlavors = getInlineFlavors();
ImageManager manager = getUserAgent().getFactory().getImageManager();
ImageProviderPipeline[] inlineCandidates
= manager.getPipelineFactory().determineCandidatePipelines(
info, inlineFlavors);
ImageProviderPipeline inlineChoice = manager.choosePipeline(inlineCandidates);
ImageFlavor inlineFlavor = (inlineChoice != null ? inlineChoice.getTargetFlavor() : null);

//Investigate choice for form mode
ImageFlavor[] formFlavors = getFormFlavors();
ImageProviderPipeline[] formCandidates
= manager.getPipelineFactory().determineCandidatePipelines(
info, formFlavors);
ImageProviderPipeline formChoice = manager.choosePipeline(formCandidates);
ImageFlavor formFlavor = (formChoice != null ? formChoice.getTargetFlavor() : null);

//Inline if form is not supported or if a better choice is available with inline mode
return formFlavor == null || !formFlavor.equals(inlineFlavor);
}

/** {@inheritDoc} */
protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
endTextObject();
@@ -403,89 +353,48 @@ public class PSRenderer extends AbstractPathOrientedRenderer
if (log.isDebugEnabled()) {
log.debug("Handling image: " + uri);
}
int width = (int)pos.getWidth();
int height = (int)pos.getHeight();
Rectangle targetRect = new Rectangle(x, y, width, height);

ImageManager manager = getUserAgent().getFactory().getImageManager();
ImageInfo info = null;
try {
ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
info = manager.getImageInfo(uri, sessionContext);
int width = (int)pos.getWidth();
int height = (int)pos.getHeight();

//millipoints --> points for PostScript
float ptx = x / 1000f;
float pty = y / 1000f;
float ptw = width / 1000f;
float pth = height / 1000f;
PSRenderingContext renderingContext = new PSRenderingContext(
getUserAgent(), gen, getFontInfo());

if (isImageInlined(info)) {
if (!isOptimizeResources()
|| PSImageUtils.isImageInlined(info, renderingContext)) {
if (log.isDebugEnabled()) {
log.debug("Image " + info + " is inlined");
}

//Determine supported flavors
ImageFlavor[] flavors;
ImageHandlerRegistry imageHandlerRegistry
= userAgent.getFactory().getImageHandlerRegistry();
flavors = imageHandlerRegistry.getSupportedFlavors(renderingContext);

//Only now fully load/prepare the image
Map hints = ImageUtil.getDefaultHints(sessionContext);
org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
info, getInlineFlavors(), hints, sessionContext);
info, flavors, hints, sessionContext);

//Get handler for image
ImageHandler basicHandler = imageHandlerRegistry.getHandler(renderingContext, img);

//...and embed as inline image
if (img instanceof ImageGraphics2D) {
ImageGraphics2D imageG2D = (ImageGraphics2D)img;
RendererContext context = createRendererContext(
x, y, width, height, foreignAttributes);
getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
context, x, y, width, height);
} else if (img instanceof ImageRendered) {
ImageRendered imgRend = (ImageRendered)img;
RenderedImage ri = imgRend.getRenderedImage();
PSImageUtils.renderBitmapImage(ri, ptx, pty, ptw, pth, gen);
} else if (img instanceof ImageXMLDOM) {
ImageXMLDOM imgXML = (ImageXMLDOM)img;
renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(),
pos, foreignAttributes);
} else if (img instanceof ImageRawStream) {
final ImageRawStream raw = (ImageRawStream)img;
if (raw instanceof ImageRawEPS) {
ImageRawEPS eps = (ImageRawEPS)raw;
Rectangle2D bbox = eps.getBoundingBox();
InputStream in = raw.createInputStream();
try {
PSImageUtils.renderEPS(in, uri,
new Rectangle2D.Float(ptx, pty, ptw, pth),
bbox,
gen);
} finally {
IOUtils.closeQuietly(in);
}
} else if (raw instanceof ImageRawCCITTFax) {
final ImageRawCCITTFax ccitt = (ImageRawCCITTFax)raw;
ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
Rectangle2D targetRect = new Rectangle2D.Float(
ptx, pty, ptw, pth);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
uri, targetRect,
ccitt.getColorSpace(), 1, false, gen);
} else if (raw instanceof ImageRawJPEG) {
ImageRawJPEG jpeg = (ImageRawJPEG)raw;
ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
Rectangle2D targetRect = new Rectangle2D.Float(
ptx, pty, ptw, pth);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
uri, targetRect,
jpeg.getColorSpace(), 8, jpeg.isInverted(), gen);
} else {
throw new UnsupportedOperationException("Unsupported raw image: " + info);
}
} else {
throw new UnsupportedOperationException("Unsupported image type: " + img);
}
basicHandler.handleImage(renderingContext, img, targetRect);
} else {
if (log.isDebugEnabled()) {
log.debug("Image " + info + " is embedded as a form later");
}
//Don't load image at this time, just put a form placeholder in the stream
PSResource form = getFormForImage(uri);
Rectangle2D targetRect = new Rectangle2D.Double(ptx, pty, ptw, pth);
PSImageUtils.paintForm(form, info.getSize().getDimensionPt(), targetRect, gen);
PSResource form = getFormForImage(info.getOriginalURI());
PSImageUtils.drawForm(form, info, targetRect, gen);
}

} catch (ImageException ie) {
@@ -503,26 +412,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer
}
}

private ImageFlavor[] getInlineFlavors() {
ImageFlavor[] flavors;
if (gen.getPSLevel() >= 3) {
flavors = LEVEL_3_FLAVORS_INLINE;
} else {
flavors = LEVEL_2_FLAVORS_INLINE;
}
return flavors;
}

private ImageFlavor[] getFormFlavors() {
ImageFlavor[] flavors;
if (gen.getPSLevel() >= 3) {
flavors = LEVEL_3_FLAVORS_FORM;
} else {
flavors = LEVEL_2_FLAVORS_FORM;
}
return flavors;
}

/**
* Returns a PSResource instance representing a image as a PostScript form.
* @param uri the image URI
@@ -978,8 +867,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer
in = new java.io.BufferedInputStream(in);
try {
try {
ResourceHandler.process(this.userAgent, in, this.outputStream,
this.fontInfo, resTracker, this.formResources,
ResourceHandler handler = new ResourceHandler(this.userAgent, this.fontInfo,
resTracker, this.formResources);
handler.process(in, this.outputStream,
this.currentPageNumber, this.documentBoundingBox);
this.outputStream.flush();
} catch (DSCException e) {

+ 44
- 1
src/java/org/apache/fop/render/ps/PSRenderingContext.java View File

@@ -19,6 +19,7 @@

package org.apache.fop.render.ps;

import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.util.MimeConstants;

import org.apache.fop.apps.FOUserAgent;
@@ -30,17 +31,34 @@ import org.apache.fop.render.AbstractRenderingContext;
*/
public class PSRenderingContext extends AbstractRenderingContext {

private PSGenerator gen;
private FontInfo fontInfo;
private boolean createForms;

/**
* Main constructor.
* @param userAgent the user agent
* @param gen the PostScript generator
* @param fontInfo the font list
*/
public PSRenderingContext(FOUserAgent userAgent,
FontInfo fontInfo) {
PSGenerator gen, FontInfo fontInfo) {
this(userAgent, gen, fontInfo, false);
}

/**
* Special constructor.
* @param userAgent the user agent
* @param gen the PostScript generator
* @param fontInfo the font list
* @param createForms true if form generation mode should be enabled
*/
public PSRenderingContext(FOUserAgent userAgent,
PSGenerator gen, FontInfo fontInfo, boolean createForms) {
super(userAgent);
this.gen = gen;
this.fontInfo = fontInfo;
this.createForms = createForms;
}

/** {@inheritDoc} */
@@ -48,6 +66,14 @@ public class PSRenderingContext extends AbstractRenderingContext {
return MimeConstants.MIME_POSTSCRIPT;
}

/**
* Returns the PostScript generator.
* @return the PostScript generator
*/
public PSGenerator getGenerator() {
return this.gen;
}

/**
* Returns the font list.
* @return the font list
@@ -56,4 +82,21 @@ public class PSRenderingContext extends AbstractRenderingContext {
return this.fontInfo;
}

/**
* Indicates whether PS forms should be created for the images instead of inline images.
* Note that not all image handlers will support this!
* @return true if PS forms shall be created
*/
public boolean isCreateForms() {
return this.createForms;
}

/**
* Create a copy of this rendering context and activate form mode.
* @return the form-enabled rendering context
*/
public PSRenderingContext toFormContext() {
return new PSRenderingContext(getUserAgent(), getGenerator(), getFontInfo(), true);
}

}

+ 163
- 119
src/java/org/apache/fop/render/ps/ResourceHandler.java View File

@@ -21,7 +21,6 @@ package org.apache.fop.render.ps;

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.Iterator;
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.DSCCommentBoundingBox;
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 @@ import org.apache.fop.fonts.FontInfo;
*/
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 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
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 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
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 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
}
}

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);
private void generateFormForImage(PSGenerator gen, PSImageFormResource form)
throws IOException {
final String uri = form.getImageURI();

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");
}
ImageManager manager = userAgent.getFactory().getImageManager();
ImageInfo info = null;
try {
ImageSessionContext sessionContext = userAgent.getImageSessionContext();
info = manager.getImageInfo(uri, sessionContext);

};
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);
//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() + ")");
}

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 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
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();
}
}
}

}

}

+ 139
- 0
test/java/org/apache/fop/render/ps/AbstractPostScriptTestCase.java View File

@@ -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;
}

}

+ 188
- 0
test/java/org/apache/fop/render/ps/ImageHandlingTestCase.java View File

@@ -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();
}

}

+ 222
- 0
test/java/org/apache/fop/render/ps/ResourceOptimizationTestCase.java View File

@@ -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);
}
}

}

+ 35
- 0
test/java/org/apache/fop/render/ps/ps-jpeg-image.fo View File

@@ -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>

+ 50
- 0
test/java/org/apache/fop/render/ps/ps-resources.fo View File

@@ -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>

Loading…
Cancel
Save