From 3ffb084b33b21958c419cac602ecdf447fb3a059 Mon Sep 17 00:00:00 2001 From: Emmeran Seehuber Date: Sat, 11 Feb 2017 05:59:05 +0100 Subject: [PATCH] #23: PDFBox-Graphics2D based SVG rendering (#66) * #23: Allow drawing on the output device using a Graphics2D. This implements the infrastructure, but does not yet use it to render SVGs. * #23: Use pdfbox-graphics2d to render the SVG. But the positioning is not right yet. --- .../openhtmltopdf/extend/OutputDevice.java | 5 + .../extend/OutputDeviceGraphicsDrawer.java | 17 +++ .../com/openhtmltopdf/extend/SVGDrawer.java | 9 +- .../swing/Java2DOutputDevice.java | 14 +- openhtmltopdf-examples/pom.xml | 5 + .../testcases/TestcaseRunner.java | 38 ++--- .../main/resources/testcases/svg-inline.html | 143 ++++++++++++++++++ openhtmltopdf-pdfbox/pom.xml | 5 + .../pdfboxout/PdfBoxOutputDevice.java | 31 +++- .../pdfboxout/PdfBoxSVGReplacedElement.java | 9 +- .../pdfboxout/PdfContentStreamAdapter.java | 34 ++++- .../svgsupport/BatikSVGDrawer.java | 23 ++- .../PDFGraphics2DOutputDeviceAdapter.java | 29 +--- .../svgsupport/PDFTranscoder.java | 75 ++++++--- 14 files changed, 339 insertions(+), 98 deletions(-) create mode 100644 openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDeviceGraphicsDrawer.java create mode 100644 openhtmltopdf-examples/src/main/resources/testcases/svg-inline.html diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDevice.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDevice.java index 81c09b826..823d8cfc7 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDevice.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDevice.java @@ -111,4 +111,9 @@ public void paintBackground( public boolean isSupportsCMYKColors(); + /** + * Draw something using a Graphics2D at the given rectangle. + */ + public void drawWithGraphics(float x, float y, float width, float height, OutputDeviceGraphicsDrawer renderer); + } diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDeviceGraphicsDrawer.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDeviceGraphicsDrawer.java new file mode 100644 index 000000000..a4807e742 --- /dev/null +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/OutputDeviceGraphicsDrawer.java @@ -0,0 +1,17 @@ +package com.openhtmltopdf.extend; + +import java.awt.*; + +/** + * Render something on a Graphics2D on the OutputDevice. + * + * @FunctionalInterface + */ +public interface OutputDeviceGraphicsDrawer { + + /** + * Draw something using the given graphics. For PDFs it will be converted to vector drawings. + * @param graphics2D the graphics you can use to draw + */ + public void render(Graphics2D graphics2D); +} diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java index 24c0373db..c2ffbf502 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java @@ -1,15 +1,14 @@ package com.openhtmltopdf.extend; -import java.util.List; - -import org.w3c.dom.Element; - import com.openhtmltopdf.css.sheet.FontFaceRule; import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.RenderingContext; +import org.w3c.dom.Element; + +import java.util.List; public interface SVGDrawer { - public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, float dotsPerInch); + public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, double width, double height, double dotsPerPixel); public void importFontFaceRules(List fontFaces, SharedContext shared); diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/swing/Java2DOutputDevice.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/swing/Java2DOutputDevice.java index 99327d61c..2fe5131c0 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/swing/Java2DOutputDevice.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/swing/Java2DOutputDevice.java @@ -21,10 +21,7 @@ import com.openhtmltopdf.css.parser.FSColor; import com.openhtmltopdf.css.parser.FSRGBColor; -import com.openhtmltopdf.extend.FSGlyphVector; -import com.openhtmltopdf.extend.FSImage; -import com.openhtmltopdf.extend.OutputDevice; -import com.openhtmltopdf.extend.ReplacedElement; +import com.openhtmltopdf.extend.*; import com.openhtmltopdf.render.*; import javax.swing.*; @@ -280,7 +277,14 @@ public boolean isSupportsCMYKColors() { return true; } - private Stack transformStack = new Stack(); + @Override + public void drawWithGraphics(float x, float y, float width, float height, OutputDeviceGraphicsDrawer renderer) { + Graphics2D graphics = (Graphics2D) _graphics.create((int) x, (int) y, (int) width, (int) height); + renderer.render(graphics); + graphics.dispose(); + } + + private Stack transformStack = new Stack(); private Stack clipStack= new Stack(); @Override diff --git a/openhtmltopdf-examples/pom.xml b/openhtmltopdf-examples/pom.xml index 52e907e72..83ca1de47 100644 --- a/openhtmltopdf-examples/pom.xml +++ b/openhtmltopdf-examples/pom.xml @@ -39,6 +39,11 @@ openhtmltopdf-rtl-support ${project.version} + + com.openhtmltopdf + openhtmltopdf-svg-support + ${project.version} + junit junit diff --git a/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/testcases/TestcaseRunner.java b/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/testcases/TestcaseRunner.java index fbb36da6f..94d72940e 100644 --- a/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/testcases/TestcaseRunner.java +++ b/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/testcases/TestcaseRunner.java @@ -4,10 +4,10 @@ import com.openhtmltopdf.bidi.support.ICUBidiSplitter; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder.TextDirection; +import com.openhtmltopdf.svgsupport.BatikSVGDrawer; import com.openhtmltopdf.util.JDKXRLogger; import com.openhtmltopdf.util.XRLog; import com.openhtmltopdf.util.XRLogger; - import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.util.Charsets; @@ -50,6 +50,11 @@ public static void main(String[] args) throws Exception { runTestCase("font-family-built-in"); runTestCase("form-controls"); + /* + * SVG samples + */ + runTestCase("svg-inline"); + /* Add additional test cases here. */ } @@ -105,24 +110,29 @@ public void log(String where, Level level, String msg) { delegate.log(where, level, msg); } }); - + + renderPDF(html, outputStream); + + if (!warnings.isEmpty() && !allowWarnings) { + throw warnings.get(0); + } + } + + private static void renderPDF(String html, OutputStream outputStream) throws Exception { try { PdfRendererBuilder builder = new PdfRendererBuilder(); builder.useUnicodeBidiSplitter(new ICUBidiSplitter.ICUBidiSplitterFactory()); builder.useUnicodeBidiReorderer(new ICUBidiReorderer()); builder.defaultTextDirection(TextDirection.LTR); + builder.useSVGDrawer(new BatikSVGDrawer()); builder.withHtmlContent(html, TestcaseRunner.class.getResource("/testcases/").toString()); builder.toStream(outputStream); builder.run(); } finally { outputStream.close(); } - - if (!warnings.isEmpty() && !allowWarnings) { - throw warnings.get(0); - } } - + public static void runTestCase(String testCaseFile) throws Exception { byte[] htmlBytes = IOUtils.toByteArray(TestcaseRunner.class .getResourceAsStream("/testcases/" + testCaseFile + ".html")); @@ -130,18 +140,8 @@ public static void runTestCase(String testCaseFile) throws Exception { String outDir = System.getProperty("OUT_DIRECTORY", "."); String testCaseOutputFile = outDir + "/" + testCaseFile + ".pdf"; FileOutputStream outputStream = new FileOutputStream(testCaseOutputFile); - - try { - PdfRendererBuilder builder = new PdfRendererBuilder(); - builder.useUnicodeBidiSplitter(new ICUBidiSplitter.ICUBidiSplitterFactory()); - builder.useUnicodeBidiReorderer(new ICUBidiReorderer()); - builder.defaultTextDirection(TextDirection.LTR); - builder.withHtmlContent(html, TestcaseRunner.class.getResource("/testcases/").toString()); - builder.toStream(outputStream); - builder.run(); - } finally { - outputStream.close(); - } + + renderPDF(html, outputStream); System.out.println("Wrote " + testCaseOutputFile); } } diff --git a/openhtmltopdf-examples/src/main/resources/testcases/svg-inline.html b/openhtmltopdf-examples/src/main/resources/testcases/svg-inline.html new file mode 100644 index 000000000..0d8358cd1 --- /dev/null +++ b/openhtmltopdf-examples/src/main/resources/testcases/svg-inline.html @@ -0,0 +1,143 @@ + + + + + + +

