aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2008-08-05 15:31:00 +0000
committerJeremias Maerki <jeremias@apache.org>2008-08-05 15:31:00 +0000
commit83abc0b9b18852ffed4533d18f27e1b27df081b5 (patch)
tree7659b6be4f8f6183f8625a343caed2f7606f6909 /src/java
parent46631569e9ccd7e2a179b0c6d1349fa7451ccc70 (diff)
downloadxmlgraphics-fop-83abc0b9b18852ffed4533d18f27e1b27df081b5.tar.gz
xmlgraphics-fop-83abc0b9b18852ffed4533d18f27e1b27df081b5.zip
First steps at unified image handling as proposed on http://wiki.apache.org/xmlgraphics-fop/ImageSupport/ImageHandler. This shall serve as a preview to motivate early feedback if anyone is interested.
Basic external-graphic support now available for PDF and SVG painters (for PDF: RenderedImage, SVG, JPEG, CCITT and Java2D, for SVG: embedded SVG and RFC2397 data URLs containing PNG and JPEG images) Change to IFPainter: added support for foreign attributes for the "image" tag. PDFContentGenerator introduced to hold the most important objects for PDF generation (unification for renderer and painter). Re-routed most image handling through the new image handling code (not fully done, yet, some code duplication remains). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@682757 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r--src/java/META-INF/services/org.apache.fop.render.ImageHandler4
-rw-r--r--src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter1
-rw-r--r--src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java141
-rw-r--r--src/java/org/apache/fop/render/AbstractRenderingContext.java49
-rw-r--r--src/java/org/apache/fop/render/ImageAdapter.java8
-rw-r--r--src/java/org/apache/fop/render/ImageHandler.java78
-rw-r--r--src/java/org/apache/fop/render/ImageHandlerRegistry.java177
-rw-r--r--src/java/org/apache/fop/render/RendererContext.java3
-rw-r--r--src/java/org/apache/fop/render/RenderingContext.java43
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java7
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java13
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFConstants.java5
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFPainter.java3
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFParser.java19
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFRenderer.java24
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFSerializer.java25
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFContentGenerator.java327
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java20
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java77
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java31
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java30
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java30
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java230
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainterMaker.java3
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java332
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingContext.java82
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java29
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFSVGHandler.java45
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java44
29 files changed, 1448 insertions, 432 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
new file mode 100644
index 000000000..8f4354630
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.fop.render.ImageHandler
@@ -0,0 +1,4 @@
+org.apache.fop.render.pdf.PDFImageHandlerGraphics2D
+org.apache.fop.render.pdf.PDFImageHandlerRenderedImage
+org.apache.fop.render.pdf.PDFImageHandlerRawJPEG
+org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax
diff --git a/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter b/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter
new file mode 100644
index 000000000..9bb645ebb
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter
@@ -0,0 +1 @@
+org.apache.fop.render.pdf.PDFPainterMaker \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java
new file mode 100644
index 000000000..a79734d49
--- /dev/null
+++ b/src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java
@@ -0,0 +1,141 @@
+/*
+ * 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;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.fop.util.UnitConv;
+
+/**
+ * Abstract base class for ImageHandler implementations that process Java2D images through
+ * the Graphics2DImagePainter interface.
+ */
+public abstract class AbstractImageHandlerGraphics2D implements ImageHandler {
+
+ /**
+ * Paints the image to a BufferedImage and returns that.
+ * @param painter the painter which will paint the actual image
+ * @param context the renderer context for the current renderer
+ * @param targetDimension the target dimensions of the image to be converted to a bitmap
+ * @param resolution the requested bitmap resolution
+ * @param gray true if the generated image should be in grayscales
+ * @param withAlpha true if an alpha channel should be created
+ * @return the generated BufferedImage
+ */
+ protected BufferedImage paintToBufferedImage(
+ org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter,
+ Dimension targetDimension,
+ int resolution, boolean gray, boolean withAlpha) {
+ int bmw = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getWidth(), resolution));
+ int bmh = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getHeight(), resolution));
+ BufferedImage bi;
+ if (gray) {
+ if (withAlpha) {
+ bi = createGrayBufferedImageWithAlpha(bmw, bmh);
+ } else {
+ bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_BYTE_GRAY);
+ }
+ } else {
+ if (withAlpha) {
+ bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_ARGB);
+ } else {
+ bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_RGB);
+ }
+ }
+ Graphics2D g2d = bi.createGraphics();
+ try {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ setRenderingHintsForBufferedImage(g2d);
+
+ g2d.setBackground(Color.white);
+ g2d.setColor(Color.black);
+ if (!withAlpha) {
+ g2d.clearRect(0, 0, bmw, bmh);
+ }
+ /* debug code
+ int off = 2;
+ g2d.drawLine(off, 0, off, bmh);
+ g2d.drawLine(bmw - off, 0, bmw - off, bmh);
+ g2d.drawLine(0, off, bmw, off);
+ g2d.drawLine(0, bmh - off, bmw, bmh - off);
+ */
+ double sx = (double)bmw / targetDimension.getWidth();
+ double sy = (double)bmh / targetDimension.getHeight();
+ g2d.scale(sx, sy);
+
+ //Paint the image on the BufferedImage
+ Rectangle2D area = new Rectangle2D.Double(
+ 0.0, 0.0, targetDimension.getWidth(), targetDimension.getHeight());
+ painter.paint(g2d, area);
+ } finally {
+ g2d.dispose();
+ }
+ return bi;
+ }
+
+ private static BufferedImage createGrayBufferedImageWithAlpha(int width, int height) {
+ BufferedImage bi;
+ boolean alphaPremultiplied = true;
+ int bands = 2;
+ int[] bits = new int[bands];
+ for (int i = 0; i < bands; i++) {
+ bits[i] = 8;
+ }
+ ColorModel cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ bits,
+ true, alphaPremultiplied,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+ WritableRaster wr = Raster.createInterleavedRaster(
+ DataBuffer.TYPE_BYTE,
+ width, height, bands,
+ new Point(0, 0));
+ bi = new BufferedImage(cm, wr, alphaPremultiplied, null);
+ return bi;
+ }
+
+ /**
+ * Sets rendering hints on the Graphics2D created for painting to a BufferedImage. Subclasses
+ * can modify the settings to customize the behavior.
+ * @param g2d the Graphics2D instance
+ */
+ protected void setRenderingHintsForBufferedImage(Graphics2D g2d) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/AbstractRenderingContext.java b/src/java/org/apache/fop/render/AbstractRenderingContext.java
new file mode 100644
index 000000000..7bacac58d
--- /dev/null
+++ b/src/java/org/apache/fop/render/AbstractRenderingContext.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import org.apache.fop.apps.FOUserAgent;
+
+/**
+ * Abstract base class for RenderingContext implementations.
+ */
+public abstract class AbstractRenderingContext implements RenderingContext {
+
+ private FOUserAgent userAgent;
+
+ /**
+ * Main constructor.
+ * @param userAgent the user agent
+ */
+ public AbstractRenderingContext(FOUserAgent userAgent) {
+ this.userAgent = userAgent;
+ }
+
+ /**
+ * Returns the user agent.
+ *
+ * @return The user agent
+ */
+ public FOUserAgent getUserAgent() {
+ return userAgent;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/render/ImageAdapter.java b/src/java/org/apache/fop/render/ImageAdapter.java
index a67d43bdc..757be43b1 100644
--- a/src/java/org/apache/fop/render/ImageAdapter.java
+++ b/src/java/org/apache/fop/render/ImageAdapter.java
@@ -34,10 +34,10 @@ public interface ImageAdapter {
* Paints an image at the given position.
* @param image the image which will be painted
* @param context the renderer context for the current renderer
- * @param x X position of the image
- * @param y Y position of the image
- * @param width width of the image
- * @param height height of the image
+ * @param x X position of the image (in millipoints)
+ * @param y Y position of the image (in millipoints)
+ * @param width width of the image (in millipoints)
+ * @param height height of the image (in millipoints)
* @throws IOException In case of an I/O error while writing the output format
*/
void paintImage(RenderedImage image,
diff --git a/src/java/org/apache/fop/render/ImageHandler.java b/src/java/org/apache/fop/render/ImageHandler.java
new file mode 100644
index 000000000..42ae5fd49
--- /dev/null
+++ b/src/java/org/apache/fop/render/ImageHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import java.awt.Rectangle;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+
+/**
+ * This interface is used for handling all sorts of image types for PDF output.
+ */
+public interface ImageHandler {
+
+ /**
+ * Returns the priority for this image handler. A lower value means higher priority. This
+ * information is used to build the ordered/prioritized list of supported ImageFlavors.
+ * The built-in handlers use priorities between 100 and 999.
+ * @return a positive integer (>0) indicating the priority
+ */
+ int getPriority();
+
+ /**
+ * Returns the {@link ImageFlavor}s supported by this instance
+ * @return the supported image flavors
+ */
+ ImageFlavor[] getSupportedImageFlavors();
+
+ /**
+ * Indicates whether the image handler is compatible with the indicated target represented
+ * by the rendering context object and with the image to be processed. The image is also
+ * passed as a parameter because a handler might not support every subtype of image that is
+ * presented. For example: in the case of {@code ImageXMLDOM}, the image might carry an SVG
+ * or some other XML format. One handler might only handle SVG but no other XML format.
+ * @param targetContext the target rendering context
+ * @param image the image to be processed (or null if only to check based on the rendering
+ * context)
+ * @return true if this handler is compatible with the target rendering context
+ */
+ boolean isCompatible(RenderingContext targetContext, Image image);
+
+ /**
+ * Returns the {@link Image} subclass supported by this instance.
+ * @return the Image type
+ */
+ Class getSupportedImageClass();
+
+ /**
+ * Handles the given {@link Image} instance painting it at the indicated position in the
+ * output format being generated.
+ * @param context the rendering context
+ * @param image the image to be handled
+ * @param pos the position and scaling of the image relative to the origin point of the
+ * current viewport (in millipoints)
+ * @throws IOException if an I/O error occurs
+ */
+ void handleImage(RenderingContext context, Image image,
+ Rectangle pos) throws IOException;
+
+}
diff --git a/src/java/org/apache/fop/render/ImageHandlerRegistry.java b/src/java/org/apache/fop/render/ImageHandlerRegistry.java
new file mode 100644
index 000000000..3a241138a
--- /dev/null
+++ b/src/java/org/apache/fop/render/ImageHandlerRegistry.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.util.Service;
+
+/**
+ * This class holds references to various image handlers. It also
+ * supports automatic discovery of additional handlers available through
+ * the class path.
+ */
+public class ImageHandlerRegistry {
+
+ /** the logger */
+ private static Log log = LogFactory.getLog(ImageHandlerRegistry.class);
+
+ private static final Comparator HANDLER_COMPARATOR = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ ImageHandler h1 = (ImageHandler)o1;
+ ImageHandler h2 = (ImageHandler)o2;
+ return h1.getPriority() - h2.getPriority();
+ }
+ };
+
+ /** Map containing image handlers for various {@code Image} subclasses. */
+ private Map handlers = new java.util.HashMap();
+ /** List containing the same handlers as above but ordered by priority */
+ private List handlerList = new java.util.LinkedList();
+
+ private int handlerRegistrations;
+
+ /**
+ * Default constructor.
+ */
+ public ImageHandlerRegistry() {
+ discoverHandlers();
+ }
+
+ /**
+ * Add an PDFImageHandler. The handler itself is inspected to find out what it supports.
+ * @param classname the fully qualified class name
+ */
+ public void addHandler(String classname) {
+ try {
+ ImageHandler handlerInstance
+ = (ImageHandler)Class.forName(classname).newInstance();
+ addHandler(handlerInstance);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Could not find "
+ + classname);
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException("Could not instantiate "
+ + classname);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Could not access "
+ + classname);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException(classname
+ + " is not an "
+ + ImageHandler.class.getName());
+ }
+ }
+
+ /**
+ * Add an image handler. The handler itself is inspected to find out what it supports.
+ * @param handler the ImageHandler instance
+ */
+ public synchronized void addHandler(ImageHandler handler) {
+ Class imageClass = handler.getSupportedImageClass();
+ //List
+ this.handlers.put(imageClass, handler);
+
+ //Sorted insert (sort by priority)
+ ListIterator iter = this.handlerList.listIterator();
+ while (iter.hasNext()) {
+ ImageHandler h = (ImageHandler)iter.next();
+ if (HANDLER_COMPARATOR.compare(handler, h) < 0) {
+ iter.previous();
+ break;
+ }
+ }
+ iter.add(handler);
+ this.handlerRegistrations++;
+ }
+
+ /**
+ * Returns an {@code ImageHandler} which handles an specific image type given the MIME type
+ * of the image.
+ * @param targetContext the target rendering context that is used for identifying compatibility
+ * @param image the Image to be handled
+ * @return the image handler responsible for handling the image or null if none is available
+ */
+ public ImageHandler getHandler(RenderingContext targetContext, Image image) {
+ ListIterator iter = this.handlerList.listIterator();
+ while (iter.hasNext()) {
+ ImageHandler h = (ImageHandler)iter.next();
+ if (h.isCompatible(targetContext, image)) {
+ //Return the first handler in the prioritized list that is compatible
+ return h;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the ordered array of supported image flavors. The array needs to be ordered by
+ * priority so the image loader framework can return the preferred image type.
+ * @return the array of image flavors
+ */
+ public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) {
+ //Extract all ImageFlavors into a single array
+ List flavors = new java.util.ArrayList();
+ Iterator iter = this.handlerList.iterator();
+ while (iter.hasNext()) {
+ ImageHandler handler = (ImageHandler)iter.next();
+ if (handler.isCompatible(context, null)) {
+ ImageFlavor[] f = handler.getSupportedImageFlavors();
+ for (int i = 0; i < f.length; i++) {
+ flavors.add(f[i]);
+ }
+ }
+ }
+ return (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]);
+ }
+
+ /**
+ * Discovers ImageHandler implementations through the classpath and dynamically
+ * registers them.
+ */
+ private void discoverHandlers() {
+ // add mappings from available services
+ Iterator providers = Service.providers(ImageHandler.class);
+ if (providers != null) {
+ while (providers.hasNext()) {
+ ImageHandler handler = (ImageHandler)providers.next();
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Dynamically adding ImageHandler: "
+ + handler.getClass().getName());
+ }
+ addHandler(handler);
+ } catch (IllegalArgumentException e) {
+ log.error("Error while adding ImageHandler", e);
+ }
+
+ }
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/RendererContext.java b/src/java/org/apache/fop/render/RendererContext.java
index 08ca76957..e52588176 100644
--- a/src/java/org/apache/fop/render/RendererContext.java
+++ b/src/java/org/apache/fop/render/RendererContext.java
@@ -22,7 +22,6 @@ package org.apache.fop.render;
//Java
import java.util.Map;
-//FOP
import org.apache.fop.apps.FOUserAgent;
/**
@@ -30,7 +29,7 @@ import org.apache.fop.apps.FOUserAgent;
* so that external handlers can get information to be able to render to the
* render target.
*/
-public class RendererContext {
+public class RendererContext implements RenderingContext {
private String mime;
private AbstractRenderer renderer;
diff --git a/src/java/org/apache/fop/render/RenderingContext.java b/src/java/org/apache/fop/render/RenderingContext.java
new file mode 100644
index 000000000..a6f958328
--- /dev/null
+++ b/src/java/org/apache/fop/render/RenderingContext.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.fop.apps.FOUserAgent;
+
+/**
+ * Implementations of this interface provide context information needed by supporting classes
+ * during specific tasks (like image rendering).
+ */
+public interface RenderingContext {
+
+ /**
+ * Returns the MIME type associated with the current output format.
+ * @return the MIME type (ex. application/pdf)
+ */
+ String getMimeType();
+
+ /**
+ * Returns the user agent. The user agent is used to access configuration and other information
+ * for the rendering process.
+ * @return the user agent
+ */
+ FOUserAgent getUserAgent();
+
+}
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
index 54d5b33b4..f5e43229b 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.render.ImageHandlerRegistry;
/**
* Abstract base class for IFPainter implementations.
@@ -32,6 +33,9 @@ public abstract class AbstractIFPainter implements IFPainter {
private FOUserAgent userAgent;
+ /** Image handler registry */
+ protected ImageHandlerRegistry imageHandlerRegistry = new ImageHandlerRegistry();
+
/**
* Default constructor.
*/
@@ -40,6 +44,9 @@ public abstract class AbstractIFPainter implements IFPainter {
/** {@inheritDoc} */
public void setUserAgent(FOUserAgent ua) {
+ if (this.userAgent != null) {
+ throw new IllegalStateException("The user agent was already set");
+ }
this.userAgent = ua;
}
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java
index 9e0f97699..63238354b 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java
@@ -35,6 +35,8 @@ import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import org.apache.xmlgraphics.util.QName;
+
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.util.DecimalFormatCache;
@@ -219,6 +221,17 @@ public abstract class AbstractXMLWritingIFPainter extends AbstractIFPainter {
}
/**
+ * Adds an attribute to a given {@code AttributesImpl} instance.
+ * @param atts the attributes collection
+ * @param attribute the attribute to add
+ * @param value the attribute's CDATA value
+ */
+ protected void addAttribute(AttributesImpl atts, QName attribute, String value) {
+ atts.addAttribute(attribute.getNamespaceURI(),
+ attribute.getLocalName(), attribute.getQName(), CDATA, value);
+ }
+
+ /**
* Converts an array of integer coordinates into a space-separated string.
* @param coordinates the coordinates
* @return the space-separated array of coordinates
diff --git a/src/java/org/apache/fop/render/intermediate/IFConstants.java b/src/java/org/apache/fop/render/intermediate/IFConstants.java
index 18de496e1..b90e77d07 100644
--- a/src/java/org/apache/fop/render/intermediate/IFConstants.java
+++ b/src/java/org/apache/fop/render/intermediate/IFConstants.java
@@ -19,6 +19,8 @@
package org.apache.fop.render.intermediate;
+import org.apache.xmlgraphics.util.QName;
+
import org.apache.fop.apps.MimeConstants;
/**
@@ -39,6 +41,8 @@ public interface IFConstants {
String XLINK_PREFIX = "xlink";
/** XML namespace for XLink */
String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink";
+ /** xlink:href attribute */
+ QName XLINK_HREF = new QName(XLINK_NAMESPACE, XLINK_PREFIX, "href");
String EL_DOCUMENT = "document";
String EL_HEADER = "header";
@@ -49,4 +53,5 @@ public interface IFConstants {
String EL_PAGE_CONTENT = "content";
String EL_VIEWPORT = "viewport";
String EL_GROUP = "g";
+ String EL_IMAGE = "image";
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java
index 269c4b0ad..e257caec4 100644
--- a/src/java/org/apache/fop/render/intermediate/IFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java
@@ -24,6 +24,7 @@ import java.awt.Dimension;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
+import java.util.Map;
import javax.xml.transform.Result;
@@ -257,7 +258,7 @@ public interface IFPainter {
* @throws IFException if an error occurs while handling this event
*/
void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException;
- void drawImage(String uri, Rectangle rect) throws IFException; //external images
+ void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException; //external images
void startImage(Rectangle rect) throws IFException; //followed by a SAX stream (SVG etc.)
void endImage() throws IFException;
//etc. etc.
diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java
index 09358da40..566b91a9a 100644
--- a/src/java/org/apache/fop/render/intermediate/IFParser.java
+++ b/src/java/org/apache/fop/render/intermediate/IFParser.java
@@ -135,6 +135,7 @@ public class IFParser implements IFConstants {
elementHandlers.put("font", new FontHandler());
elementHandlers.put("text", new TextHandler());
elementHandlers.put("rect", new RectHandler());
+ elementHandlers.put(EL_IMAGE, new ImageHandler());
}
@@ -459,6 +460,24 @@ public class IFParser implements IFConstants {
}
+ private class ImageHandler extends AbstractElementHandler {
+
+ public void endElement() throws IFException {
+ int x = Integer.parseInt(lastAttributes.getValue("x"));
+ int y = Integer.parseInt(lastAttributes.getValue("y"));
+ int width = Integer.parseInt(lastAttributes.getValue("width"));
+ int height = Integer.parseInt(lastAttributes.getValue("height"));
+ String uri = lastAttributes.getValue(
+ XLINK_HREF.getNamespaceURI(), XLINK_HREF.getLocalName());
+ Map foreignAttributes = null; //TODO Implement me!
+ painter.drawImage(uri, new Rectangle(x, y, width, height), foreignAttributes);
+ }
+
+ public boolean ignoreCharacters() {
+ return false;
+ }
+ }
+
// ====================================================================
diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
index a8e0208f1..e870a4263 100644
--- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
@@ -62,6 +62,7 @@ import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
@@ -168,8 +169,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
}
if (this.painter == null) {
this.painter = new IFSerializer();
+ this.painter.setUserAgent(getUserAgent());
}
- this.painter.setUserAgent(getUserAgent());
this.painter.setFontInfo(fontInfo);
this.painter.setResult(result);
}
@@ -695,15 +696,22 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
/** {@inheritDoc} */
public void renderImage(Image image, Rectangle2D pos) {
- if (log.isDebugEnabled()) {
- log.debug("renderImage() image=" + image + ", pos=" + pos);
- }
- super.renderImage(image, pos);
+ drawImage(image.getURL(), pos, image.getForeignAttributes());
}
- protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
- // TODO Auto-generated method stub
- log.warn("drawImage() NYI");
+ /** {@inheritDoc} */
+ protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
+ Rectangle posInt = new Rectangle(
+ currentIPPosition + (int)pos.getX(),
+ currentBPPosition + (int)pos.getY(),
+ (int)pos.getWidth(),
+ (int)pos.getHeight());
+ uri = URISpecification.getURL(uri);
+ try {
+ painter.drawImage(uri, posInt, foreignAttributes);
+ } catch (IFException ife) {
+ handleIFException(ife);
+ }
}
protected void clip() {
diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
index 601732b39..0f3d20f0b 100644
--- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
@@ -24,10 +24,13 @@ import java.awt.Dimension;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
+import java.util.Iterator;
+import java.util.Map;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import org.apache.xmlgraphics.util.QName;
import org.apache.xmlgraphics.util.XMLizable;
import org.apache.fop.util.ColorUtil;
@@ -275,9 +278,25 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst
}
/** {@inheritDoc} */
- public void drawImage(String uri, Rectangle rect) throws IFException {
- // TODO Auto-generated method stub
-
+ public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException {
+ try {
+ AttributesImpl atts = new AttributesImpl();
+ addAttribute(atts, XLINK_HREF, uri);
+ atts.addAttribute("", "x", "x", CDATA, Integer.toString(rect.x));
+ atts.addAttribute("", "y", "y", CDATA, Integer.toString(rect.y));
+ atts.addAttribute("", "width", "width", CDATA, Integer.toString(rect.width));
+ atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height));
+ if (foreignAttributes != null) {
+ Iterator iter = foreignAttributes.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ addAttribute(atts, (QName)entry.getKey(), entry.getValue().toString());
+ }
+ }
+ element(EL_IMAGE, atts);
+ } catch (SAXException e) {
+ throw new IFException("SAX error in startGroup()", e);
+ }
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
new file mode 100644
index 000000000..ba2a20707
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
@@ -0,0 +1,327 @@
+/*
+ * 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.pdf;
+
+import java.awt.Color;
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilterList;
+import org.apache.fop.pdf.PDFNumber;
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFState;
+import org.apache.fop.pdf.PDFStream;
+import org.apache.fop.pdf.PDFTextUtil;
+import org.apache.fop.pdf.PDFXObject;
+
+/**
+ * Generator class encapsulating all object references and state necessary to generate a
+ * PDF content stream.
+ */
+public class PDFContentGenerator {
+
+ /** Controls whether comments are written to the PDF stream. */
+ protected static final boolean WRITE_COMMENTS = true;
+
+ private PDFDocument document;
+ private OutputStream outputStream;
+ private PDFResourceContext resourceContext;
+
+ /** the current stream to add PDF commands to */
+ private PDFStream currentStream;
+
+ /** drawing state */
+ protected PDFState currentState = null;
+ /** Text generation utility holding the current font status */
+ protected PDFTextUtil textutil;
+
+
+ /**
+ * Main constructor. Creates a new PDF stream and additional helper classes for text painting
+ * and state management.
+ * @param document the PDF document
+ * @param out the output stream the PDF document is generated to
+ * @param resourceContext the resource context
+ */
+ public PDFContentGenerator(PDFDocument document, OutputStream out,
+ PDFResourceContext resourceContext) {
+ this.document = document;
+ this.outputStream = out;
+ this.resourceContext = resourceContext;
+ this.currentStream = document.getFactory()
+ .makeStream(PDFFilterList.CONTENT_FILTER, false);
+ this.textutil = new PDFTextUtil() {
+ protected void write(String code) {
+ currentStream.add(code);
+ }
+ };
+
+ this.currentState = new PDFState();
+ }
+
+ /**
+ * Returns the applicable resource context for the generator.
+ * @return the resource context
+ */
+ public PDFDocument getDocument() {
+ return this.document;
+ }
+
+ /**
+ * Returns the output stream the PDF document is written to.
+ * @return the output stream
+ */
+ public OutputStream getOutputStream() {
+ return this.outputStream;
+ }
+
+ /**
+ * Returns the applicable resource context for the generator.
+ * @return the resource context
+ */
+ public PDFResourceContext getResourceContext() {
+ return this.resourceContext;
+ }
+
+ /**
+ * Returns the {@code PDFStream} associated with this instance.
+ * @return the PDF stream
+ */
+ public PDFStream getStream() {
+ return this.currentStream;
+ }
+
+ /**
+ * Returns the {@code PDFState} associated with this instance.
+ * @return the PDF state
+ */
+ public PDFState getState() {
+ return this.currentState;
+ }
+
+ /**
+ * Returns the {@code PDFTextUtil} associated with this instance.
+ * @return the text utility
+ */
+ public PDFTextUtil getTextUtil() {
+ return this.textutil;
+ }
+
+ /**
+ * Flushes all queued PDF objects ready to be written to the output stream.
+ * @throws IOException if an error occurs while flushing the PDF objects
+ */
+ public void flushPDFDoc() throws IOException {
+ this.document.output(this.outputStream);
+ }
+
+ /**
+ * Writes out a comment.
+ * @param text text for the comment
+ */
+ protected void comment(String text) {
+ if (WRITE_COMMENTS) {
+ currentStream.add("% " + text + "\n");
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void saveGraphicsState() {
+ endTextObject();
+ currentState.push();
+ currentStream.add("q\n");
+ }
+
+ /**
+ * Restored the graphics state valid before the previous {@code #saveGraphicsState()}.
+ * @param popState true if the state should also be popped, false if only the PDF command
+ * should be issued
+ */
+ protected void restoreGraphicsState(boolean popState) {
+ endTextObject();
+ currentStream.add("Q\n");
+ if (popState) {
+ currentState.pop();
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void restoreGraphicsState() {
+ restoreGraphicsState(true);
+ }
+
+ /** Indicates the beginning of a text object. */
+ protected void beginTextObject() {
+ if (!textutil.isInTextObject()) {
+ textutil.beginTextObject();
+ }
+ }
+
+ /** Indicates the end of a text object. */
+ protected void endTextObject() {
+ if (textutil.isInTextObject()) {
+ textutil.endTextObject();
+ }
+ }
+
+ /**
+ * Concatenates the given transformation matrix with the current one.
+ * @param transform the transformation matrix (in points)
+ */
+ public void concatenate(AffineTransform transform) {
+ concatenate(transform, false);
+ }
+
+ /**
+ * Concatenates the given transformation matrix with the current one.
+ * @param transform the transformation matrix
+ * @param convertMillipoints true if the coordinates are in millipoints and need to be
+ * converted to points
+ */
+ public void concatenate(AffineTransform transform, boolean convertMillipoints) {
+ if (!transform.isIdentity()) {
+ currentState.concatenate(transform);
+ currentStream.add(CTMHelper.toPDFString(transform, convertMillipoints) + " cm\n");
+ }
+ }
+
+ /**
+ * Adds content to the stream.
+ * @param content the PDF content
+ */
+ public void add(String content) {
+ currentStream.add(content);
+ }
+
+ /**
+ * Formats a float value (normally coordinates in points) as Strings.
+ * @param value the value
+ * @return the formatted value
+ */
+ protected static String format(float value) {
+ return PDFNumber.doubleOut(value);
+ }
+
+ /**
+ * Sets the current line width in points.
+ * @param width line width in points
+ */
+ public void updateLineWidth(float width) {
+ if (currentState.setLineWidth(width)) {
+ //Only write if value has changed WRT the current line width
+ currentStream.add(format(width) + " w\n");
+ }
+ }
+
+ /**
+ * Establishes a new foreground or fill color. In contrast to updateColor
+ * this method does not check the PDFState for optimization possibilities.
+ * @param col the color to apply
+ * @param fill true to set the fill color, false for the foreground color
+ * @param pdf StringBuffer to write the PDF code to
+ *//*
+ public void setColor(Color col, boolean fill, StringBuffer pdf) {
+ assert pdf != null;
+ }*/
+
+ /**
+ * Establishes a new foreground or fill color.
+ * @param col the color to apply
+ * @param fill true to set the fill color, false for the foreground color
+ * @param stream the PDFStream to write the PDF code to
+ */
+ public void setColor(Color col, boolean fill, PDFStream stream) {
+ assert stream != null;
+ PDFColor color = new PDFColor(this.document, col);
+ stream.add(color.getColorSpaceOut(fill));
+ }
+
+ /**
+ * Establishes a new foreground or fill color.
+ * @param col the color to apply
+ * @param fill true to set the fill color, false for the foreground color
+ */
+ public void setColor(Color col, boolean fill) {
+ setColor(col, fill, getStream());
+ }
+
+ /**
+ * Establishes a new foreground or fill color. In contrast to updateColor
+ * this method does not check the PDFState for optimization possibilities.
+ * @param col the color to apply
+ * @param fill true to set the fill color, false for the foreground color
+ * @param pdf StringBuffer to write the PDF code to, if null, the code is
+ * written to the current stream.
+ */
+ protected void setColor(Color col, boolean fill, StringBuffer pdf) {
+ if (pdf != null) {
+ PDFColor color = new PDFColor(this.document, col);
+ pdf.append(color.getColorSpaceOut(fill));
+ } else {
+ setColor(col, fill, this.currentStream);
+ }
+ }
+
+ /**
+ * Establishes a new foreground or fill color.
+ * @param col the color to apply (null skips this operation)
+ * @param fill true to set the fill color, false for the foreground color
+ * @param pdf StringBuffer to write the PDF code to, if null, the code is
+ * written to the current stream.
+ */
+ public void updateColor(Color col, boolean fill, StringBuffer pdf) {
+ if (col == null) {
+ return;
+ }
+ boolean update = false;
+ if (fill) {
+ update = getState().setBackColor(col);
+ } else {
+ update = getState().setColor(col);
+ }
+
+ if (update) {
+ setColor(col, fill, pdf);
+ }
+ }
+
+ /**
+ * Places a previously registered image at a certain place on the page.
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param w width for image
+ * @param h height for image
+ * @param xobj the image XObject
+ */
+ public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
+ saveGraphicsState();
+ add(format(w) + " 0 0 "
+ + format(-h) + " "
+ + format(x) + " "
+ + format(y + h)
+ + " cm\n" + xobj.getName() + " Do\n");
+ restoreGraphicsState();
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
index b61ebc346..f69937888 100644
--- a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
@@ -55,6 +55,7 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter {
RendererContext context,
int x, int y, int width, int height) throws IOException {
+ PDFContentGenerator generator = renderer.getGenerator();
PDFSVGHandler.PDFInfo pdfInfo = PDFSVGHandler.getPDFInfo(context);
float fwidth = width / 1000f;
float fheight = height / 1000f;
@@ -69,16 +70,17 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter {
float sx = fwidth / (float)imw;
float sy = fheight / (float)imh;
- renderer.saveGraphicsState();
- renderer.setColor(Color.black, false, null);
- renderer.setColor(Color.black, true, null);
+ generator.comment("G2D start");
+ generator.saveGraphicsState();
+ generator.updateColor(Color.black, false, null);
+ generator.updateColor(Color.black, true, null);
//TODO Clip to the image area.
// 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.
- renderer.currentStream.add(sx + " 0 0 " + sy + " " + fx + " "
+ generator.add(sx + " 0 0 " + sy + " " + fx + " "
+ fy + " cm\n");
@@ -95,8 +97,8 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter {
AffineTransform transform = new AffineTransform();
transform.translate(fx, fy);
- pdfInfo.pdfState.concatenate(transform);
- graphics.setPDFState(pdfInfo.pdfState);
+ generator.getState().concatenate(transform);
+ graphics.setPDFState(generator.getState());
graphics.setOutputStream(pdfInfo.outputStream);
if (pdfInfo.paintAsBitmap) {
@@ -113,9 +115,9 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter {
painter.paint(graphics, area);
}
- pdfInfo.currentStream.add(graphics.getString());
- renderer.restoreGraphicsState();
- pdfInfo.pdfState.pop();
+ generator.add(graphics.getString());
+ generator.restoreGraphicsState();
+ generator.comment("G2D end");
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
index a58fe5922..610fa274f 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
@@ -19,8 +19,12 @@
package org.apache.fop.render.pdf;
+import java.awt.Color;
+import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
import java.io.IOException;
import org.apache.xmlgraphics.image.loader.Image;
@@ -28,12 +32,16 @@ import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.AbstractImageHandlerGraphics2D;
import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RenderingContext;
+import org.apache.fop.svg.PDFGraphics2D;
/**
* PDFImageHandler implementation which handles Graphics2D images.
*/
-public class PDFImageHandlerGraphics2D implements PDFImageHandler {
+public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D
+ implements PDFImageHandler {
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.GRAPHICS2D,
@@ -44,13 +52,74 @@ public class PDFImageHandlerGraphics2D implements PDFImageHandler {
Point origin, Rectangle pos)
throws IOException {
PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ /*
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
renderer.getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
context, origin.x + pos.x, origin.y + pos.y, pos.width, pos.height);
+ */
+ PDFRenderingContext pdfContext = new PDFRenderingContext(
+ context.getUserAgent(),
+ renderer.getGenerator(),
+ renderer.currentPage,
+ renderer.getFontInfo());
+ Rectangle effPos = new Rectangle(origin.x + pos.x, origin.y + pos.y, pos.width, pos.height);
+ handleImage(pdfContext, image, effPos);
return null;
}
/** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ PDFRenderingContext pdfContext = (PDFRenderingContext)context;
+ PDFContentGenerator generator = pdfContext.getGenerator();
+ ImageGraphics2D imageG2D = (ImageGraphics2D)image;
+ float fwidth = pos.width / 1000f;
+ float fheight = pos.height / 1000f;
+ float fx = pos.x / 1000f;
+ float fy = pos.y / 1000f;
+
+ // get the 'width' and 'height' attributes of the SVG document
+ Dimension dim = image.getInfo().getSize().getDimensionMpt();
+ float imw = (float)dim.getWidth() / 1000f;
+ float imh = (float)dim.getHeight() / 1000f;
+
+ float sx = fwidth / (float)imw;
+ float sy = fheight / (float)imh;
+
+ generator.comment("G2D start");
+ generator.saveGraphicsState();
+ generator.updateColor(Color.black, false, null);
+ generator.updateColor(Color.black, true, null);
+
+ //TODO Clip to the image area.
+
+ // 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.
+ generator.add(sx + " 0 0 " + sy + " " + fx + " " + fy + " cm\n");
+
+ final boolean textAsShapes = false;
+ PDFGraphics2D graphics = new PDFGraphics2D(textAsShapes,
+ pdfContext.getFontInfo(), generator.getDocument(),
+ generator.getResourceContext(), pdfContext.getPage().referencePDF(),
+ "", 0.0f);
+ graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
+
+ AffineTransform transform = new AffineTransform();
+ transform.translate(fx, fy);
+ generator.getState().concatenate(transform);
+ graphics.setPDFState(generator.getState());
+ graphics.setOutputStream(generator.getOutputStream());
+
+ Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
+ imageG2D.getGraphics2DImagePainter().paint(graphics, area);
+
+ generator.add(graphics.getString());
+ generator.restoreGraphicsState();
+ generator.comment("G2D end");
+ }
+
+ /** {@inheritDoc} */
public int getPriority() {
return 200;
}
@@ -65,4 +134,10 @@ public class PDFImageHandlerGraphics2D implements PDFImageHandler {
return FLAVORS;
}
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageGraphics2D)
+ && targetContext instanceof PDFRenderingContext;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
index 9f56ebfea..75b1d356e 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
@@ -31,12 +31,15 @@ import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RenderingContext;
/**
- * PDFImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4).
+ * Image handler implementation which handles CCITT encoded images (CCITT fax group 3/4)
+ * for PDF output.
*/
-public class PDFImageHandlerRawCCITTFax implements PDFImageHandler {
+public class PDFImageHandlerRawCCITTFax implements PDFImageHandler, ImageHandler {
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.RAW_CCITTFAX,
@@ -66,6 +69,24 @@ public class PDFImageHandlerRawCCITTFax implements PDFImageHandler {
}
/** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ PDFRenderingContext pdfContext = (PDFRenderingContext)context;
+ PDFContentGenerator generator = pdfContext.getGenerator();
+ ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
+
+ PDFImage pdfimage = new ImageRawCCITTFaxAdapter(ccitt, image.getInfo().getOriginalURI());
+ PDFXObject xobj = generator.getDocument().addImage(
+ generator.getResourceContext(), pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ generator.placeImage(x, y, w, h, xobj);
+ }
+
+ /** {@inheritDoc} */
public int getPriority() {
return 100;
}
@@ -80,4 +101,10 @@ public class PDFImageHandlerRawCCITTFax implements PDFImageHandler {
return FLAVORS;
}
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageRawCCITTFax)
+ && targetContext instanceof PDFRenderingContext;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
index f971a49ae..d47d5a439 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
@@ -31,12 +31,14 @@ import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RenderingContext;
/**
- * PDFImageHandler implementation which handles raw JPEG images.
+ * Image handler implementation which handles raw JPEG images for PDF output.
*/
-public class PDFImageHandlerRawJPEG implements PDFImageHandler {
+public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler {
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.RAW_JPEG,
@@ -66,6 +68,24 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler {
}
/** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ PDFRenderingContext pdfContext = (PDFRenderingContext)context;
+ PDFContentGenerator generator = pdfContext.getGenerator();
+ ImageRawJPEG imageJPEG = (ImageRawJPEG)image;
+
+ PDFImage pdfimage = new ImageRawJPEGAdapter(imageJPEG, image.getInfo().getOriginalURI());
+ PDFXObject xobj = generator.getDocument().addImage(
+ generator.getResourceContext(), pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ generator.placeImage(x, y, w, h, xobj);
+ }
+
+ /** {@inheritDoc} */
public int getPriority() {
return 100;
}
@@ -80,4 +100,10 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler {
return FLAVORS;
}
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageRawJPEG)
+ && targetContext instanceof PDFRenderingContext;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
index 783cb225c..3e57c7216 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
@@ -31,12 +31,14 @@ import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RenderingContext;
/**
- * PDFImageHandler implementation which handles RenderedImage instances.
+ * Image handler implementation which handles RenderedImage instances for PDF output.
*/
-public class PDFImageHandlerRenderedImage implements PDFImageHandler {
+public class PDFImageHandlerRenderedImage implements PDFImageHandler, ImageHandler {
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.BUFFERED_IMAGE,
@@ -67,6 +69,24 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler {
}
/** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ PDFRenderingContext pdfContext = (PDFRenderingContext)context;
+ PDFContentGenerator generator = pdfContext.getGenerator();
+ ImageRendered imageRend = (ImageRendered)image;
+
+ PDFImage pdfimage = new ImageRenderedAdapter(imageRend, image.getInfo().getOriginalURI());
+ PDFXObject xobj = generator.getDocument().addImage(
+ generator.getResourceContext(), pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ generator.placeImage(x, y, w, h, xobj);
+ }
+
+ /** {@inheritDoc} */
public int getPriority() {
return 300;
}
@@ -81,4 +101,10 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler {
return FLAVORS;
}
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageRendered)
+ && targetContext instanceof PDFRenderingContext;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java
index e75417d33..5b763b197 100644
--- a/src/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -24,16 +24,23 @@ import java.awt.Dimension;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
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.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
@@ -42,19 +49,17 @@ import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFDocument;
-import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
-import org.apache.fop.pdf.PDFState;
-import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFTextUtil;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFPainter;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
import org.apache.fop.util.CharUtilities;
-import org.apache.fop.util.ColorUtil;
/**
* IFPainter implementation that produces PDF.
@@ -79,8 +84,8 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
/** the /Resources object of the PDF document being created */
protected PDFResources pdfResources;
- /** the current stream to add PDF commands to */
- protected PDFStream currentStream;
+ /** The current content generator */
+ protected PDFContentGenerator generator;
/** the current annotation list to add annotations to */
protected PDFResourceContext currentContext;
@@ -98,16 +103,6 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
/** the current page's PDF reference string (to avoid numerous function calls) */
protected String currentPageRef;
- /** drawing state */
- protected PDFState currentState;
-
- /** Text generation utility holding the current font status */
- protected PDFTextUtil textutil;
-
-
- /** Image handler registry */
- private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
-
/**
* Default constructor.
*/
@@ -173,11 +168,9 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
//pageReferences.clear();
pdfResources = null;
- currentStream = null;
+ this.generator = null;
currentContext = null;
currentPage = null;
- currentState = null;
- this.textutil = null;
//idPositions.clear();
//idGoTos.clear();
@@ -213,20 +206,11 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
currentPageRef = currentPage.referencePDF();
- currentStream = this.pdfDoc.getFactory()
- .makeStream(PDFFilterList.CONTENT_FILTER, false);
- this.textutil = new PDFTextUtil() {
- protected void write(String code) {
- currentStream.add(code);
- }
- };
-
- currentState = new PDFState();
+ this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, this.currentPage);
// Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's
AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
size.height);
- currentState.concatenate(basicPageTransform);
- currentStream.add(CTMHelper.toPDFString(basicPageTransform, true) + " cm\n");
+ generator.concatenate(basicPageTransform, true);
}
/** {@inheritDoc} */
@@ -258,80 +242,136 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
/** {@inheritDoc} */
public void endPage() throws IFException {
try {
- this.pdfDoc.registerObject(currentStream);
- currentPage.setContents(currentStream);
+ this.pdfDoc.registerObject(generator.getStream());
+ currentPage.setContents(generator.getStream());
PDFAnnotList annots = currentPage.getAnnotations();
if (annots != null) {
this.pdfDoc.addObject(annots);
}
this.pdfDoc.addObject(currentPage);
- this.pdfDoc.output(this.outputStream);
- this.textutil = null;
+ this.generator.flushPDFDoc();
+ this.generator = null;
} catch (IOException ioe) {
throw new IFException("I/O error in endPage()", ioe);
}
}
/** {@inheritDoc} */
- private void saveGraphicsState() {
- //endTextObject();
- currentState.push();
- this.state = this.state.push();
- currentStream.add("q\n");
- }
-
- private void restoreGraphicsState(boolean popState) {
- endTextObject();
- currentStream.add("Q\n");
- if (popState) {
- currentState.pop();
- this.state = this.state.pop();
- }
- }
-
- private void restoreGraphicsState() {
- restoreGraphicsState(true);
- }
-
- /** {@inheritDoc} */
public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect)
throws IFException {
- saveGraphicsState();
- currentStream.add(CTMHelper.toPDFString(transform, true) + " cm\n");
+ generator.saveGraphicsState();
+ generator.add(CTMHelper.toPDFString(transform, true) + " cm\n");
if (clipRect != null) {
StringBuffer sb = new StringBuffer();
sb.append(format(clipRect.x)).append(' ');
sb.append(format(clipRect.y)).append(' ');
sb.append(format(clipRect.width)).append(' ');
sb.append(format(clipRect.height)).append(" re W n\n");
- currentStream.add(sb.toString());
+ generator.add(sb.toString());
}
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
- saveGraphicsState();
- currentStream.add(CTMHelper.toPDFString(transform, true) + " cm\n");
+ public void endViewport() throws IFException {
+ generator.restoreGraphicsState();
}
/** {@inheritDoc} */
- public void endGroup() throws IFException {
- restoreGraphicsState();
+ public void startGroup(AffineTransform transform) throws IFException {
+ generator.saveGraphicsState();
+ generator.add(CTMHelper.toPDFString(transform, true) + " cm\n");
}
/** {@inheritDoc} */
- public void endViewport() throws IFException {
- restoreGraphicsState();
+ public void endGroup() throws IFException {
+ generator.restoreGraphicsState();
}
/** {@inheritDoc} */
- public void startImage(Rectangle rect) throws IFException {
- // TODO Auto-generated method stub
+ public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException {
+ PDFXObject xobject = pdfDoc.getXObject(uri);
+ if (xobject != null) {
+ placeImage(rect, xobject);
+ return;
+ }
+
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
+
+ PDFRenderingContext pdfContext = new PDFRenderingContext(
+ getUserAgent(), generator, currentPage, getFontInfo());
+
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, imageHandlerRegistry.getSupportedFlavors(pdfContext),
+ hints, sessionContext);
+
+ //First check for a dynamically registered handler
+ ImageHandler handler = imageHandlerRegistry.getHandler(pdfContext, img);
+ if (handler == null) {
+ throw new UnsupportedOperationException(
+ "No ImageHandler available for image: "
+ + info + " (" + img.getClass().getName() + ")");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Using ImageHandler: " + handler.getClass().getName());
+ }
+ try {
+ //TODO foreign attributes
+ handler.handleImage(pdfContext, img, rect);
+ } catch (IOException ioe) {
+ ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
+ getUserAgent().getEventBroadcaster());
+ eventProducer.imageWritingError(this, ioe);
+ return;
+ }
+ } catch (ImageException ie) {
+ ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
+ getUserAgent().getEventBroadcaster());
+ eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null);
+ } catch (FileNotFoundException fe) {
+ ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
+ getUserAgent().getEventBroadcaster());
+ eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null);
+ } catch (IOException ioe) {
+ ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
+ getUserAgent().getEventBroadcaster());
+ eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null);
+ }
+ // output new data
+ try {
+ generator.flushPDFDoc();
+ } catch (IOException ioe) {
+ throw new IFException("I/O error flushing the PDF document", ioe);
+ }
+ }
+
+ /**
+ * Places a previously registered image at a certain place on the page.
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param w width for image
+ * @param h height for image
+ * @param xobj the image XObject
+ */
+ private void placeImage(Rectangle rect, PDFXObject xobj) {
+ generator.saveGraphicsState();
+ generator.add(format(rect.width) + " 0 0 "
+ + format(-rect.height) + " "
+ + format(rect.x) + " "
+ + format(rect.y + rect.height )
+ + " cm " + xobj.getName() + " Do\n");
+ generator.restoreGraphicsState();
}
+
/** {@inheritDoc} */
- public void drawImage(String uri, Rectangle rect) throws IFException {
+ public void startImage(Rectangle rect) throws IFException {
// TODO Auto-generated method stub
}
@@ -348,14 +388,6 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
}
- private static String toString(Paint paint) {
- if (paint instanceof Color) {
- return ColorUtil.colorToString((Color)paint);
- } else {
- throw new UnsupportedOperationException("Paint not supported: " + paint);
- }
- }
-
/**
* Formats a integer value (normally coordinates in millipoints) to a String.
* @param value the value (in millipoints)
@@ -365,37 +397,16 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
return PDFNumber.doubleOut(value / 1000f);
}
- /**
- * Establishes a new foreground or fill color.
- * @param col the color to apply (null skips this operation)
- * @param fill true to set the fill color, false for the foreground color
- */
- private void updateColor(Color col, boolean fill) {
- if (col == null) {
- return;
- }
- boolean update = false;
- if (fill) {
- update = currentState.setBackColor(col);
- } else {
- update = currentState.setColor(col);
- }
-
- if (update) {
- pdfUtil.setColor(col, fill, this.currentStream);
- }
- }
-
/** {@inheritDoc} */
public void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException {
if (fill == null && stroke == null) {
return;
}
- endTextObject();
+ generator.endTextObject();
if (rect.width != 0 && rect.height != 0) {
if (fill != null) {
if (fill instanceof Color) {
- updateColor((Color)fill, true);
+ generator.updateColor((Color)fill, true, null);
} else {
throw new UnsupportedOperationException("Non-Color paints NYI");
}
@@ -415,21 +426,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
sb.append(" S");
}
sb.append('\n');
- currentStream.add(sb.toString());
- }
- }
-
- /** Indicates the beginning of a text object. */
- private void beginTextObject() {
- if (!textutil.isInTextObject()) {
- textutil.beginTextObject();
- }
- }
-
- /** Indicates the end of a text object. */
- private void endTextObject() {
- if (textutil.isInTextObject()) {
- textutil.endTextObject();
+ generator.add(sb.toString());
}
}
@@ -447,14 +444,14 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
/** {@inheritDoc} */
public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException {
//Note: dy is currently ignored
- beginTextObject();
+ generator.beginTextObject();
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
String fontKey = fontInfo.getInternalFontKey(triplet);
int sizeMillipoints = state.getFontSize();
float fontSize = sizeMillipoints / 1000f;
- updateColor(state.getTextColor(), true);
+ generator.updateColor(state.getTextColor(), true, null);
// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontKey);
@@ -465,6 +462,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter {
Font font = fontInfo.getFontInstance(triplet, sizeMillipoints);
String fontName = font.getFontName();
+ PDFTextUtil textutil = generator.getTextUtil();
textutil.updateTf(fontKey, fontSize, tf.isMultiByte());
textutil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f));
diff --git a/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java b/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java
index b3fe42824..f1fbe48fd 100644
--- a/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java
+++ b/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java
@@ -30,7 +30,8 @@ import org.apache.fop.render.intermediate.IFPainterConfigurator;
*/
public class PDFPainterMaker extends AbstractIFPainterMaker {
- private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF};
+ //TODO Revert to normal MIME after stabilization!
+ private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF + ";mode=painter"};
/** {@inheritDoc} */
public IFPainter makePainter(FOUserAgent ua) {
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index cfe8b9902..4ce3dfbd9 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -76,7 +76,6 @@ import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFFactory;
-import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFGoTo;
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFLink;
@@ -86,7 +85,6 @@ import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
-import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFTextUtil;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.pdf.PDFXObject;
@@ -167,10 +165,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
*/
protected PDFResources pdfResources;
- /**
- * the current stream to add PDF commands to
- */
- protected PDFStream currentStream;
+ /** The current content generator to produce PDF commands with */
+ protected PDFContentGenerator generator;
/**
* the current annotation list to add annotations to
@@ -187,11 +183,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
*/
protected String currentPageRef;
- /** drawing state */
- protected PDFState currentState = null;
-
- /** Text generation utility holding the current font status */
- protected PDFTextUtil textutil;
/** page height */
protected int pageHeight;
@@ -214,6 +205,14 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
return this.pdfUtil;
}
+ PDFContentGenerator getGenerator() {
+ return this.generator;
+ }
+
+ PDFState getState() {
+ return getGenerator().getState();
+ }
+
/** {@inheritDoc} */
public void startRenderer(OutputStream stream) throws IOException {
if (userAgent == null) {
@@ -258,11 +257,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
pageReferences.clear();
//pvReferences.clear();
pdfResources = null;
- currentStream = null;
+ this.generator = null;
+ //currentStream = null;
currentContext = null;
currentPage = null;
- currentState = null;
- this.textutil = null;
+ //currentState = null;
+ //this.textutil = null;
idPositions.clear();
idGoTos.clear();
@@ -354,48 +354,24 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
return new PDFGraphics2DAdapter(this);
}
- /**
- * writes out a comment.
- * @param text text for the comment
- */
- protected void comment(String text) {
- if (WRITE_COMMENTS) {
- currentStream.add("% " + text + "\n");
- }
- }
-
/** {@inheritDoc} */
protected void saveGraphicsState() {
- endTextObject();
- currentState.push();
- currentStream.add("q\n");
- }
-
- private void restoreGraphicsState(boolean popState) {
- endTextObject();
- currentStream.add("Q\n");
- if (popState) {
- currentState.pop();
- }
+ generator.saveGraphicsState();
}
/** {@inheritDoc} */
protected void restoreGraphicsState() {
- restoreGraphicsState(true);
+ generator.restoreGraphicsState();
}
/** Indicates the beginning of a text object. */
protected void beginTextObject() {
- if (!textutil.isInTextObject()) {
- textutil.beginTextObject();
- }
+ generator.beginTextObject();
}
/** Indicates the end of a text object. */
protected void endTextObject() {
- if (textutil.isInTextObject()) {
- textutil.endTextObject();
- }
+ generator.endTextObject();
}
/**
@@ -483,6 +459,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
double h = bounds.getHeight();
pageHeight = (int) h;
+ this.generator = new PDFContentGenerator(this.pdfDoc, this.ostream, this.currentPage);
+ /*
currentStream = this.pdfDoc.getFactory()
.makeStream(PDFFilterList.CONTENT_FILTER, false);
this.textutil = new PDFTextUtil() {
@@ -492,31 +470,37 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
};
currentState = new PDFState();
+ */
// Transform the PDF's default coordinate system (0,0 at lower left) to the PDFRenderer's
AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
pageHeight / 1000f);
+ generator.concatenate(basicPageTransform);
+ /*
currentState.concatenate(basicPageTransform);
currentStream.add(CTMHelper.toPDFString(basicPageTransform, false) + " cm\n");
+ */
super.renderPage(page);
- this.pdfDoc.registerObject(currentStream);
- currentPage.setContents(currentStream);
+ this.pdfDoc.registerObject(generator.getStream());
+ currentPage.setContents(generator.getStream());
PDFAnnotList annots = currentPage.getAnnotations();
if (annots != null) {
this.pdfDoc.addObject(annots);
}
this.pdfDoc.addObject(currentPage);
- this.pdfDoc.output(ostream);
- this.textutil = null;
+ this.generator.flushPDFDoc();
+ this.generator = null;
}
/** {@inheritDoc} */
protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
saveGraphicsState();
// Set the given CTM in the graphics state
+ /*
currentState.concatenate(
new AffineTransform(CTMHelper.toPDFArray(ctm)));
+ */
if (clippingRect != null) {
clipRect((float)clippingRect.getX() / 1000f,
@@ -525,7 +509,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
(float)clippingRect.getHeight() / 1000f);
}
// multiply with current CTM
- currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
+ generator.concatenate(new AffineTransform(CTMHelper.toPDFArray(ctm)));
+ //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
}
/** {@inheritDoc} */
@@ -535,10 +520,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
/** {@inheritDoc} */
protected void concatenateTransformationMatrix(AffineTransform at) {
+ generator.concatenate(at);
+ /*
if (!at.isIdentity()) {
currentState.concatenate(at);
currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n");
- }
+ }*/
}
/**
@@ -562,7 +549,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
}
switch (style) {
case Constants.EN_DASHED:
- setColor(col, false, null);
+ generator.setColor(col, false);
if (horz) {
float unit = Math.abs(2 * h);
int rep = (int)(w / unit);
@@ -570,10 +557,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
rep++;
}
unit = w / rep;
- currentStream.add("[" + format(unit) + "] 0 d ");
- currentStream.add(format(h) + " w\n");
+ generator.add("[" + format(unit) + "] 0 d ");
+ generator.add(format(h) + " w\n");
float ym = y1 + (h / 2);
- currentStream.add(format(x1) + " " + format(ym) + " m "
+ generator.add(format(x1) + " " + format(ym) + " m "
+ format(x2) + " " + format(ym) + " l S\n");
} else {
float unit = Math.abs(2 * w);
@@ -582,16 +569,16 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
rep++;
}
unit = h / rep;
- currentStream.add("[" + format(unit) + "] 0 d ");
- currentStream.add(format(w) + " w\n");
+ generator.add("[" + format(unit) + "] 0 d ");
+ generator.add(format(w) + " w\n");
float xm = x1 + (w / 2);
- currentStream.add(format(xm) + " " + format(y1) + " m "
+ generator.add(format(xm) + " " + format(y1) + " m "
+ format(xm) + " " + format(y2) + " l S\n");
}
break;
case Constants.EN_DOTTED:
- setColor(col, false, null);
- currentStream.add("1 J ");
+ generator.setColor(col, false);
+ generator.add("1 J ");
if (horz) {
float unit = Math.abs(2 * h);
int rep = (int)(w / unit);
@@ -599,10 +586,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
rep++;
}
unit = w / rep;
- currentStream.add("[0 " + format(unit) + "] 0 d ");
- currentStream.add(format(h) + " w\n");
+ generator.add("[0 " + format(unit) + "] 0 d ");
+ generator.add(format(h) + " w\n");
float ym = y1 + (h / 2);
- currentStream.add(format(x1) + " " + format(ym) + " m "
+ generator.add(format(x1) + " " + format(ym) + " m "
+ format(x2) + " " + format(ym) + " l S\n");
} else {
float unit = Math.abs(2 * w);
@@ -611,33 +598,33 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
rep++;
}
unit = h / rep;
- currentStream.add("[0 " + format(unit) + " ] 0 d ");
- currentStream.add(format(w) + " w\n");
+ generator.add("[0 " + format(unit) + " ] 0 d ");
+ generator.add(format(w) + " w\n");
float xm = x1 + (w / 2);
- currentStream.add(format(xm) + " " + format(y1) + " m "
+ generator.add(format(xm) + " " + format(y1) + " m "
+ format(xm) + " " + format(y2) + " l S\n");
}
break;
case Constants.EN_DOUBLE:
- setColor(col, false, null);
- currentStream.add("[] 0 d ");
+ generator.setColor(col, false);
+ generator.add("[] 0 d ");
if (horz) {
float h3 = h / 3;
- currentStream.add(format(h3) + " w\n");
+ generator.add(format(h3) + " w\n");
float ym1 = y1 + (h3 / 2);
float ym2 = ym1 + h3 + h3;
- currentStream.add(format(x1) + " " + format(ym1) + " m "
+ generator.add(format(x1) + " " + format(ym1) + " m "
+ format(x2) + " " + format(ym1) + " l S\n");
- currentStream.add(format(x1) + " " + format(ym2) + " m "
+ generator.add(format(x1) + " " + format(ym2) + " m "
+ format(x2) + " " + format(ym2) + " l S\n");
} else {
float w3 = w / 3;
- currentStream.add(format(w3) + " w\n");
+ generator.add(format(w3) + " w\n");
float xm1 = x1 + (w3 / 2);
float xm2 = xm1 + w3 + w3;
- currentStream.add(format(xm1) + " " + format(y1) + " m "
+ generator.add(format(xm1) + " " + format(y1) + " m "
+ format(xm1) + " " + format(y2) + " l S\n");
- currentStream.add(format(xm2) + " " + format(y1) + " m "
+ generator.add(format(xm2) + " " + format(y1) + " m "
+ format(xm2) + " " + format(y2) + " l S\n");
}
break;
@@ -645,36 +632,36 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
case Constants.EN_RIDGE:
{
float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f);
- currentStream.add("[] 0 d ");
+ generator.add("[] 0 d ");
if (horz) {
Color uppercol = lightenColor(col, -colFactor);
Color lowercol = lightenColor(col, colFactor);
float h3 = h / 3;
- currentStream.add(format(h3) + " w\n");
+ generator.add(format(h3) + " w\n");
float ym1 = y1 + (h3 / 2);
- setColor(uppercol, false, null);
- currentStream.add(format(x1) + " " + format(ym1) + " m "
+ generator.setColor(uppercol, false);
+ generator.add(format(x1) + " " + format(ym1) + " m "
+ format(x2) + " " + format(ym1) + " l S\n");
- setColor(col, false, null);
- currentStream.add(format(x1) + " " + format(ym1 + h3) + " m "
+ generator.setColor(col, false);
+ generator.add(format(x1) + " " + format(ym1 + h3) + " m "
+ format(x2) + " " + format(ym1 + h3) + " l S\n");
- setColor(lowercol, false, null);
- currentStream.add(format(x1) + " " + format(ym1 + h3 + h3) + " m "
+ generator.setColor(lowercol, false);
+ generator.add(format(x1) + " " + format(ym1 + h3 + h3) + " m "
+ format(x2) + " " + format(ym1 + h3 + h3) + " l S\n");
} else {
Color leftcol = lightenColor(col, -colFactor);
Color rightcol = lightenColor(col, colFactor);
float w3 = w / 3;
- currentStream.add(format(w3) + " w\n");
+ generator.add(format(w3) + " w\n");
float xm1 = x1 + (w3 / 2);
- setColor(leftcol, false, null);
- currentStream.add(format(xm1) + " " + format(y1) + " m "
+ generator.setColor(leftcol, false);
+ generator.add(format(xm1) + " " + format(y1) + " m "
+ format(xm1) + " " + format(y2) + " l S\n");
- setColor(col, false, null);
- currentStream.add(format(xm1 + w3) + " " + format(y1) + " m "
+ generator.setColor(col, false);
+ generator.add(format(xm1 + w3) + " " + format(y1) + " m "
+ format(xm1 + w3) + " " + format(y2) + " l S\n");
- setColor(rightcol, false, null);
- currentStream.add(format(xm1 + w3 + w3) + " " + format(y1) + " m "
+ generator.setColor(rightcol, false);
+ generator.add(format(xm1 + w3 + w3) + " " + format(y1) + " m "
+ format(xm1 + w3 + w3) + " " + format(y2) + " l S\n");
}
break;
@@ -683,21 +670,21 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
case Constants.EN_OUTSET:
{
float colFactor = (style == EN_OUTSET ? 0.4f : -0.4f);
- currentStream.add("[] 0 d ");
+ generator.add("[] 0 d ");
Color c = col;
if (horz) {
c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor);
- currentStream.add(format(h) + " w\n");
+ generator.add(format(h) + " w\n");
float ym1 = y1 + (h / 2);
- setColor(c, false, null);
- currentStream.add(format(x1) + " " + format(ym1) + " m "
+ generator.setColor(c, false);
+ generator.add(format(x1) + " " + format(ym1) + " m "
+ format(x2) + " " + format(ym1) + " l S\n");
} else {
c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor);
- currentStream.add(format(w) + " w\n");
+ generator.add(format(w) + " w\n");
float xm1 = x1 + (w / 2);
- setColor(c, false, null);
- currentStream.add(format(xm1) + " " + format(y1) + " m "
+ generator.setColor(c, false);
+ generator.add(format(xm1) + " " + format(y1) + " m "
+ format(xm1) + " " + format(y2) + " l S\n");
}
break;
@@ -705,36 +692,25 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
case Constants.EN_HIDDEN:
break;
default:
- setColor(col, false, null);
- currentStream.add("[] 0 d ");
+ generator.setColor(col, false);
+ generator.add("[] 0 d ");
if (horz) {
- currentStream.add(format(h) + " w\n");
+ generator.add(format(h) + " w\n");
float ym = y1 + (h / 2);
- currentStream.add(format(x1) + " " + format(ym) + " m "
+ generator.add(format(x1) + " " + format(ym) + " m "
+ format(x2) + " " + format(ym) + " l S\n");
} else {
- currentStream.add(format(w) + " w\n");
+ generator.add(format(w) + " w\n");
float xm = x1 + (w / 2);
- currentStream.add(format(xm) + " " + format(y1) + " m "
+ generator.add(format(xm) + " " + format(y1) + " m "
+ format(xm) + " " + format(y2) + " l S\n");
}
}
}
- /**
- * Sets the current line width in points.
- * @param width line width in points
- */
- private void updateLineWidth(float width) {
- if (currentState.setLineWidth(width)) {
- //Only write if value has changed WRT the current line width
- currentStream.add(format(width) + " w\n");
- }
- }
-
/** {@inheritDoc} */
protected void clipRect(float x, float y, float width, float height) {
- currentStream.add(format(x) + " " + format(y) + " "
+ generator.add(format(x) + " " + format(y) + " "
+ format(width) + " " + format(height) + " re ");
clip();
}
@@ -743,8 +719,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* Clip an area.
*/
protected void clip() {
- currentStream.add("W\n");
- currentStream.add("n\n");
+ generator.add("W\n" + "n\n");
}
/**
@@ -753,7 +728,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* @param y y coordinate
*/
protected void moveTo(float x, float y) {
- currentStream.add(format(x) + " " + format(y) + " m ");
+ generator.add(format(x) + " " + format(y) + " m ");
}
/**
@@ -763,7 +738,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* @param y y coordinate
*/
protected void lineTo(float x, float y) {
- currentStream.add(format(x) + " " + format(y) + " l ");
+ generator.add(format(x) + " " + format(y) + " l ");
}
/**
@@ -771,7 +746,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* the current point to the starting point of the subpath.
*/
protected void closePath() {
- currentStream.add("h ");
+ generator.add("h ");
}
/**
@@ -779,7 +754,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
*/
protected void fillRect(float x, float y, float w, float h) {
if (w != 0 && h != 0) {
- currentStream.add(format(x) + " " + format(y) + " "
+ generator.add(format(x) + " " + format(y) + " "
+ format(w) + " " + format(h) + " re f\n");
}
}
@@ -793,8 +768,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* @param endy the y end position
*/
private void drawLine(float startx, float starty, float endx, float endy) {
- currentStream.add(format(startx) + " " + format(starty) + " m ");
- currentStream.add(format(endx) + " " + format(endy) + " l S\n");
+ generator.add(format(startx) + " " + format(starty) + " m ");
+ generator.add(format(endx) + " " + format(endy) + " l S\n");
}
/**
@@ -805,15 +780,15 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
List breakOutList = new java.util.ArrayList();
PDFState.Data data;
while (true) {
- data = currentState.getData();
- if (currentState.pop() == null) {
+ data = getState().getData();
+ if (getState().pop() == null) {
break;
}
if (breakOutList.size() == 0) {
- comment("------ break out!");
+ generator.comment("------ break out!");
}
breakOutList.add(0, data); //Insert because of stack-popping
- restoreGraphicsState(false);
+ generator.restoreGraphicsState();
}
return breakOutList;
}
@@ -823,7 +798,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* @param breakOutList the state stack to restore.
*/
protected void restoreStateStackAfterBreakOut(List breakOutList) {
- comment("------ restoring context after break-out...");
+ generator.comment("------ restoring context after break-out...");
PDFState.Data data;
Iterator i = breakOutList.iterator();
while (i.hasNext()) {
@@ -835,7 +810,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
//Left out for now because all this painting stuff is very
//inconsistent. Some values go over PDFState, some don't.
}
- comment("------ done.");
+ generator.comment("------ done.");
}
/**
@@ -967,7 +942,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
*/
protected void saveAbsolutePosition(String id, int relativeIPP, int relativeBPP) {
saveAbsolutePosition(id, currentPageRef,
- relativeIPP, relativeBPP, currentState.getTransform());
+ relativeIPP, relativeBPP, getState().getTransform());
}
/**
@@ -991,8 +966,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
bpp += currentBPPosition;
}
AffineTransform tf = positioning == Block.FIXED
- ? currentState.getBaseTransform()
- : currentState.getTransform();
+ ? getState().getBaseTransform()
+ : getState().getTransform();
saveAbsolutePosition(id, currentPageRef, ipp, bpp, tf);
}
}
@@ -1055,7 +1030,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
int bpp = currentBPPosition + ip.getOffset();
ipRect = new Rectangle2D.Float(ipp / 1000f, bpp / 1000f,
ip.getIPD() / 1000f, ip.getBPD() / 1000f);
- AffineTransform transform = currentState.getTransform();
+ AffineTransform transform = getState().getTransform();
ipRect = transform.createTransformedShape(ipRect).getBounds2D();
factory = pdfDoc.getFactory();
@@ -1131,6 +1106,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontName);
+ PDFTextUtil textutil = generator.getTextUtil();
textutil.updateTf(fontName, size / 1000f, tf.isMultiByte());
@@ -1174,7 +1150,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
if (tws != 0) {
float adjust = tws / (font.getFontSize() / 1000f);
- textutil.adjustGlyphTJ(adjust);
+ generator.getTextUtil().adjustGlyphTJ(adjust);
}
}
@@ -1213,6 +1189,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
if (tf instanceof SingleByteFont) {
singleByteFont = (SingleByteFont)tf;
}
+ PDFTextUtil textutil = generator.getTextUtil();
int l = s.length();
@@ -1258,48 +1235,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
}
}
- /**
- * Establishes a new foreground or fill color. In contrast to updateColor
- * this method does not check the PDFState for optimization possibilities.
- * @param col the color to apply
- * @param fill true to set the fill color, false for the foreground color
- * @param pdf StringBuffer to write the PDF code to, if null, the code is
- * written to the current stream.
- */
- protected void setColor(Color col, boolean fill, StringBuffer pdf) {
- if (pdf != null) {
- pdfUtil.setColor(col, fill, pdf);
- } else {
- pdfUtil.setColor(col, fill, this.currentStream);
- }
- }
-
- /**
- * Establishes a new foreground or fill color.
- * @param col the color to apply (null skips this operation)
- * @param fill true to set the fill color, false for the foreground color
- * @param pdf StringBuffer to write the PDF code to, if null, the code is
- * written to the current stream.
- */
- private void updateColor(Color col, boolean fill, StringBuffer pdf) {
- if (col == null) {
- return;
- }
- boolean update = false;
- if (fill) {
- update = currentState.setBackColor(col);
- } else {
- update = currentState.setColor(col);
- }
-
- if (update) {
- setColor(col, fill, pdf);
- }
- }
-
/** {@inheritDoc} */
protected void updateColor(Color col, boolean fill) {
- updateColor(col, fill, null);
+ generator.updateColor(col, fill, null);
}
/** {@inheritDoc} */
@@ -1398,7 +1336,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
// output new data
try {
- this.pdfDoc.output(ostream);
+ this.generator.flushPDFDoc();
} catch (IOException ioe) {
// ioexception will be caught later
}
@@ -1414,7 +1352,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
*/
public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
saveGraphicsState();
- currentStream.add(format(w) + " 0 0 "
+ generator.add(format(w) + " 0 0 "
+ format(-h) + " "
+ format(currentIPPosition / 1000f + x) + " "
+ format(currentBPPosition / 1000f + h + y)
@@ -1429,12 +1367,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
x, y, width, height, foreignAttributes);
context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc);
context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream);
- context.setProperty(PDFRendererContextConstants.PDF_STATE, currentState);
+ context.setProperty(PDFRendererContextConstants.PDF_STATE, getState());
context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage);
context.setProperty(PDFRendererContextConstants.PDF_CONTEXT,
currentContext == null ? currentPage : currentContext);
context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext);
- context.setProperty(PDFRendererContextConstants.PDF_STREAM, currentStream);
+ context.setProperty(PDFRendererContextConstants.PDF_STREAM, generator.getStream());
context.setProperty(PDFRendererContextConstants.PDF_FONT_INFO, fontInfo);
context.setProperty(PDFRendererContextConstants.PDF_FONT_NAME, "");
context.setProperty(PDFRendererContextConstants.PDF_FONT_SIZE, new Integer(0));
@@ -1449,7 +1387,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
public void renderLeader(Leader area) {
renderInlineAreaBackAndBorders(area);
- currentState.push();
+ getState().push();
saveGraphicsState();
int style = area.getRuleStyle();
float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f;
@@ -1470,7 +1408,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
clipRect(startx, starty, endx - startx, ruleThickness);
//This displaces the dots to the right by half a dot's width
//TODO There's room for improvement here
- currentStream.add("1 0 0 1 " + format(ruleThickness / 2) + " 0 cm\n");
+ generator.add("1 0 0 1 " + format(ruleThickness / 2) + " 0 cm\n");
drawBorderLine(startx, starty, endx, starty + ruleThickness,
true, true, style, col);
break;
@@ -1478,36 +1416,36 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
case EN_RIDGE:
float half = area.getRuleThickness() / 2000f;
- setColor(lightenColor(col, 0.6f), true, null);
- currentStream.add(format(startx) + " " + format(starty) + " m\n");
- currentStream.add(format(endx) + " " + format(starty) + " l\n");
- currentStream.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
- currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
- currentStream.add("h\n");
- currentStream.add("f\n");
- setColor(col, true, null);
+ generator.setColor(lightenColor(col, 0.6f), true);
+ generator.add(format(startx) + " " + format(starty) + " m\n");
+ generator.add(format(endx) + " " + format(starty) + " l\n");
+ generator.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
+ generator.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
+ generator.add("h\n");
+ generator.add("f\n");
+ generator.setColor(col, true);
if (style == EN_GROOVE) {
- currentStream.add(format(startx) + " " + format(starty) + " m\n");
- currentStream.add(format(endx) + " " + format(starty) + " l\n");
- currentStream.add(format(endx) + " " + format(starty + half) + " l\n");
- currentStream.add(format(startx + half) + " " + format(starty + half) + " l\n");
- currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
+ generator.add(format(startx) + " " + format(starty) + " m\n");
+ generator.add(format(endx) + " " + format(starty) + " l\n");
+ generator.add(format(endx) + " " + format(starty + half) + " l\n");
+ generator.add(format(startx + half) + " " + format(starty + half) + " l\n");
+ generator.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
} else {
- currentStream.add(format(endx) + " " + format(starty) + " m\n");
- currentStream.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
- currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
- currentStream.add(format(startx) + " " + format(starty + half) + " l\n");
- currentStream.add(format(endx - half) + " " + format(starty + half) + " l\n");
+ generator.add(format(endx) + " " + format(starty) + " m\n");
+ generator.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
+ generator.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
+ generator.add(format(startx) + " " + format(starty + half) + " l\n");
+ generator.add(format(endx - half) + " " + format(starty + half) + " l\n");
}
- currentStream.add("h\n");
- currentStream.add("f\n");
+ generator.add("h\n");
+ generator.add("f\n");
break;
default:
throw new UnsupportedOperationException("rule style not supported");
}
restoreGraphicsState();
- currentState.pop();
+ getState().pop();
beginTextObject();
super.renderLeader(area);
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java
new file mode 100644
index 000000000..98b0c8203
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java
@@ -0,0 +1,82 @@
+/*
+ * 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.pdf;
+
+import org.apache.xmlgraphics.util.MimeConstants;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.pdf.PDFPage;
+import org.apache.fop.render.AbstractRenderingContext;
+
+/**
+ * Rendering context for PDF production.
+ */
+public class PDFRenderingContext extends AbstractRenderingContext {
+
+ private PDFContentGenerator generator;
+ private FontInfo fontInfo;
+ private PDFPage page;
+
+ /**
+ * Main constructor.
+ * @param userAgent the user agent
+ * @param generator the PDF content generator
+ * @param page the current PDF page
+ * @param fontInfo the font list
+ */
+ public PDFRenderingContext(FOUserAgent userAgent,
+ PDFContentGenerator generator, PDFPage page, FontInfo fontInfo) {
+ super(userAgent);
+ this.generator = generator;
+ this.page = page;
+ this.fontInfo = fontInfo;
+ }
+
+ /** {@inheritDoc} */
+ public String getMimeType() {
+ return MimeConstants.MIME_PDF;
+ }
+
+ /**
+ * Returns the PDF content generator.
+ * @return the PDF content generator
+ */
+ public PDFContentGenerator getGenerator() {
+ return this.generator;
+ }
+
+ /**
+ * Returns the current PDF page.
+ * @return the PDF page
+ */
+ public PDFPage getPage() {
+ return this.page;
+ }
+
+ /**
+ * Returns the font list.
+ * @return the font list
+ */
+ public FontInfo getFontInfo() {
+ return this.fontInfo;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
index adc3ff771..e44edf8af 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -19,7 +19,6 @@
package org.apache.fop.render.pdf;
-import java.awt.Color;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.io.InputStream;
@@ -41,7 +40,6 @@ import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAMode;
-import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
@@ -54,7 +52,6 @@ import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPageLabels;
-import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.util.ColorProfileUtil;
@@ -410,30 +407,4 @@ class PDFRenderingUtil implements PDFConfigurationConstants {
nums.put(pageIndex, dict);
}
- /**
- * Establishes a new foreground or fill color. In contrast to updateColor
- * this method does not check the PDFState for optimization possibilities.
- * @param col the color to apply
- * @param fill true to set the fill color, false for the foreground color
- * @param pdf StringBuffer to write the PDF code to
- */
- public void setColor(Color col, boolean fill, StringBuffer pdf) {
- assert pdf != null;
- PDFColor color = new PDFColor(this.pdfDoc, col);
- pdf.append(color.getColorSpaceOut(fill));
- }
-
- /**
- * Establishes a new foreground or fill color.
- * @param col the color to apply
- * @param fill true to set the fill color, false for the foreground color
- * @param stream the PDFStream to write the PDF code to
- */
- public void setColor(Color col, boolean fill, PDFStream stream) {
- assert stream != null;
- PDFColor color = new PDFColor(this.pdfDoc, col);
- stream.add(color.getColorSpaceOut(fill));
- }
-
-
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
index 864a82517..11d9b1c3f 100644
--- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
@@ -44,8 +44,6 @@ import org.apache.fop.fonts.FontInfo;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResourceContext;
-import org.apache.fop.pdf.PDFState;
-import org.apache.fop.pdf.PDFStream;
import org.apache.fop.render.AbstractGenericSVGHandler;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
@@ -78,10 +76,10 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
PDFInfo pdfi = new PDFInfo();
pdfi.pdfDoc = (PDFDocument)context.getProperty(PDF_DOCUMENT);
pdfi.outputStream = (OutputStream)context.getProperty(OUTPUT_STREAM);
- pdfi.pdfState = (PDFState)context.getProperty(PDF_STATE);
+ //pdfi.pdfState = (PDFState)context.getProperty(PDF_STATE);
pdfi.pdfPage = (PDFPage)context.getProperty(PDF_PAGE);
pdfi.pdfContext = (PDFResourceContext)context.getProperty(PDF_CONTEXT);
- pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM);
+ //pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM);
pdfi.width = ((Integer)context.getProperty(WIDTH)).intValue();
pdfi.height = ((Integer)context.getProperty(HEIGHT)).intValue();
pdfi.fi = (FontInfo)context.getProperty(PDF_FONT_INFO);
@@ -108,13 +106,13 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
/** see OUTPUT_STREAM */
public OutputStream outputStream;
/** see PDF_STATE */
- public PDFState pdfState;
+ //public PDFState pdfState;
/** see PDF_PAGE */
public PDFPage pdfPage;
/** see PDF_CONTEXT */
public PDFResourceContext pdfContext;
/** see PDF_STREAM */
- public PDFStream currentStream;
+ //public PDFStream currentStream;
/** see PDF_WIDTH */
public int width;
/** see PDF_HEIGHT */
@@ -216,14 +214,15 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
* Note: To have the svg overlay (under) a text area then use
* an fo:block-container
*/
- pdfInfo.currentStream.add("%SVG setup\n");
- renderer.saveGraphicsState();
- renderer.setColor(Color.black, false, null);
- renderer.setColor(Color.black, true, null);
+ PDFContentGenerator generator = renderer.getGenerator();
+ generator.comment("SVG setup");
+ generator.saveGraphicsState();
+ generator.setColor(Color.black, false);
+ generator.setColor(Color.black, true);
if (!scaling.isIdentity()) {
- pdfInfo.currentStream.add("%viewbox\n");
- pdfInfo.currentStream.add(CTMHelper.toPDFString(scaling, false) + " cm\n");
+ generator.comment("viewbox");
+ generator.add(CTMHelper.toPDFString(scaling, false) + " cm\n");
}
//SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
@@ -238,38 +237,38 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
if (!resolutionScaling.isIdentity()) {
- pdfInfo.currentStream.add("%resolution scaling for " + uaResolution
+ generator.comment("resolution scaling for " + uaResolution
+ " -> " + deviceResolution + "\n");
- pdfInfo.currentStream.add(
+ generator.add(
CTMHelper.toPDFString(resolutionScaling, false) + " cm\n");
graphics.scale(1 / s, 1 / s);
}
- pdfInfo.currentStream.add("%SVG start\n");
+ generator.comment("SVG start");
//Save state and update coordinate system for the SVG image
- pdfInfo.pdfState.push();
- pdfInfo.pdfState.concatenate(imageTransform);
+ generator.getState().push();
+ generator.getState().concatenate(imageTransform);
//Now that we have the complete transformation matrix for the image, we can update the
//transformation matrix for the AElementBridge.
PDFAElementBridge aBridge = (PDFAElementBridge)ctx.getBridge(
SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG);
- aBridge.getCurrentTransform().setTransform(pdfInfo.pdfState.getTransform());
+ aBridge.getCurrentTransform().setTransform(generator.getState().getTransform());
- graphics.setPDFState(pdfInfo.pdfState);
+ graphics.setPDFState(generator.getState());
graphics.setOutputStream(pdfInfo.outputStream);
try {
root.paint(graphics);
- pdfInfo.currentStream.add(graphics.getString());
+ generator.add(graphics.getString());
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgRenderingError(this, e, getDocumentURI(doc));
}
- pdfInfo.pdfState.pop();
- renderer.restoreGraphicsState();
- pdfInfo.currentStream.add("%SVG end\n");
+ generator.getState().pop();
+ generator.restoreGraphicsState();
+ generator.comment("SVG end");
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
index ca2245a12..0b2f0a45f 100644
--- a/src/java/org/apache/fop/svg/PDFGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -440,6 +440,14 @@ public class PDFGraphics2D extends AbstractGraphics2D {
}
PDFXObject xObject = this.pdfDoc.addImage(resourceContext, pdfImage);
+ flushPDFDocument();
+
+ AffineTransform at = new AffineTransform();
+ at.translate(x, y);
+ useXObject(xObject, at, width, height);
+ }
+
+ private void flushPDFDocument() {
if (outputStream != null) {
try {
this.pdfDoc.output(outputStream);
@@ -447,10 +455,6 @@ public class PDFGraphics2D extends AbstractGraphics2D {
// ignore exception, will be thrown again later
}
}
-
- AffineTransform at = new AffineTransform();
- at.translate(x, y);
- useXObject(xObject, at, width, height);
}
/**
@@ -1044,13 +1048,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
this.pdfDoc.addObject(annots);
}
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
+ flushPDFDocument();
return true;
}
@@ -1147,26 +1145,14 @@ public class PDFGraphics2D extends AbstractGraphics2D {
PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
maskRef = xobj.referencePDF();
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
+ flushPDFDocument();
}
BitmapImage fopimg;
fopimg = new BitmapImage("TempImage:" + pctx.toString(),
devW, devH, rgb, maskRef);
fopimg.setTransparent(new PDFColor(255, 255, 255));
imageInfo = pdfDoc.addImage(resourceContext, fopimg);
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
+ flushPDFDocument();
}
currentStream.write("q\n");
@@ -1275,13 +1261,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
ImageRendered imgRend = new ImageRendered(info, img, null);
ImageRenderedAdapter adapter = new ImageRenderedAdapter(imgRend, key);
PDFXObject xObject = pdfDoc.addImage(resourceContext, adapter);
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
+ flushPDFDocument();
return xObject;
}