将SVG转换为PDF

27
如何以编程方式将SVG文件转换为PDF?(我需要在生成PDF之前在某些方面更改SVG,因此仅使用工具进行预转换不足够。)
最好使用Java,但Perl或PHP也可以。
显然,我基本上考虑使用Java的Apache FOP和Batik。但是,无论我搜索多长时间,都找不到有关如何执行此操作的简单介绍。像SVGConverter这样的东西有描述,例如“定义能够转换部分或全部GraphicContext的类的接口”,但我真的不知道那是什么意思。
我有这种感觉,FOP或Batik提供了一个很简单的API来完成这个任务,但是我现在无法找到它(或者它确实不存在)。
就支持的SVG功能而言,该文件具有一些填充有一些线性渐变的路径。
如果我可以将SVG作为DOM文档传递,那就太理想了;然后我会加载我的模板SVG文件,按用户指定的方式更改它,然后生成PDF。

1
请点击此处查看相关API:https://dev59.com/questions/V2w15IYBdhLWcg3wcbWy#6613033 - jbeard4
5个回答

22
感谢Adrian展示了如何使用Batik光栅化API。然而,我需要一个更轻量级的解决方案——我不能写临时文件,并且我希望有更少的依赖。因此,从他指出的方法开始,我找到了一种访问低级代码以执行转换而不进行其他操作的方法。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.fop.svg.PDFTranscoder;

public class Test {
    public static void main(String[] argv) throws TranscoderException, FileNotFoundException {
        Transcoder transcoder = new PDFTranscoder();
        TranscoderInput transcoderInput = new TranscoderInput(new FileInputStream(new File("/tmp/test.svg")));
        TranscoderOutput transcoderOutput = new TranscoderOutput(new FileOutputStream(new File("/tmp/test.pdf")));
        transcoder.transcode(transcoderInput, transcoderOutput);
    }
}

编译和运行命令为:
javac -cp batik-rasterizer.jar -d build Test.java
java -cp build:batik-rasterizer.jar Test

重要的一点是 TranscoderInputTranscoderOutput 可以使用任何 InputStreamOutputStream,而不仅仅是文件流。请注意,其中一个构造函数需要一个 org.w3c.dom.Document,这意味着您甚至不需要将 SVG DOM 序列化为 SVG 字符串,从而节省了额外的步骤。
与高级 API 不同,此版本也不会将任何内容写入 stdout/stderr。
对于JPEG、PNG或TIFF输出,请将org.apache.fop.svg.PDFTranscoder替换为org.apache.batik.transcoder.image.JPEGTranscoderPNGTranscoderTIFFTranscoder(注意,这些光栅格式在不同的包中)。
(我不太确定Java如何找到org.apache.batik.transcoder.*org.apache.fop.svg.PDFTranscoder类,因为我在batik-rasterizer.jar中没有看到它们。) 编辑: 尽管简单的命令行编译仅适用于batik-rasterizer.jar,但它会使用某种类加载器魔法来查找所有必要的类。在更实际的情况下(使用Ant构建项目),您需要手动查找这些类。可以在Batik项目batik-1.7.zipFOP项目fop-1.1.zip中找到它们。从Batik开始,您需要使用batik-transcoder.jar进行编译并运行。
  • batik-transcoder.jar
  • batik-anim.jar
  • batik-awt-util.jar
  • batik-bridge.jar
  • batik-css.jar
  • batik-dom.jar
  • batik-ext.jar
  • batik-gvt.jar
  • batik-parser.jar
  • batik-script.jar
  • batik-svg-dom.jar
  • batik-util.jar
  • batik-xml.jar
  • xml-apis-ext.jar

从FOP开始,你需要使用fop.jar进行编译,并且运行。

  • fop.jar
  • avalon-framework-4.2.0.jar
  • xmlgraphics-commons-1.5.jar

6

我终于找到了使用Batik解决问题的适当代码行。

你需要将SVG文件和生成的PDF文件作为磁盘上的文件,不能在内存中处理(我正在编写一个HTTP Servlet,因此没有必要把任何东西写成文件,理想情况下,我应该将结果流式传输到HTTP客户端)。我使用File.createTemporaryFile创建一个文件,将我的SVG数据导出到文件中,然后将生成的PDF写入。

所以我使用的代码如下:

import org.apache.batik.apps.rasterizer.DestinationType;
import org.apache.batik.apps.rasterizer.SVGConverter;
import ...

// SVG available as a DOM object (created programatically by my program)
Document svgXmlDoc = ...

// Save this SVG into a file (required by SVG -> PDF transformation process)
File svgFile = File.createTempFile("graphic-", ".svg");
Transformer transformer = TransformerFactory.newInstance().newTransformer();
DOMSource source2 = new DOMSource(svgXmlDoc);
FileOutputStream fOut = new FileOutputStream(svgFile);
try { transformer.transform(source2, new StreamResult(fOut)); }
finally { fOut.close(); }

// Convert the SVG into PDF
File outputFile = File.createTempFile("result-", ".pdf");
SVGConverter converter = new SVGConverter();
converter.setDestinationType(DestinationType.PDF);
converter.setSources(new String[] { svgFile.toString() });
converter.setDst(outputFile);
converter.execute();

我有以下JAR文件(使用Google搜索以找到项目并下载它们):

  • avalon-framework-4.2.0.jar
  • batik-all-1.7.jar
  • commons-io-1.3.1.jar
  • commons-logging-1.0.4.jar
  • fop-0.95.jar
  • log4j-1.2.15.jar
  • xml-apis-ext.jar
  • xmlgraphics-commons-1.3.1.jar

4

您需要一个用于呈现SVG和PDF的库。我推荐使用SVG Salamander来处理前者,使用iText来处理后者。使用SVG Salamander,您可以读取SVG并创建图像对象;而使用iText,您可以将该图像写入PDF。


1
你只需要phantomjs。这个过程中完全不需要笨重的Batik;只需达到能够运行phantomjs,调用rasterize.js,使用pdf的url作为源,以及一个位置作为输出的点即可。根据你想要做的事情,甚至不需要Java。

http://phantomjs.org/screen-capture.html

除了PNG格式外,PhantomJS还支持JPEG、GIF和PDF格式。


4
这个想法相当有创意,但总的来说可能不是首选方案。根据使用情况,你可能希望保留SVG的向量而不是将文档光栅化。 - jon_wu

1

我使用Altsoft Xml2PDF。如果我理解您的所有需求和要求正确的话,最好尝试他们的Xml2PDF服务器版。


谢谢你的提示!不幸的是,我正在部署在Linux上,这个解决方案似乎只适用于Windows。 - Adrian Smith

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