From 8244a3fc897a61644cd65d3e2ea02ffc0dba47f8 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 11 Aug 2006 12:47:35 +0000 Subject: [PATCH] Bugfix: Corrected painting of shading patterns and position of links for SVG images inside FO documents. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@430777 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/pdf/PDFSVGHandler.java | 82 +++++++++++-------- .../org/apache/fop/svg/PDFAElementBridge.java | 5 ++ .../org/apache/fop/svg/PDFGraphics2D.java | 16 +++- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java index bf90191b2..c8f5f71a6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java @@ -26,6 +26,7 @@ import java.awt.Color; import java.awt.geom.AffineTransform; import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGAElement; import org.w3c.dom.svg.SVGDocument; import org.w3c.dom.svg.SVGSVGElement; @@ -39,6 +40,7 @@ import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFStream; import org.apache.fop.pdf.PDFResourceContext; +import org.apache.fop.svg.PDFAElementBridge; import org.apache.fop.svg.PDFBridgeContext; import org.apache.fop.svg.PDFGraphics2D; import org.apache.fop.svg.SVGUserAgent; @@ -55,7 +57,9 @@ import org.apache.avalon.framework.configuration.Configuration; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.ViewBox; +import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.util.SVGConstants; /** * PDF XML handler for SVG (uses Apache Batik). @@ -142,6 +146,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler */ protected void renderSVGDocument(RendererContext context, Document doc) { + PDFRenderer renderer = (PDFRenderer)context.getRenderer(); PDFInfo pdfInfo = getPDFInfo(context); if (pdfInfo.paintAsBitmap) { try { @@ -163,12 +168,18 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler final float uaResolution = context.getUserAgent().getSourceResolution(); SVGUserAgent ua = new SVGUserAgent(25.4f / uaResolution, new AffineTransform()); - GVTBuilder builder = new GVTBuilder(); + //Scale for higher resolution on-the-fly images from Batik + double s = uaResolution / deviceResolution; + AffineTransform resolutionScaling = new AffineTransform(); + resolutionScaling.scale(s, s); - //TODO This AffineTransform here has to be fixed!!! - AffineTransform linkTransform = pdfInfo.pdfState.getTransform(); - linkTransform.translate(xOffset / 1000f, yOffset / 1000f); + //Transformation matrix that establishes the local coordinate system for the SVG graphic + //in relation to PDF's initial coordinate system. + AffineTransform baseTransform = (AffineTransform)renderer.currentBasicTransform.clone(); + baseTransform.concatenate(pdfInfo.pdfState.getTransform()); + GVTBuilder builder = new GVTBuilder(); + //Controls whether text painted by Batik is generated using text or path operations boolean strokeText = false; Configuration cfg = pdfInfo.cfg; @@ -178,11 +189,12 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler BridgeContext ctx = new PDFBridgeContext(ua, (strokeText ? null : pdfInfo.fi), - linkTransform); + new AffineTransform()); GraphicsNode root; try { root = builder.build(ctx, doc); + builder = null; } catch (Exception e) { log.error("svg graphic could not be built: " + e.getMessage(), e); @@ -195,35 +207,36 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler float sx = pdfInfo.width / (float)w; float sy = pdfInfo.height / (float)h; - ctx = null; - builder = null; + //Scaling and translation for the bounding box of the image + AffineTransform scaling = new AffineTransform( + sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f); + + //Finish the baseTransform, now that we know everything + baseTransform.concatenate(scaling); + baseTransform.concatenate(resolutionScaling); + + //Now that we have the full baseTransform, 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(baseTransform); /* * Clip to the svg area. * Note: To have the svg overlay (under) a text area then use * an fo:block-container */ - PDFRenderer renderer = (PDFRenderer)context.getRenderer(); + pdfInfo.currentStream.add("%SVG setup\n"); renderer.saveGraphicsState(); renderer.setColor(Color.black, false, null); renderer.setColor(Color.black, true, null); - // 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. - pdfInfo.currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " " - + yOffset / 1000f + " cm\n"); + + if (!scaling.isIdentity()) { + pdfInfo.currentStream.add("%viewbox\n"); + pdfInfo.currentStream.add(CTMHelper.toPDFString(scaling, false) + " cm\n"); + } SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); - //AffineTransform at = ViewBox.getPreserveAspectRatioTransform( - // svg, w / 1000f, h / 1000f); - AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, - pdfInfo.width / 1000f, pdfInfo.height / 1000f); - /* - if (!at.isIdentity()) { - double[] vals = new double[6]; - at.getMatrix(vals); - pdfInfo.currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n"); - }*/ if (pdfInfo.pdfContext == null) { pdfInfo.pdfContext = pdfInfo.pdfPage; @@ -233,21 +246,18 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler pdfInfo.pdfContext, pdfInfo.pdfPage.referencePDF(), pdfInfo.currentFontName, pdfInfo.currentFontSize); graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); - pdfInfo.pdfState.push(); - AffineTransform transform = new AffineTransform(); - // scale to viewbox - transform.translate(xOffset / 1000f, yOffset / 1000f); - if (deviceResolution != uaResolution) { - //Scale for higher resolution on-the-fly images from Batik - double s = uaResolution / deviceResolution; - at.scale(s, s); - pdfInfo.currentStream.add("" + PDFNumber.doubleOut(s) + " 0 0 " - + PDFNumber.doubleOut(s) + " 0 0 cm\n"); + if (!resolutionScaling.isIdentity()) { + pdfInfo.currentStream.add("%resolution scaling for " + uaResolution + " -> " + deviceResolution + "\n"); + pdfInfo.currentStream.add( + CTMHelper.toPDFString(resolutionScaling, false) + " cm\n"); graphics.scale(1 / s, 1 / s); } + + pdfInfo.currentStream.add("%SVG start\n"); - pdfInfo.pdfState.setTransform(transform); + pdfInfo.pdfState.push(); + pdfInfo.pdfState.setTransform(baseTransform); graphics.setPDFState(pdfInfo.pdfState); graphics.setOutputStream(pdfInfo.outputStream); try { @@ -257,9 +267,9 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler log.error("svg graphic could not be rendered: " + e.getMessage(), e); } - - renderer.restoreGraphicsState(); pdfInfo.pdfState.pop(); + renderer.restoreGraphicsState(); + pdfInfo.currentStream.add("%SVG end\n"); } /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */ diff --git a/src/java/org/apache/fop/svg/PDFAElementBridge.java b/src/java/org/apache/fop/svg/PDFAElementBridge.java index 56576afa5..e9bb8a955 100644 --- a/src/java/org/apache/fop/svg/PDFAElementBridge.java +++ b/src/java/org/apache/fop/svg/PDFAElementBridge.java @@ -51,6 +51,11 @@ public class PDFAElementBridge extends AbstractGraphicsNodeBridge { transform = tf; } + /** @return the transformation matrix for links */ + public AffineTransform getCurrentTransform() { + return this.transform; + } + /** * Returns 'a'. * @return the name of this node diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index af0a0cfaa..0e821975d 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -342,6 +342,16 @@ public class PDFGraphics2D extends AbstractGraphics2D { + PDFNumber.doubleOut(matrix[4], DEC) + " " + PDFNumber.doubleOut(matrix[5], DEC) + " cm\n"); } + + /** + * This is mainly used for shading patterns which use the document-global coordinate system + * instead of the local one. + * @return the transformation matrix that established the basic user space for this document + */ + protected AffineTransform getBaseTransform() { + AffineTransform at = new AffineTransform(graphicsState.getTransform()); + return at; + } /** * This is a pdf specific method used to add a link to the @@ -897,7 +907,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { // Build proper transform from gradient space to page space // ('Patterns' don't get userspace transform). AffineTransform transform; - transform = new AffineTransform(graphicsState.getTransform()); + transform = new AffineTransform(getBaseTransform()); transform.concatenate(getTransform()); transform.concatenate(gp.getTransform()); @@ -973,7 +983,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { } AffineTransform transform; - transform = new AffineTransform(graphicsState.getTransform()); + transform = new AffineTransform(getBaseTransform()); transform.concatenate(getTransform()); transform.concatenate(rgp.getTransform()); @@ -1103,7 +1113,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { bbox.add(new Double(rect.getY())); AffineTransform transform; - transform = new AffineTransform(graphicsState.getTransform()); + transform = new AffineTransform(getBaseTransform()); transform.concatenate(getTransform()); transform.concatenate(pp.getPatternTransform()); -- 2.39.5