【问题标题】:Multi-page PDF generation from SVG with Java and Apache Batik使用 Java 和 Apache Batik 从 SVG 生成多页 PDF
【发布时间】:2016-08-30 03:34:57
【问题描述】:

我有两个简单的 SVG 文档,我想将它们转换为 PDF,这样每个文档都位于 PDF 的一页上。

我的第一个 SVG 文档有两个如下所示的矩形:

第二个是黑色圆圈。

代码如下:

import java.io.*;
import org.apache.batik.anim.dom.*;
import org.apache.batik.transcoder.*;
import org.w3c.dom.*;

public class MultiPagePdf {

  public static void main(String[] args) {

    MultiPagePDFTranscoder transcoder = new MultiPagePDFTranscoder();
    try {
      final DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
      SVGOMDocument doc1 = (SVGOMDocument) impl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);

      // 1st rectangle in doc1
      Element el = doc1.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect");
      el.setAttributeNS(null, "width", "60");
      el.setAttributeNS(null, "height", "60");
      el.setAttributeNS(null, "fill", "none");
      el.setAttributeNS(null, "stroke", "blue");
      SVGOMSVGElement docEl = (SVGOMSVGElement) doc1.getDocumentElement();
      docEl.appendChild(el);

      // 2nd rectangle in doc1
      Element ell = doc1.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect");
      ell.setAttributeNS(null, "x", "50");
      ell.setAttributeNS(null, "y", "50");
      ell.setAttributeNS(null, "width", "25");
      ell.setAttributeNS(null, "height", "25");
      ell.setAttributeNS(null, "fill", "green");
      docEl.appendChild(ell);

      final DOMImplementation impl2 = SVGDOMImplementation.getDOMImplementation();
      SVGOMDocument doc2 = (SVGOMDocument) impl2.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
      // circle in doc2
      Element el2 = doc2.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "circle");
      el2.setAttributeNS(null, "cx", "130");
      el2.setAttributeNS(null, "cy", "100");
      el2.setAttributeNS(null, "r", "50");
      SVGOMSVGElement docEl2 = (SVGOMSVGElement) doc2.getDocumentElement();
      docEl2.appendChild(el2);

      OutputStream outputStream = new FileOutputStream(new File("/C:/Users/ah/Documents/simpleMulti.pdf"));
      TranscoderOutput transcoderOutput = new TranscoderOutput(outputStream);

      Document[] doccs = { doc1, doc2 };
      transcoder.transcode(doccs, null, transcoderOutput); // generate PDF doc
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

我已经打印了两个 SVG 文档,它们看起来应该是这样的:

第一个 SVG 文档:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="text/ecmascript" zoomAndPan="magnify" contentStyleType="text/css" preserveAspectRatio="xMidYMid meet" version="1.0">
    <rect fill="none" width="60" height="60" stroke="blue"/>
    <rect fill="green" x="50" width="25" height="25" y="50"/>
</svg>

第二个 SVG 文档:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="text/ecmascript" zoomAndPan="magnify" contentStyleType="text/css" preserveAspectRatio="xMidYMid meet" version="1.0">
    <circle r="50" cx="130" cy="100"/>
</svg>

我使用 Apache FOP 找到了 a code that should be doing what I'm after;我有以下代码来生成 PDF:

import java.io.*;
import java.util.*;
import org.apache.batik.transcoder.*;
import org.apache.fop.*;
import org.apache.fop.svg.*;
import org.w3c.dom.*;

public class MultiPagePDFTranscoder extends AbstractFOPTranscoder {

  protected PDFDocumentGraphics2D graphics = null;
  protected Map<String, Object> params = null;

  public MultiPagePDFTranscoder() {
    super();
  }

  protected void transcode(Document[] documents, String uri, TranscoderOutput output) throws TranscoderException {
    graphics = new PDFDocumentGraphics2D(isTextStroked());
    graphics.getPDFDocument().getInfo().setProducer("Apache FOP Version " + Version.getVersion() + ": PDF Transcoder for Batik");

    try {
      OutputStream out = output.getOutputStream();
      if (!(out instanceof BufferedOutputStream)) {
        out = new BufferedOutputStream(out);
      }
      for (int i = 0; i < documents.length; i++) {
        Document document = documents[i];
        super.transcode(document, uri, null);
        int tmpWidth = 300;
        int tmpHeight = 300;
        if (i == 0) {
          graphics.setupDocument(out, tmpWidth, tmpHeight);
        } else {
          graphics.nextPage(tmpWidth, tmpHeight);
        }

        graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
        graphics.transform(curTxf);
        this.root.paint(graphics);
      }
      graphics.finish();
    } catch (IOException ex) {
      throw new TranscoderException(ex);
    }
  }
}

PDF 文件已生成,但我有两个问题。

  1. SVG 元素的平移和缩放不正确。

  2. 在第二页上,存在第一个文档(我尝试了多页,所有以前的文档都存在于当前页面上)。

我使用 Apache FOP 2.1 和 Apache Batik 1.8。

对于这两个问题的任何帮助将不胜感激。 对于我的整体任务(将 SVG 转换为多页 PDF),我也愿意接受其他解决方案。

【问题讨论】:

    标签: java pdf svg apache-fop batik


    【解决方案1】:

    我遇到了类似的问题。我采用的方法是使用 Batik 中的 SVGConverter 应用程序 (org.apache.batik.apps.rasterizer.SVGConverter) 将单个 SVG 转换为 PDF,然后使用 PDFBox (org.apache. pdfbox.multipdf.PDFMergerUtility)。

    将 SVG 转换为单页 PDF:

    File outputFile = new File(pdfPath);
    SVGConverter converter = new SVGConverter();
    converter.setDestinationType(DestinationType.PDF);
    converter.setSources(new String[] { svgPath });
    converter.setDst(outputFile);
    converter.execute();
    

    将 PDF 合并在一起:

    File pdffile = new File(multipagepdfPath);
    PDFMergerUtility pdf = new PDFMergerUtility();
    pdf.setDestinationFileName(pdffile.getPath());
    pdf.addSource(page1pdffile);
    pdf.addSource(page2pdffile);
    pdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
    //The memory settings depend on if you want to use RAM or Temp files.
    

    如果您找到更好的解决方案,请告诉我。 我遇到的主要问题是转换器应用程序是 Batik 中唯一可以转换为 pdf 并保持正确大小的应用程序。

    【讨论】:

    • 您是否找到了更好的解决方案,如何在不单独创建每个 PDF 并最终合并为一个的情况下创建此类 PDF?性能呢?我必须生成大约 3 000 页的 PDF。每个页面都基于相同的 SVG,但内容有所变化。
    【解决方案2】:

    rsvg-convert 可以将多个 svg-document 转换为一个 PDF。

    rsvg-convert -f pdf -o out.pdf file1.svg file2.svg file3.svg
    

    或文件夹中的所有文件:

      rsvg-convert -f pdf -o out.pdf *.svg
    

    虽然不知道如何用 Java 做到这一点。只是一个想法......

    【讨论】:

      猜你喜欢
      • 2016-11-09
      • 2018-05-10
      • 2015-03-23
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 2017-10-17
      • 2022-11-25
      • 1970-01-01
      相关资源
      最近更新 更多