Im working on generation of PDFs with XHTML using the flying saucer library (old but open source). I got that working but I also want to add SVG images. Ive started working on integrating batik to try and get it to work but I'm running into issues. I cannot seem to include/append my SVG image into the PDF. The XHTML still renders, but it doesnt seem to show the SVG. I've gotten SVG to render on separate PDFs but never together with the flying saucer results. I've added the usual ReplacedElementFactory (which works with regular images as well but havent included that code). The only relevant method (that does get called and everything) is the following:
public ReplacedElement createReplacedElement(LayoutContext LayoutContext, BlockBox blockBox, UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) {
Element element = blockBox.getElement();
if (element == null) {
return null;
}
String nodeName = element.getNodeName();
String className = element.getAttribute("class");
if ("svg".equals(nodeName)) {
if (element.hasAttribute("src")){
Document svgImage = null;
try {
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
svgImage = f.createDocument(element.getAttribute("src")+".svg");
} catch (IOException ex) {
System.out.println(element.getAttribute("src")+".svg");
}
Element svgElement = svgImage.getDocumentElement();
Document htmlDoc = element.getOwnerDocument();
htmlDoc.importNode(svgElement, true);
element.appendChild(svgElement);
return new SVGReplacedElement(svgImage, cssWidth, cssHeight);
}
}
}
So the svgElement gets loaded and seems to be the correct image. htmlDoc is the original xhtml Document that does get rendered normaly. I try to import the svgElement into the regular xhtml dom and append it (as many examples also do, but it then gives an error:
Exception in thread "main" org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source)
at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source)
at org.apache.xerces.dom.NodeImpl.appendChild(Unknown Source)
at pdf.printing.MediaReplacedElementFactory.createReplacedElement(MediaReplacedElementFactory.java:73)
at org.xhtmlrenderer.render.BlockBox.calcDimensions(BlockBox.java:674)
at org.xhtmlrenderer.render.BlockBox.calcDimensions(BlockBox.java:628)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:763)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:732)
at org.xhtmlrenderer.layout.Layer.layoutAbsoluteChild(Layer.java:714)
at org.xhtmlrenderer.layout.Layer.layoutAbsoluteChildren(Layer.java:687)
at org.xhtmlrenderer.layout.Layer.finish(Layer.java:673)
at org.xhtmlrenderer.layout.LayoutContext.popLayer(LayoutContext.java:231)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:844)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:732)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:293)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:271)
at org.xhtmlrenderer.layout.BlockBoxing.layoutContent(BlockBoxing.java:89)
at org.xhtmlrenderer.render.BlockBox.layoutChildren(BlockBox.java:922)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:802)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:732)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:293)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:271)
at org.xhtmlrenderer.layout.BlockBoxing.layoutContent(BlockBoxing.java:89)
at org.xhtmlrenderer.render.BlockBox.layoutChildren(BlockBox.java:922)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:802)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:732)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:293)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:271)
at org.xhtmlrenderer.layout.BlockBoxing.layoutContent(BlockBoxing.java:89)
at org.xhtmlrenderer.render.BlockBox.layoutChildren(BlockBox.java:922)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:802)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:732)
at org.xhtmlrenderer.pdf.ITextRenderer.layout(ITextRenderer.java:209)
at pdf.printing.Printer.print(Printer.java:206)
Afterwards Ill try to print it with:
@Override
public void paint(RenderingContext renderingContext, ITextOutputDevice outputDevice,
BlockBox blockBox) {
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
blockBox.paintDebugOutline(renderingContext);
PdfContentByte cb = outputDevice.getWriter().getDirectContent();
float width = cssWidth / outputDevice.getDotsPerPoint();
float height = cssHeight / outputDevice.getDotsPerPoint();
PdfTemplate map = cb.createTemplate(width, height);
Graphics2D g2d = map.createGraphics(width, height);
GraphicsNode mapGraphics = builder.build(ctx, svg);
mapGraphics.paint(g2d);
g2d.dispose();
PageBox page = renderingContext.getPage();
float x = blockBox.getAbsX() + page.getMarginBorderPadding(renderingContext, CalculatedStyle.LEFT);
float y = (page.getBottom() - (blockBox.getAbsY() + cssHeight)) + page.getMarginBorderPadding(
renderingContext, CalculatedStyle.BOTTOM);
cb.addTemplate(map, x, y);
}
Interesting: the blockbox.paintDebugOutline does show the outline. All of this is either textbook or a combination of textbook things. I've made sure that the css has a width height display:block etc defined for this. It is embedded in the html as <img class="icon" src="something.svg" alt=""> Im using FlyingSaucer jar and batik 1.8 and Im stuck :(
Alternatively Ive tried:
@Override
public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox, UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) {
Element element = blockBox.getElement();
if (element == null) {
return null;
}
String nodeName = element.getNodeName();
String className = element.getAttribute("class");
if ("svg".equals(nodeName)) {
if (element.hasAttribute("src")){
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
Document svgImage = documentBuilder.newDocument();
element.getOwnerDocument().importNode(element, true);
return new SVGReplacedElement(svgImage, cssWidth, cssHeight);
Which resulted in:
Exception in thread "main" java.lang.ClassCastException: org.apache.xerces.dom.DocumentImpl cannot be cast to org.apache.batik.anim.dom.SVGOMDocument
at org.apache.batik.bridge.BridgeContext.setDocument(Unknown Source)
at org.apache.batik.bridge.GVTBuilder.build(Unknown Source)
at pdf.printing.SVGReplacedElement.paint(SVGReplacedElement.java:121)
at org.xhtmlrenderer.pdf.ITextOutputDevice.paintReplacedElement(ITextOutputDevice.java:183)
at org.xhtmlrenderer.layout.Layer.paintReplacedElement(Layer.java:540)
at org.xhtmlrenderer.layout.Layer.paint(Layer.java:306)
at org.xhtmlrenderer.layout.Layer.paintLayers(Layer.java:165)
at org.xhtmlrenderer.layout.Layer.paint(Layer.java:337)
at org.xhtmlrenderer.pdf.ITextRenderer.paintPage(ITextRenderer.java:384)
at org.xhtmlrenderer.pdf.ITextRenderer.writePDF(ITextRenderer.java:348)
at org.xhtmlrenderer.pdf.ITextRenderer.createPDF(ITextRenderer.java:315)
at org.xhtmlrenderer.pdf.ITextRenderer.createPDF(ITextRenderer.java:246)
at pdf.printing.Printer.print(Printer.java:207)
Thanks a lot for your attention and feedback (and possibly answers)
Aucun commentaire:
Enregistrer un commentaire