diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-08-05 15:31:00 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-08-05 15:31:00 +0000 |
commit | 83abc0b9b18852ffed4533d18f27e1b27df081b5 (patch) | |
tree | 7659b6be4f8f6183f8625a343caed2f7606f6909 /src/java/org/apache/fop/render/pdf | |
parent | 46631569e9ccd7e2a179b0c6d1349fa7451ccc70 (diff) | |
download | xmlgraphics-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/org/apache/fop/render/pdf')
12 files changed, 854 insertions, 382 deletions
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} */ |