aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java')
-rw-r--r--src/java/META-INF/services/org.apache.fop.render.ImageHandler6
-rw-r--r--src/java/org/apache/fop/apps/FOUserAgent.java38
-rw-r--r--src/java/org/apache/fop/render/RendererFactory.java44
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java5
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java28
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java9
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java1
-rw-r--r--src/java/org/apache/fop/render/ps/PSDocumentHandler.java25
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandler.java48
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java107
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java153
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java115
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java115
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java101
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java161
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageUtils.java90
-rw-r--r--src/java/org/apache/fop/render/ps/PSPainter.java48
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java166
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderingContext.java45
-rw-r--r--src/java/org/apache/fop/render/ps/ResourceHandler.java282
20 files changed, 1295 insertions, 292 deletions
diff --git a/src/java/META-INF/services/org.apache.fop.render.ImageHandler b/src/java/META-INF/services/org.apache.fop.render.ImageHandler
index 58e2a52be..730032927 100644
--- a/src/java/META-INF/services/org.apache.fop.render.ImageHandler
+++ b/src/java/META-INF/services/org.apache.fop.render.ImageHandler
@@ -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
diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java
index f051dc281..ebd2e0594 100644
--- a/src/java/org/apache/fop/apps/FOUserAgent.java
+++ b/src/java/org/apache/fop/apps/FOUserAgent.java
@@ -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;
@@ -159,6 +163,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.
* @param renderer the Renderer instance to use
@@ -274,6 +296,22 @@ public class FOUserAgent {
}
/**
+ * 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
*/
diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java
index 721ffa131..19cf76931 100644
--- a/src/java/org/apache/fop/render/RendererFactory.java
+++ b/src/java/org/apache/fop/render/RendererFactory.java
@@ -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;
}
/**
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java
index 4894604a2..a7b2757a8 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java
@@ -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;
}
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
index 07d8334d5..ea74a37c8 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
@@ -209,6 +209,34 @@ public abstract class AbstractIFPainter implements IFPainter {
}
/**
+ * 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
* @param rect the rectangle in which to paint the image
diff --git a/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java
index f1d6e2057..ea07deee6 100644
--- a/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java
+++ b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java
@@ -82,6 +82,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
* @throws IFException if an error occurs setting up the output
@@ -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
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
index e44edf8af..2e3c83126 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -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());
}
diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
index 8223ec29b..365df2fe3 100644
--- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
+++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
@@ -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;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandler.java b/src/java/org/apache/fop/render/ps/PSImageHandler.java
new file mode 100644
index 000000000..ff94fdd2c
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandler.java
@@ -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;
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java b/src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java
new file mode 100644
index 000000000..b77d48162
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
new file mode 100644
index 000000000..b2934d4dd
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java b/src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java
new file mode 100644
index 000000000..1bbbf310c
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java
new file mode 100644
index 000000000..deedf3bc4
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
new file mode 100644
index 000000000..5a13c1c8e
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
new file mode 100644
index 000000000..2138e3cf3
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java
index 7a011fbec..431071701 100644
--- a/src/java/org/apache/fop/render/ps/PSImageUtils.java
+++ b/src/java/org/apache/fop/render/ps/PSImageUtils.java
@@ -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();
+ }
+
+
}
diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java
index e43b0f2c4..3c937addf 100644
--- a/src/java/org/apache/fop/render/ps/PSPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSPainter.java
@@ -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);
}
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
index 83dbd4b62..55f714f31 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderer.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -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) {
diff --git a/src/java/org/apache/fop/render/ps/PSRenderingContext.java b/src/java/org/apache/fop/render/ps/PSRenderingContext.java
index 63f00ea1a..b34874ffa 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderingContext.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderingContext.java
@@ -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} */
@@ -49,6 +67,14 @@ public class PSRenderingContext extends AbstractRenderingContext {
}
/**
+ * 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);
+ }
+
}
diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java
index bdd305164..0b2f174f5 100644
--- a/src/java/org/apache/fop/render/ps/ResourceHandler.java
+++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java
@@ -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();
+ }
+ }
+ }
+
+ }
+
}