使用Flying Saucer将图像渲染为PDF格式的内存

我正在使用Flying Saucer将XHTML转换为PDF文档。 我已经得到了只使用基本HTML和内联CSS的代码,但是,现在我正在尝试将图像作为一种标题添加到PDF中。 我想知道的是,如果有任何方式通过在图像文件中读取Java Image对象来添加图像,然后以某种方式将其添加到PDF(或XHTML – 就像它获取虚拟“url”一样表示我可以用来渲染PDF的Image对象。 有没有人做过这样的事情?

预先感谢您提供的任何帮助!

我上周必须这样做,希望我能马上回答你。

飞碟

最简单的方法是在使用Flying Saucer渲染之前,在HTML模板中添加想要的图像作为标记。 在Flying Saucer中,您必须实现ReplacedElementFactory以便在使用图像数据渲染之前替换任何标记。

 /** * Replaced element in order to replace elements like * <div class="media" data-src="image.png" /> with the real * media content. */ public class MediaReplacedElementFactory implements ReplacedElementFactory { private final ReplacedElementFactory superFactory; public MediaReplacedElementFactory(ReplacedElementFactory superFactory) { this.superFactory = superFactory; } @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"); // Replace any 
with the // binary data of `image.png` into the PDF. if ("div".equals(nodeName) && "media".equals(className)) { if (!element.hasAttribute("data-src")) { throw new RuntimeException("An element with class `media` is missing a `data-src` attribute indicating the media file."); } InputStream input = null; try { input = new FileInputStream("/base/folder/" + element.getAttribute("data-src")); final byte[] bytes = IOUtils.toByteArray(input); final Image image = Image.getInstance(bytes); final FSImage fsImage = new ITextFSImage(image); if (fsImage != null) { if ((cssWidth != -1) || (cssHeight != -1)) { fsImage.scale(cssWidth, cssHeight); } return new ITextImageElement(fsImage); } } catch (Exception e) { throw new RuntimeException("There was a problem trying to read a template embedded graphic.", e); } finally { IOUtils.closeQuietly(input); } } return this.superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight); } @Override public void reset() { this.superFactory.reset(); } @Override public void remove(Element e) { this.superFactory.remove(e); } @Override public void setFormSubmissionListener(FormSubmissionListener listener) { this.superFactory.setFormSubmissionListener(listener); } }

您会注意到我在这里/base/folder有硬编码,这是HTML文件所在的文件夹,因为它将成为Flying Saucer解析媒体的根URL。 您可以将其更改为正确的位置,来自您想要的任何位置(例如属性)。

HTML

在您的HTML标记中,您可以在某处指示

如下所示:

     My document      ...   

渲染

最后,你需要在渲染时向Flying-Saucer指出你的ReplacedElementFactory

 String content = loadHtml(); ITextRenderer renderer = new ITextRenderer(); renderer.getSharedContext().setReplacedElementFactory(new MediaReplacedElementFactory(renderer.getSharedContext().getReplacedElementFactory())); renderer.setDocumentFromString(content.toString()); renderer.layout(); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); renderer.createPDF(baos); // baos.toByteArray(); 

我一直在使用Freemarker从模板生成HTML,然后将结果提供给FlyingSaucer取得了巨大成功。 这是一个非常整洁的图书馆。

感谢Alex提供详细解决方案。 我正在使用这个解决方案,发现还有另一条线要加以使其工作。

 public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox, UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) { Element element = blockBox.getElement(); .... .... final Image image = Image.getInstance(bytes); final int factor = ((ITextUserAgent)userAgentCallback).getSharedContext().getDotsPerPixel(); //Need to add this line image.scaleAbsolute(image.getPlainWidth() * factor, image.getPlainHeight() * factor) //Need to add this line final FSImage fsImage = new ITextFSImage(image); .... .... 

我们需要从SharedContext读取DPP并缩放图像以显示在PDF上呈现图像。

另一个建议:我们可以直接扩展ITextReplacedElement而不是实现ReplacedElementFactory 。 在这种情况下,我们可以在SharedContext设置ReplacedElementFactory ,如下所示:

 renderer.getSharedContext().setReplacedElementFactory(new MediaReplacedElementFactory(renderer.getOutputDevice()); 

对我有用的是将它作为嵌入式图像。 首先将图像转换为base64然后嵌入它:

  byte[] image = ... ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString("\n" + " \n" + " 

Image

\n" + "
\n" + " \n" + ""); renderer.layout(); renderer.createPDF(response.getOutputStream());