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. The SVG images are not drawn. 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:
@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();
if ("img".equals(nodeName)) {
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
SVGDocument svgImage = null;
try {
svgImage = factory.createSVGDocument(new File("logo.svg").toURL()
.toString());
} catch (IOException e) {
e.printStackTrace();
}
Element svgElement = svgImage.getDocumentElement();
Document htmlDoc = element.getOwnerDocument();
Node importedNode = htmlDoc.importNode(svgElement, true);
element.appendChild(importedNode);
return new SVGReplacedElement(svgImage, cssWidth, cssHeight);
}
return this.superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight);
}
Afterwards I try to paint it with:
import java.awt.Graphics2D;
import java.awt.Point;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.gvt.GraphicsNode;
import org.w3c.dom.svg.SVGDocument;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextOutputDevice;
import org.xhtmlrenderer.pdf.ITextReplacedElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.render.PageBox;
import org.xhtmlrenderer.render.RenderingContext;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
public class SVGReplacedElement implements ITextReplacedElement {
private Point location = new Point(0, 0);
private SVGDocument svg;
private int cssWidth;
private int cssHeight;
public SVGReplacedElement(SVGDocument importedNode, int cssWidth, int cssHeight) {
this.cssWidth = cssWidth;
this.cssHeight = cssHeight;
this.svg = importedNode;
}
@Override
Methods....
@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);
}
}
Interestingly enough, the blockBox.paintDebugOutline(renderingContext);
does draw the outlines of where the images should be. Eclipse debugging also revealed that the right files are connected to the IMG elements.
The CSS looks as follows:
.header {
position: absolute;
display: inline-block;
right: 0;
top: 0;
width: 150px;
height: 54px;
}
I've also tried with display:block;
. Examples xhtml I tried:
<img class='header' src='icon.svg' alt='Logo'/>
<svg class='header' type='image/svg+xml' data='icon.svg' />
<object class='header' type='image/svg+xml' data='icon.svg' />
Thanks a lot for your attention and feedback (and possibly answers)
EDIT: Originally the problems was slightly different but I've resolved that. The SVGImage could not be appended to the actual document. Now it just doesnt draw. I've added the CSS to display:block etc as mentioned in guides.
EDIT: Cleaner code
EDIT: Added more on what I've tried