【问题标题】:Svg integration in pdf using flying saucer使用飞碟将 Svg 集成到 pdf 中
【发布时间】:2016-08-31 14:34:02
【问题描述】:

我遇到了将html转换为pdf的情况,幸好我可以通过飞碟api实现这一点。但是我的 HTML 在转换时由 svg 标签组成,我无法在 pdf 中获取 svg。可以使用Stackoverflow question 来实现 和Tutorial

replacedElementFactory 是什么意思?

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

【问题讨论】:

    标签: java html pdf svg flying-saucer


    【解决方案1】:

    只是教程中的一个错误,不需要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>
    

    ChainingReplacedElementFactorySVGReplacedElementSVGReplacedElementFactory 来自 tutorial

    【讨论】:

    • 感谢您的快速回复......它在上面的html中使用svg标签工作正常......但我有由highchart api生成的svg......示例输入在这里......jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/…跨度>
    • 问题是在服务器上从 highchart JS 代码生成 SVG(或图像)。不幸的是,我没有解决方案,但 highchart 网站上的这个页面可以帮助你:highcharts.com/news/52-serverside-generated-charts
    • 链接已损坏。我尝试使用xpert-framework 没有结果。我在哪里可以得到ChainingReplacedElementFactorySVGReplacedElementFactory
    • 如果没有 html head 部分中的 svg 样式(如上所示),这将无法工作 - 不要忽视它!
    【解决方案2】:

    如果您想要页内解决方案,这里有一个使用 @cloudformatter 的替代方案,它是一种远程格式化服务。我将他们的 Javascript 以及一些文本和您的 Highchart 图表添加到您的小提琴中。

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

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

    上面放置在小提琴中的代码会将带有'id' printme的div格式化为PDF以供下载。该 div 包括您的图表和一些文本。

    http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage 显示使用说明,并有更多的 SVG 图表示例,这些图表可以单独或作为页面的一部分与文本、表格等相结合。

    【讨论】:

      【解决方案3】:

      @Rajesh 我希望您已经找到了解决问题的方法。如果没有(或任何人在使用飞碟、蜡染和 svg 标签时遇到问题),那么您可能需要考虑这一点 - 从&lt;g&gt; 标记中删除所有clip-path="url(#highcharts-xxxxxxx-xx)" 对我有用。

      【讨论】:

        【解决方案4】:

        我的代码指的是缺少的代码部分“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()
            {
            }
        } 
        

        【讨论】:

        • 感谢您提供此代码 sn-p,它可能会提供一些有限的短期帮助。一个正确的解释would greatly improve 其长期价值通过展示为什么这是解决问题的好方法,并将使其对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
        猜你喜欢
        • 2016-06-26
        • 2017-11-25
        • 2021-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-15
        • 2013-05-05
        • 2013-04-09
        相关资源
        最近更新 更多