使用飞碟将Svg集成到pdf中

问题描述 投票:0回答:5

我遇到了将 html 转换为 pdf 的情况,幸运的是我可以通过 Flying Sacer api 实现这一点。但我的 HTML 由 svg 标签组成,在转换时我无法获取 pdf 中的 svg。可以使用 Stackoverflow 问题 来实现 和教程

replacedElementFactory
是什么意思?

ChainingReplacedElementFactory chainingReplacedElementFactory 
        = new ChainingReplacedElementFactory();
chainingReplacedElementFactory.addReplacedElementFactory(replacedElementFactory);
chainingReplacedElementFactory.addReplacedElementFactory(new SVGReplacedElementFactory());
renderer.getSharedContext().setReplacedElementFactory(chainingReplacedElementFactory);
java html pdf svg flying-saucer
5个回答
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
来自教程


1
投票

如果您想要页面内解决方案,这里有一个使用@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 格式的图表示例,这些图表可以单独格式化为 PDF,也可以作为与文本、表格等结合的页面的一部分。


0
投票

@Rajesh 我希望您已经找到问题的解决方案。如果没有(或者任何在使用飞碟、蜡染和 svg 标签时遇到问题的人)那么您可能需要考虑这一点 - 从

clip-path="url(#highcharts-xxxxxxx-xx)"
标签中删除所有
<g>
对我来说成功了。


0
投票

将 svg 转换为 pdf 图像时可获得最佳结果:

class ResourceLoaderUserAgent extends ITextUserAgent {

    private final String sessionId;
    private final ITextOutputDevice outputDevice;

    public ResourceLoaderUserAgent(ITextOutputDevice outputDevice) {
        super(outputDevice, DEFAULT_DOTS_PER_PIXEL);
        this.outputDevice = outputDevice;
    }

    @Override
    public ImageResource getImageResource(String uriStr) {
        if (uriStr.contains(".svg")) {
            return getSVGImageAsPDF(uriStr);
        } else {
            return super.getImageResource(uriStr);
        }
    }

    @Override
    public byte[] getBinaryResource(String uri) {
        if (uri.contains(".svg")) {
            try(var is = resolveAndOpenStream(uri)) {
                Transcoder transcoder = new PDFTranscoder();
                TranscoderInput input = new TranscoderInput(is);
                var os = new ByteArrayOutputStream();
                TranscoderOutput output = new TranscoderOutput(os);
                transcoder.transcode(input, output);
                return os.toByteArray();
            } catch (Exception e) {
                LOG.error("Could not get svg {} as pdf", uri, e);
                return new byte[]{};
            }
        } else {
            return super.getBinaryResource(uri);
        }
    }

    private ImageResource getSVGImageAsPDF(String uriStr) {
        try {
            // Code from ITextUserAgent.getImageResource(String)
            URI uri = new URI(uriStr);
            PdfReader reader = outputDevice.getReader(uri);
            PDFAsImage image = new PDFAsImage(uri);
            Rectangle rect = reader.getPageSizeWithRotation(1);
            image.setInitialWidth(rect.getWidth() * outputDevice.getDotsPerPoint());
            image.setInitialHeight(rect.getHeight() * outputDevice.getDotsPerPoint());
            return new ImageResource(uriStr, image);
        } catch (URISyntaxException | IOException e) {
            throw new RuntimeException(e);
        }
    }
}

依赖关系:

 <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-transcoder</artifactId>
            <version>1.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>fop</artifactId>
            <version>2.9</version>
        </dependency>

-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()
    {
    }
} 
© www.soinside.com 2019 - 2024. All rights reserved.