使用Flying Saucer将SVG集成到PDF中

7

我曾经遇到过将html转换为pdf的情况,谢天谢地,我通过使用飞行剪贴簿api实现了这一点。但是,我的HTML包含svg标签,在转换时,我无法在pdf中获取svg。可以通过 Stackoverflow问题教程 实现。

replacedElementFactory是什么意思?

ChainingReplacedElementFactory chainingReplacedElementFactory 
        = new ChainingReplacedElementFactory();
chainingReplacedElementFactory.addReplacedElementFactory(replacedElementFactory);
chainingReplacedElementFactory.addReplacedElementFactory(new SVGReplacedElementFactory());
renderer.getSharedContext().setReplacedElementFactory(chainingReplacedElementFactory);
4个回答

7
这只是教程中的一个错误,不需要使用带有replacedElementFactory的行。

这是我的工作示例。

Java:

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;

public class PdfSvg {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document inputDoc =  builder.parse("svg.html");

        ByteArrayOutputStream output = new ByteArrayOutputStream();

        ITextRenderer renderer = new ITextRenderer();

        ChainingReplacedElementFactory chainingReplacedElementFactory = new ChainingReplacedElementFactory();
        chainingReplacedElementFactory.addReplacedElementFactory(new SVGReplacedElementFactory());
        renderer.getSharedContext().setReplacedElementFactory(chainingReplacedElementFactory);

        renderer.setDocument(inputDoc, "");;
        renderer.layout();
        renderer.createPDF(output);

        OutputStream fos = new FileOutputStream("svg.pdf");
        output.writeTo(fos);
    }
}

HTML:
<html>
<head>
<style type="text/css">
    svg {display: block;width:100mm;height:100mm}
</style>
</head>
<body>
    <div>
        <svg xmlns="http://www.w3.org/2000/svg">
            <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3"
                fill="red" />
        </svg>
    </div>
</body>
</html>

ChainingReplacedElementFactory”,“SVGReplacedElement”和“SVGReplacedElementFactory”来自于这个教程。”

感谢您的快速回复...在上面的HTML中使用SVG标签很好地运行了,但是我有通过Highchart API生成的SVG...样例输入在这里...http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/line-basic/ - Rajesh Kumar Duraisamy
问题是从高图 JS 代码生成 SVG(或图像)在服务器上。不幸的是,我没有解决方案,但这个高图网站上的页面可能会帮助你:http://www.highcharts.com/news/52-serverside-generated-charts。 - obourgain
链接已经失效。我尝试使用 xpert-framework 但没有结果。我在哪里可以获取 ChainingReplacedElementFactorySVGReplacedElementFactory - Marco Sulla
如果没有HTML头部区域中的SVG样式(如上所示),这将无法正常工作 - 不要忽视它! - Geyser14

1
如果您想要一个页面内的解决方案,这里有一个备选方案,使用@cloudformatter提供的远程格式化服务。我将他们的JavaScript添加到了您的fiddle中,以及一些文本和您的Highchart图表。

http://jsfiddle.net/yk0Lxzg0/1/

var click="return xepOnline.Formatter.Format('printme', {render:'download'})";
jQuery('#buttons').append('<button onclick="'+ click +'">PDF</button>');

上面的代码放在fiddle中将格式化'id'为printme的div以便下载PDF。该div包含您的图表和一些文本。 http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage显示使用说明,并具有许多其他SVG格式的图表示例,可以单独将其转换为PDF,也可以作为包含文本、表格等页面的一部分。

0

@Rajesh,希望你已经找到了解决问题的方法。如果没有(或者任何人在使用飞碟、巴蒂克和SVG标签时遇到问题),那么你可能需要考虑这个方法——从<g>标签中删除所有clip-path="url(#highcharts-xxxxxxx-xx)",这对我很有用。


-1

我的代码正在引用缺失的代码部分“SVGReplacedElementFactory”。

我是这样使用它的:

renderer
.getSharedContext()
.setReplacedElementFactory( new B64ImgReplacedElementFactory() );

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.codec.Base64;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class B64ImgReplacedElementFactory implements ReplacedElementFactory
{

    public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight)
    {
        Element e = box.getElement();
        if(e == null)
        {
            return null;
        }
        String nodeName = e.getNodeName();
        if(nodeName.equals("img"))
        {
            String attribute = e.getAttribute("src");
            FSImage fsImage;
            try
            {
                fsImage = buildImage(attribute, uac);
            }
            catch(BadElementException e1)
            {
                fsImage = null;
            }
            catch(IOException e1)
            {
                fsImage = null;
            }
            if(fsImage != null)
            {
                if(cssWidth != -1 || cssHeight != -1)
                {
                    fsImage.scale(cssWidth, cssHeight);
                }
                return new ITextImageElement(fsImage);
            }
        }

        return null;
    }

    protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException, BadElementException
    {
        if(srcAttr.startsWith("data:image/"))
        {
            // BASE64Decoder decoder = new BASE64Decoder();
            // byte[] decodedBytes = decoder.decodeBuffer(b64encoded);
            // byte[] decodedBytes = B64Decoder.decode(b64encoded);
            byte[] decodedBytes = Base64.decode(srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(), srcAttr.length()));
            return new ITextFSImage(Image.getInstance(decodedBytes));
        }
        FSImage fsImage = uac.getImageResource(srcAttr).getImage();
        if(fsImage == null)
        {
            return convertToPNG(srcAttr);
        }
        return null;
    }

    private FSImage convertToPNG(String srcAttr) throws IOException, BadElementException
    {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PNGTranscoder t = new PNGTranscoder();
//        t.addTranscodingHint(JPEGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, (25.4f / 72f));
        t.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, 4000.0F);
        t.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, 4000.0F);
        try
        {
            t.transcode(
                    new TranscoderInput(srcAttr),
                    new TranscoderOutput(byteArrayOutputStream)
            );
        }
        catch(TranscoderException e)
        {
            e.printStackTrace();
        }
        byteArrayOutputStream.flush();
        byteArrayOutputStream.close();
        return new ITextFSImage(Image.getInstance(byteArrayOutputStream.toByteArray()));
    }

    public void remove(Element e)
    {
    }

    @Override
    public void setFormSubmissionListener(FormSubmissionListener formSubmissionListener)
    {

    }

    public void reset()
    {
    }
} 

感谢您提供这段代码片段,它可能会在短期内提供一些有限的帮助。通过展示为什么这是一个好的解决方案,适当的解释将极大地提高其长期价值,并使其对未来具有类似问题的读者更有用。请编辑您的答案以添加一些解释,包括您所做的假设。 - Toby Speight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接