diff options
Diffstat (limited to 'src/java')
6 files changed, 226 insertions, 19 deletions
diff --git a/src/java/META-INF/services/org.apache.fop.render.ImageHandler b/src/java/META-INF/services/org.apache.fop.render.ImageHandler index 8f4354630..81accc88a 100644 --- a/src/java/META-INF/services/org.apache.fop.render.ImageHandler +++ b/src/java/META-INF/services/org.apache.fop.render.ImageHandler @@ -2,3 +2,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
+org.apache.fop.render.pdf.PDFImageHandlerSVG
diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index e870a4263..ed25063e5 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -670,14 +670,14 @@ public class IFRenderer extends AbstractPathOrientedRenderer { glyphAdjust -= tls; } curX += font.getCharWidth(ch); - if (letterAdjust != null && i < l - 1) { - glyphAdjust -= letterAdjust[i + 1]; + if (letterAdjust != null && i < l) { + glyphAdjust -= letterAdjust[i]; } float adjust = glyphAdjust / fontSize; if (adjust != 0) { - dx[i] = Math.round(adjust); + dx[i] = Math.round(adjust * -10); if (dx[i] != 0) { hasDX = true; } diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index ba2a20707..8d5b4ccb0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -185,23 +185,27 @@ public class PDFContentGenerator { } /** - * Concatenates the given transformation matrix with the current one. - * @param transform the transformation matrix (in points) + * Converts a transformation matrix from millipoints to points. + * @param transform the transformation matrix (in millipoints) + * @return the converted transformation matrix (in points) */ - public void concatenate(AffineTransform transform) { - concatenate(transform, false); + public AffineTransform toPoints(AffineTransform transform) { + final double[] matrix = new double[6]; + transform.getMatrix(matrix); + //Convert from millipoints to points + matrix[4] /= 1000; + matrix[5] /= 1000; + return new AffineTransform(matrix); } /** * 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 + * @param transform the transformation matrix (in points) */ - public void concatenate(AffineTransform transform, boolean convertMillipoints) { + public void concatenate(AffineTransform transform) { if (!transform.isIdentity()) { currentState.concatenate(transform); - currentStream.add(CTMHelper.toPDFString(transform, convertMillipoints) + " cm\n"); + currentStream.add(CTMHelper.toPDFString(transform, false) + " cm\n"); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java new file mode 100644 index 000000000..975f72c06 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -0,0 +1,200 @@ +/* + * 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.Rectangle; +import java.awt.geom.AffineTransform; +import java.io.IOException; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.util.SVGConstants; +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.image.loader.impl.ImageXMLDOM; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.image.loader.batik.BatikImageFlavors; +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; +import org.apache.fop.svg.PDFAElementBridge; +import org.apache.fop.svg.PDFBridgeContext; +import org.apache.fop.svg.PDFGraphics2D; +import org.apache.fop.svg.SVGEventProducer; +import org.apache.fop.svg.SVGUserAgent; + +/** + * Image Handler implementation which handles SVG images. + */ +public class PDFImageHandlerSVG implements ImageHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(PDFImageHandlerSVG.class); + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + PDFRenderingContext pdfContext = (PDFRenderingContext)context; + PDFContentGenerator generator = pdfContext.getGenerator(); + ImageXMLDOM imageSVG = (ImageXMLDOM)image; + + FOUserAgent userAgent = context.getUserAgent(); + final float deviceResolution = userAgent.getTargetResolution(); + if (log.isDebugEnabled()) { + log.debug("Generating SVG at " + deviceResolution + "dpi."); + } + + final float uaResolution = userAgent.getSourceResolution(); + SVGUserAgent ua = new SVGUserAgent(userAgent, new AffineTransform()); + + //Scale for higher resolution on-the-fly images from Batik + double s = uaResolution / deviceResolution; + AffineTransform resolutionScaling = new AffineTransform(); + resolutionScaling.scale(s, s); + + GVTBuilder builder = new GVTBuilder(); + + //Controls whether text painted by Batik is generated using text or path operations + boolean strokeText = false; + //TODO connect with configuration elsewhere. + + BridgeContext ctx = new PDFBridgeContext(ua, + (strokeText ? null : pdfContext.getFontInfo()), + userAgent.getFactory().getImageManager(), + userAgent.getImageSessionContext(), + new AffineTransform()); + + GraphicsNode root; + try { + root = builder.build(ctx, imageSVG.getDocument()); + builder = null; + } catch (Exception e) { + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI()); + return; + } + // get the 'width' and 'height' attributes of the SVG document + float w = (float)ctx.getDocumentSize().getWidth() * 1000f; + float h = (float)ctx.getDocumentSize().getHeight() * 1000f; + + float sx = pos.width / (float)w; + float sy = pos.height / (float)h; + + //Scaling and translation for the bounding box of the image + AffineTransform scaling = new AffineTransform( + sx, 0, 0, sy, pos.x / 1000f, pos.y / 1000f); + + //Transformation matrix that establishes the local coordinate system for the SVG graphic + //in relation to the current coordinate system + AffineTransform imageTransform = new AffineTransform(); + imageTransform.concatenate(scaling); + imageTransform.concatenate(resolutionScaling); + + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + generator.comment("SVG setup"); + generator.saveGraphicsState(); + generator.setColor(Color.black, false); + generator.setColor(Color.black, true); + + if (!scaling.isIdentity()) { + generator.comment("viewbox"); + generator.add(CTMHelper.toPDFString(scaling, false) + " cm\n"); + } + + //SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); + + PDFGraphics2D graphics = new PDFGraphics2D(true, pdfContext.getFontInfo(), + generator.getDocument(), + generator.getResourceContext(), pdfContext.getPage().referencePDF(), + "", 0); + graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + + if (!resolutionScaling.isIdentity()) { + generator.comment("resolution scaling for " + uaResolution + + " -> " + deviceResolution + "\n"); + generator.add( + CTMHelper.toPDFString(resolutionScaling, false) + " cm\n"); + graphics.scale(1 / s, 1 / s); + } + + generator.comment("SVG start"); + + //Save state and update coordinate system for the SVG image + 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(generator.getState().getTransform()); + + graphics.setPDFState(generator.getState()); + graphics.setOutputStream(generator.getOutputStream()); + try { + root.paint(graphics); + generator.add(graphics.getString()); + } catch (Exception e) { + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI()); + } + generator.getState().pop(); + generator.restoreGraphicsState(); + generator.comment("SVG end"); + } + + /** {@inheritDoc} */ + public int getPriority() { + return 400; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageXMLDOM.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + BatikImageFlavors.SVG_DOM + }; + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + return (image == null + || (image instanceof ImageXMLDOM + && image.getFlavor().isCompatible(BatikImageFlavors.SVG_DOM)) + && 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 5b763b197..8747edcec 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -209,8 +209,8 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { 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); - generator.concatenate(basicPageTransform, true); + size.height / 1000f); + generator.concatenate(basicPageTransform); } /** {@inheritDoc} */ @@ -260,7 +260,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) throws IFException { generator.saveGraphicsState(); - generator.add(CTMHelper.toPDFString(transform, true) + " cm\n"); + generator.concatenate(generator.toPoints(transform)); if (clipRect != null) { StringBuffer sb = new StringBuffer(); sb.append(format(clipRect.x)).append(' '); @@ -279,7 +279,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { /** {@inheritDoc} */ public void startGroup(AffineTransform transform) throws IFException { generator.saveGraphicsState(); - generator.add(CTMHelper.toPDFString(transform, true) + " cm\n"); + generator.concatenate(generator.toPoints(transform)); } /** {@inheritDoc} */ @@ -470,7 +470,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { int dxl = (dx != null ? dx.length : 0); if (dx != null && dxl > 0 && dx[0] != 0) { - textutil.adjustGlyphTJ(dx[0] / fontSize); + textutil.adjustGlyphTJ(dx[0]); } for (int i = 0; i < l; i++) { char orgChar = text.charAt(i); @@ -504,7 +504,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { } if (glyphAdjust != 0) { - textutil.adjustGlyphTJ(glyphAdjust / fontSize); + textutil.adjustGlyphTJ(-glyphAdjust / 10f); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 4ce3dfbd9..fbcf892a0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; @@ -1296,8 +1297,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf info = manager.getImageInfo(uri, sessionContext); Map hints = ImageUtil.getDefaultHints(sessionContext); + ImageFlavor[] supportedFlavors = imageHandlerRegistry.getSupportedFlavors(); org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, imageHandlerRegistry.getSupportedFlavors(), hints, sessionContext); + info, supportedFlavors, hints, sessionContext); //First check for a dynamically registered handler PDFImageHandler handler = imageHandlerRegistry.getHandler(img.getClass()); |