PDF 的高效 SVG 渲染(Java、Batik、飞碟)
Efficient SVG rendering for PDFs (Java, Batik, Flying Saucer)
我正在使用 XHTML 和飞碟渲染 PDF。我也添加了 SVG 图像(图标等)。但是,当我尝试绘制大量图像(如 5000+)时,渲染会花费很长时间(很明显)。只有大约 10 个不同的图像要绘制,但只是重复了很多次(相同大小)。
有没有 way/library 可以有效地做到这一点?
目前正在使用蜡染、飞碟组合画图。以下代码用于解析xhtml并找到放置SVG图片的img标签:
@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(element.getAttribute("src")).toURL().toString());
} catch (IOException e) {
e.printStackTrace();
}
Element svgElement = svgImage.getDocumentElement();
element.appendChild(element.getOwnerDocument().importNode(svgElement, true));
return new SVGReplacedElement(svgImage, cssWidth, cssHeight);
}
return this.superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight);
}
并绘制我使用的图像:
@Override
public void paint(RenderingContext renderingContext, ITextOutputDevice outputDevice,
BlockBox blockBox) {
PdfContentByte cb = outputDevice.getWriter().getDirectContent();
float width = cssWidth / outputDevice.getDotsPerPoint();
float height = 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);
}
缩放的想法。在 i5 8gb RAM 上,100 张图像需要 2 秒,5000 张图像大约需要 42 秒。
那么有没有一种方法可以将绘制的 SVG 存储在内存中并更快地粘贴它之类的?因为现在它似乎把所有的图像都当作单独的图像并吞噬了我所有的记忆并永远消失。
通过做两件事设法优化了内存和速度。
我在 createReplacedElement
方法中预先生成了 SVGDocuments,这加快了速度。
主要改进是为所有图像预先生成所有 pdfTemplates。这大大提高了速度,因为模板已经包含渲染图像。
所有常规文本的渲染仍然很慢,所以我可能会调低 DPI。
编辑:进一步优化见Is there any way improve the performance of FlyingSaucer?
我正在使用 XHTML 和飞碟渲染 PDF。我也添加了 SVG 图像(图标等)。但是,当我尝试绘制大量图像(如 5000+)时,渲染会花费很长时间(很明显)。只有大约 10 个不同的图像要绘制,但只是重复了很多次(相同大小)。
有没有 way/library 可以有效地做到这一点?
目前正在使用蜡染、飞碟组合画图。以下代码用于解析xhtml并找到放置SVG图片的img标签:
@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(element.getAttribute("src")).toURL().toString());
} catch (IOException e) {
e.printStackTrace();
}
Element svgElement = svgImage.getDocumentElement();
element.appendChild(element.getOwnerDocument().importNode(svgElement, true));
return new SVGReplacedElement(svgImage, cssWidth, cssHeight);
}
return this.superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight);
}
并绘制我使用的图像:
@Override
public void paint(RenderingContext renderingContext, ITextOutputDevice outputDevice,
BlockBox blockBox) {
PdfContentByte cb = outputDevice.getWriter().getDirectContent();
float width = cssWidth / outputDevice.getDotsPerPoint();
float height = 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);
}
缩放的想法。在 i5 8gb RAM 上,100 张图像需要 2 秒,5000 张图像大约需要 42 秒。
那么有没有一种方法可以将绘制的 SVG 存储在内存中并更快地粘贴它之类的?因为现在它似乎把所有的图像都当作单独的图像并吞噬了我所有的记忆并永远消失。
通过做两件事设法优化了内存和速度。
我在 createReplacedElement
方法中预先生成了 SVGDocuments,这加快了速度。
主要改进是为所有图像预先生成所有 pdfTemplates。这大大提高了速度,因为模板已经包含渲染图像。
所有常规文本的渲染仍然很慢,所以我可能会调低 DPI。
编辑:进一步优化见Is there any way improve the performance of FlyingSaucer?