aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2008-08-06 18:40:47 +0000
committerJeremias Maerki <jeremias@apache.org>2008-08-06 18:40:47 +0000
commit23f712558698be8e5addc8869a89c1719cb90808 (patch)
tree0037ae7af521c376531bb874e23dfea012a2c67f /src/java
parent83abc0b9b18852ffed4533d18f27e1b27df081b5 (diff)
downloadxmlgraphics-fop-23f712558698be8e5addc8869a89c1719cb90808.tar.gz
xmlgraphics-fop-23f712558698be8e5addc8869a89c1719cb90808.zip
Fix for kerning (switched to SVG semantics, now working correctly for both SVG and PDF)
Introduced a special SVG image handler (the successor to PDFSVGHandler). Fixed placement of patterns and links in SVGs for PDF output (the transformations for viewbox and group were not recorded in the state). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@683364 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r--src/java/META-INF/services/org.apache.fop.render.ImageHandler1
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFRenderer.java6
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFContentGenerator.java22
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java200
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java12
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java4
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());