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-examples/pom.xml b/openhtmltopdf-examples/pom.xml index 9c125bd67..8a9cf8d35 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/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 db16e648b..1f6dfe89d 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java @@ -320,7 +320,7 @@ public void placeXForm(float x, float y, PDFormXObject xFormObject) { try { cs.saveGraphicsState(); AffineTransform tf = new AffineTransform(); - tf.translate(x,y); + tf.translate(x,0); cs.transform(new Matrix(tf)); cs.drawForm(xFormObject); cs.restoreGraphicsState(); 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