如何将SVG图像添加到使用HTML和Flying Saucer库(和Batik)构建的PDF? [英] How to add SVG image to PDF built with HTML and Flying Saucer library (and Batik)?

查看:411
本文介绍了如何将SVG图像添加到使用HTML和Flying Saucer库(和Batik)构建的PDF?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

之后我尝试用它绘画:

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看起来如下:

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

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

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)

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

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.

编辑:清洁代码

编辑:添加了更多关于我尝试过的东西

Added more on what I've tried

推荐答案

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

I dont know why exactly, but replacing the code in SVGReplacedElement.paint(...) fixed it.

新代码:

@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等没有链接到原始文档。无论如何它现在都有效。希望它能帮助将来的某个人。如果人们想评论或重新说明为什么现在这样做,这可能有助于其他人稍后阅读。

Might have had something to do with the new UserAgent and DocumentLoader etc I created that were not linked to the original document. In any case it works now. Hope it will help someone in the future. If people want to comment or reanswer as to why this works now, that might help other reading this later.

这篇关于如何将SVG图像添加到使用HTML和Flying Saucer库(和Batik)构建的PDF?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