如何将SVG图像添加到使用HTML和Flying Saucer库(和Batik)构建的PDF?

我正在使用飞碟库(旧的但开源的)使用XHTML生成PDF。 我有这个工作,但我也想添加SVG图像。 我开始致力于整合蜡染试图让它工作,但我遇到了问题。 未绘制SVG图像。 XHTML仍然呈现,但它似乎没有显示SVG。 我已经让SVG在单独的PDF上渲染,但从未与飞碟结果一起渲染。 我添加了通常的ReplacedElementFactory(它也适用于常规图像,但还没有包含该代码)。 唯一相关的方法(确实被调用和所有内容)如下:

@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); } 

之后我尝试用它绘画:

 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); } } 

有趣的是, blockBox.paintDebugOutline(renderingContext); 确实绘制了图像应该在哪里的轮廓。 Eclipse调试还显示正确的文件连接到IMG元素。 CSS看起来如下:

 .header { position: absolute; display: inline-block; right: 0; top: 0; width: 150px; height: 54px; } 

我也尝试过display:block; 。 示例xhtml我试过:

 Logo   

非常感谢您的关注和反馈(可能还有答案)

编辑:最初的问题略有不同,但我已经解决了。 无法将SVGImage附加到实际文档中。 现在它只是没有画。 我已经添加了CSS来显示:块等,如指南中所述。

编辑:清洁代码

编辑:添加了更多关于我尝试过的内容

我不知道为什么,但更换SVGReplacedElement.paint(…)中的代码修复它。

新代码:

 @Override public void paint(RenderingContext renderingContext, ITextOutputDevice outputDevice, BlockBox blockBox) { PdfContentByte cb = outputDevice.getWriter().getDirectContent(); float width = (float) (cssWidth / outputDevice.getDotsPerPoint()); float height = (float) (cssHeight / outputDevice.getDotsPerPoint()); PdfTemplate template = cb.createTemplate(width, height); Graphics2D g2d = template.createGraphics(width, height); PrintTranscoder prm = new PrintTranscoder(); TranscoderInput ti = new TranscoderInput(svg); prm.transcode(ti, null); PageFormat pg = new PageFormat(); Paper pp = new Paper(); pp.setSize(width, height); pp.setImageableArea(0, 0, width, height); pg.setPaper(pp); prm.print(g2d, pg, 0); 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); x /= outputDevice.getDotsPerPoint(); y /= outputDevice.getDotsPerPoint(); cb.addTemplate(template, x, y); } 

得到它: http : //www.samuelrossille.com/posts/2013-08-13-render-html-with-svg-to-pdf-with-flying-saucer.html

可能与我创建的没有链接到原始文档的新UserAgent和DocumentLoader等有关。 无论如何它现在都有效。 希望它能帮助将来的某个人。 如果人们想要评论或重新说明为什么现在这样做,这可能有助于其他人稍后阅读。