将 SVG 转换为 PDF

2022-09-01 13:15:13

如何以编程方式将SVG文件转换为PDF?(在生成PDF之前,我需要在某些方面更改SVG,因此仅使用工具进行预转换是不够的。

理想情况下,使用Java,但Perl或PHP也会很好。

显然,我基本上正在考虑Apache FOP和Batik与Java。然而,无论我搜索多长时间,我都找不到关于如何做到这一点的简单介绍。像SVGConverter这样的东西有这样的描述:“为能够转换部分或全部GraphicContext的类定义接口”,但我真的不知道这意味着什么。

我有一种感觉,必须有一个API可以非常简单地做到这一点,由FOP或Batik提供,但我目前无法找到它(或者它可能真的不存在)。

就我需要的受支持的SVG功能而言,该文件有一些路径,这些路径填充了一些线性渐变。

理想情况下,如果我可以将SVG作为DOM文档传递,那将是理想的;然后我会加载我的模板SVG文件,按照用户指定进行更改,然后生成PDF。


答案 1

感谢 Adrian 展示了应该如何使用 Batik Rasterizer 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可以与任何InputStreamSputStream一起使用,而不仅仅是文件流。请注意,其中一个构造函数采用 org.w3c.dom.Document,这意味着您甚至不需要将 SVG DOM 序列化为 SVG 字符串,从而节省了额外的步骤。

与高级API不同,此版本也不会向stdout / stderr写入任何内容。

对于 JPEG、PNG 或 TIFF 输出,请替换为 、 或(请注意,这些栅格格式位于不同的包中)。org.apache.fop.svg.PDFTranscoderorg.apache.batik.transcoder.image.JPEGTranscoderPNGTranscoderTIFFTranscoder

(我不太确定Java如何找到和类,因为我在.c中看不到它们。org.apache.batk.transcoder.*org.apache.fop.svg.PDFTranscoderbatik-rasterizer.jar

编辑:

虽然简单的命令行编译只适用于唯一的,但它正在做某种类装入器魔术来找到所有必要的类。在更现实的情况下(使用Ant构建项目),您必须手动查找类。它们可以从蜡染项目FOP项目中找到。从 Batik 中,您需要编译和运行batik-rasterizer.jarbatik-1.7.zipfop-1.1.zipbatik-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

答案 2

我终于设法找到了合适的代码行来使用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
  • 蜡染-所有-1.7.jar
  • commons-io-1.3.1.jar
  • 共享资源-日志记录-1.0.4.jar
  • fop-0.95.jar
  • log4j-1.2.15.jar
  • xml-apis-ext.jar
  • xmlgraphics-commons-1.3.1.jar