Some inline SVG examples

+ +Some examples how inline SVG is rendered. + +

JSON-Symbol

+ + + + + + + + +

Barchart

+ + + + + + + + + + + Bar Chart + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shoe + Car + Travel + Computer + + 0 + 10 + 20 + 30 + 40 + 50 + 60 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +End of SVGs + + + diff --git a/openhtmltopdf-pdfbox/pom.xml b/openhtmltopdf-pdfbox/pom.xml index 97fe4bdbf..128f65bf4 100644 --- a/openhtmltopdf-pdfbox/pom.xml +++ b/openhtmltopdf-pdfbox/pom.xml @@ -51,6 +51,11 @@ openhtmltopdf-core ${project.version}
+ + de.rototor.pdfbox + graphics2d + 0.1 + diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java index 0b92e5bf9..91f18719e 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java @@ -29,13 +29,14 @@ import com.openhtmltopdf.css.style.CssContext; import com.openhtmltopdf.extend.FSImage; import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.extend.OutputDeviceGraphicsDrawer; import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.pdfboxout.PdfBoxFontResolver.FontDescription; import com.openhtmltopdf.pdfboxout.PdfBoxForm.CheckboxStyle; import com.openhtmltopdf.render.*; import com.openhtmltopdf.util.Configuration; import com.openhtmltopdf.util.XRLog; - +import de.rototor.pdfbox.graphics2d.PdfBoxGraphics2D; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -59,7 +60,6 @@ import org.w3c.dom.Node; import javax.imageio.ImageIO; - import java.awt.*; import java.awt.RenderingHints.Key; import java.awt.geom.*; @@ -1315,6 +1315,33 @@ public boolean isSupportsCMYKColors() { return true; } + @Override + public void drawWithGraphics(float x, float y, float width, float height, OutputDeviceGraphicsDrawer renderer) { + try { + PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(_writer, (int) width, (int) height); + /* + * We *could* customize the PDF mapping here. But for now the default is enough. + */ + + /* + * Do rendering + */ + renderer.render(pdfBoxGraphics2D); + /* + * Dispose to close the XStream + */ + pdfBoxGraphics2D.dispose(); + + /* + * And then stamp it + */ + _cp.placeXForm(x,y,pdfBoxGraphics2D.getXFormObject()); + } + catch(IOException e){ + throw new RuntimeException("Error while drawing on Graphics2D", e); + } + } + public List findPagePositionsByID(CssContext c, Pattern pattern) { Map idMap = _sharedContext.getIdMap(); if (idMap == null) { diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java index 56b4c4976..181a33304 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java @@ -1,13 +1,12 @@ package com.openhtmltopdf.pdfboxout; -import java.awt.Point; - -import org.w3c.dom.Element; - import com.openhtmltopdf.extend.SVGDrawer; import com.openhtmltopdf.layout.LayoutContext; import com.openhtmltopdf.render.BlockBox; import com.openhtmltopdf.render.RenderingContext; +import org.w3c.dom.Element; + +import java.awt.*; public class PdfBoxSVGReplacedElement implements PdfBoxReplacedElement { private final Element e; @@ -80,6 +79,6 @@ public int getBaseline() { @Override public void paint(RenderingContext c, PdfBoxOutputDevice outputDevice, BlockBox box) { - svg.drawSVG(e, outputDevice, c, point.getX(), point.getY(), this.dotsPerPixel * 96f); + svg.drawSVG(e, outputDevice, c, point.getX(), point.getY(), getIntrinsicWidth(), getIntrinsicHeight(), dotsPerPixel); } } diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java index 11764d556..1f6dfe89d 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java @@ -1,20 +1,21 @@ package com.openhtmltopdf.pdfboxout; -import java.awt.geom.AffineTransform; -import java.io.IOException; -import java.util.Locale; - +import com.openhtmltopdf.util.XRLog; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.apache.pdfbox.util.Matrix; -import com.openhtmltopdf.util.XRLog; +import java.awt.geom.AffineTransform; +import java.io.IOException; +import java.util.Locale; public class PdfContentStreamAdapter { private final PDPageContentStream cs; + public static class PdfException extends RuntimeException { private static final long serialVersionUID = 1L; @@ -48,11 +49,11 @@ public void addRect(float x, float y, float w, float h) { logAndThrow("addRect", e); } } - + public void newPath() { // I think PDF-BOX does this automatically. } - + public void setExtGState(PDExtendedGraphicsState gs) { try { cs.setGraphicsStateParameters(gs); @@ -283,6 +284,12 @@ public void drawImage(PDImageXObject xobject, float x, float y, float w, public void setMiterLimit(float miterLimit) { // TODO Not currently supported by PDF-BOX. + // TODO: Use official API when the next version is released. See PDFBOX-3669 + try { + cs.appendRawCommands(miterLimit + " M "); + } catch (IOException e) { + logAndThrow("drawImage", e); + } } public void setTextSpacing(float nonSpaceAdjust) { @@ -308,4 +315,17 @@ public void setPdfMatrix(AffineTransform transform) { logAndThrow("setPdfMatrix", e); } } + + public void placeXForm(float x, float y, PDFormXObject xFormObject) { + try { + cs.saveGraphicsState(); + AffineTransform tf = new AffineTransform(); + tf.translate(x,0); + cs.transform(new Matrix(tf)); + cs.drawForm(xFormObject); + cs.restoreGraphicsState(); + } catch (IOException e) { + logAndThrow("placeXForm", e); + } + } } diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java index 9e36a7f04..02967bd85 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java @@ -1,8 +1,12 @@ package com.openhtmltopdf.svgsupport; -import java.util.List; -import java.util.logging.Level; - +import com.openhtmltopdf.css.sheet.FontFaceRule; +import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.extend.SVGDrawer; +import com.openhtmltopdf.layout.SharedContext; +import com.openhtmltopdf.render.RenderingContext; +import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver; +import com.openhtmltopdf.util.XRLog; import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; @@ -11,13 +15,8 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; -import com.openhtmltopdf.css.sheet.FontFaceRule; -import com.openhtmltopdf.extend.OutputDevice; -import com.openhtmltopdf.extend.SVGDrawer; -import com.openhtmltopdf.layout.SharedContext; -import com.openhtmltopdf.render.RenderingContext; -import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver; -import com.openhtmltopdf.util.XRLog; +import java.util.List; +import java.util.logging.Level; public class BatikSVGDrawer implements SVGDrawer { @@ -32,14 +31,14 @@ public void importFontFaceRules(List fontFaces, SharedContext shar } @Override - public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, float dotsPerInch) { + public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, double width, double height, double dotsPerPixel) { if (this.fontResolver == null) { XRLog.general(Level.INFO, "importFontFaceRules has not been called for this pdf transcoder"); this.fontResolver = new OpenHtmlFontResolver(); } - PDFTranscoder transcoder = new PDFTranscoder(outputDevice, ctx, x, y, this.fontResolver, dotsPerInch); + PDFTranscoder transcoder = new PDFTranscoder(outputDevice, ctx, x, y, width, height, this.fontResolver, dotsPerPixel); try { DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java index 6b24fbace..3c179fa87 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java @@ -1,19 +1,12 @@ package com.openhtmltopdf.svgsupport; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.Image; -import java.awt.Paint; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Stroke; +import com.openhtmltopdf.css.parser.FSRGBColor; +import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.render.RenderingContext; +import org.apache.batik.ext.awt.g2d.AbstractGraphics2D; +import org.apache.batik.ext.awt.g2d.GraphicContext; + +import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; @@ -22,13 +15,7 @@ import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; -import org.apache.batik.ext.awt.g2d.AbstractGraphics2D; -import org.apache.batik.ext.awt.g2d.GraphicContext; - -import com.openhtmltopdf.css.parser.FSRGBColor; -import com.openhtmltopdf.extend.OutputDevice; -import com.openhtmltopdf.render.RenderingContext; - +@Deprecated public class PDFGraphics2DOutputDeviceAdapter extends AbstractGraphics2D { private final RenderingContext ctx; diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java index 939ee52ec..0322661dc 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java @@ -1,38 +1,50 @@ package com.openhtmltopdf.svgsupport; -import java.awt.FontFormatException; -import java.awt.font.TextAttribute; -import java.io.InputStream; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.batik.bridge.FontFace; -import org.apache.batik.bridge.FontFamilyResolver; -import org.apache.batik.gvt.font.GVTFontFamily; -import org.apache.batik.transcoder.ErrorHandler; -import org.apache.batik.transcoder.SVGAbstractTranscoder; -import org.apache.batik.transcoder.TranscoderException; -import org.apache.batik.transcoder.TranscoderOutput; -import org.w3c.dom.Document; - import com.openhtmltopdf.css.constants.CSSName; import com.openhtmltopdf.css.constants.IdentValue; import com.openhtmltopdf.css.sheet.FontFaceRule; import com.openhtmltopdf.css.style.CalculatedStyle; import com.openhtmltopdf.css.style.FSDerivedValue; import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.extend.OutputDeviceGraphicsDrawer; import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.util.XRLog; +import org.apache.batik.bridge.FontFace; +import org.apache.batik.bridge.FontFamilyResolver; +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.transcoder.ErrorHandler; +import org.apache.batik.transcoder.SVGAbstractTranscoder; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.batik.transcoder.TranscoderOutput; +import org.w3c.dom.Document; -public class PDFTranscoder extends SVGAbstractTranscoder { +import java.awt.*; +import java.awt.font.TextAttribute; +import java.awt.geom.AffineTransform; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; - private final PDFGraphics2DOutputDeviceAdapter od; +public class PDFTranscoder extends SVGAbstractTranscoder { private final OpenHtmlFontResolver fontResolver; - - public PDFTranscoder(OutputDevice od, RenderingContext ctx, double x, double y, OpenHtmlFontResolver fontResolver, float dotsPerInch) { - this.od = new PDFGraphics2DOutputDeviceAdapter(ctx, od, x, y, dotsPerInch); + private final OutputDevice outputDevice; + private final double x; + private final double y; + private final double dotsPerPoint; + private final AffineTransform defaultTransform; + + public PDFTranscoder(OutputDevice od, RenderingContext ctx, double x, double y, double width, double height, OpenHtmlFontResolver fontResolver, double dotsPerInch ) { + this.x = x; + this.y = y; + this.dotsPerPoint = dotsPerInch / 96f; + defaultTransform = AffineTransform.getScaleInstance(dotsPerPoint, dotsPerPoint); + + this.width = (float)width; + this.height = (float)height; + this.outputDevice = od; + this.fontResolver = fontResolver; } @@ -174,7 +186,26 @@ public void importFontFaces(List fontFaces, SharedContext ctx) { protected void transcode(Document svg, String uri, TranscoderOutput out) throws TranscoderException { this.userAgent = new OpenHtmlUserAgent(this.fontResolver); super.transcode(svg, uri, out); - this.root.paint(od); + + float x = (float) (this.x * this.dotsPerPoint); + float y = (float) (this.y * this.dotsPerPoint); + //final float width = (float) (this.width * this.dotsPerPoint); + //final float height = (float) (this.height * this.dotsPerPoint); + outputDevice.drawWithGraphics((float)x, (float)y, (float)width, (float)height, new OutputDeviceGraphicsDrawer() { + @Override + public void render(Graphics2D graphics2D) { + /* + * Debug rectangle, should only fill the black bordered space... + */ + graphics2D.setColor(new Color(128,255,128,128)); + graphics2D.fillRect(0,0,(int)width,(int)height); + + /* + * Do the real paint + */ + PDFTranscoder.this.root.paint(graphics2D); + } + }); } @Override