简体   繁体   English

使用Java和Apache Batik从SVG生成多页PDF

[英]Multi-page PDF generation from SVG with Java and Apache Batik

I have two simple SVG documents that I want to convert to a PDF such that each document is on one page in the PDF. 我有两个简单的SVG文档,我想将其转换为PDF,以便每个文档都在PDF的一个页面上。

My first SVG document has two rectangles that look as follow: 我的第一个SVG文档有两个矩形,如下所示:

第一个SVG文档

and the second one is a black circle. 第二个是黑色圆圈。

The code looks as follow: 代码如下:

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();
    }
  }
}

I've printed both SVG documents and they look as they should: 我已经打印了两个SVG文档,它们看起来应该是:

1st SVG Document: 第一个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>

2nd SVG Document: 第二篇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>

I found a code that should be doing what I'm after using Apache FOP; 我找到了一个应该在使用Apache FOP 之后做的事情的代码 ; I have the following code to generate the PDF: 我有以下代码来生成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);
    }
  }
}

The PDF file is generated, but I have two problems with it. 生成PDF文件,但我有两个问题。

  1. The translation and scale of the SVG elements are not correct. SVG元素的转换和缩放不正确。

  2. On the second page, the first document is present (I've tried with multiple pages, and all the previous documents are present on the current page). 在第二页上,存在第一个文档(我尝试过多个页面,所有以前的文档都出现在当前页面上)。

生成的PDF文档。

I use Apache FOP 2.1 with Apache Batik 1.8. 我使用Apache FOP 2.1和Apache Batik 1.8。

Any help with either problem would be highly appreciated. 任何问题的任何帮助将受到高度赞赏。 I'm also open to other solutions to my overall task (converting SVGs to multi-paged PDF). 我也对我的整体任务(将SVG转换为多页PDF)的其他解决方案持开放态度。

I had a similar problem. 我遇到了类似的问题。 The way I went about it was to use the SVGConverter app in Batik (org.apache.batik.apps.rasterizer.SVGConverter) to convert the single SVG to PDF then stick them together into one file using PDFBox (org.apache.pdfbox.multipdf.PDFMergerUtility). 我采用的方法是使用Batik中的SVGConverter应用程序(org.apache.batik.apps.rasterizer.SVGConverter)将单个SVG转换为PDF,然后使用PDFBox (org.apache.pdfbox)将它们粘贴到一个文件中。 multipdf.PDFMergerUtility)。

Convert SVG to single page PDF(s): 将SVG转换为单页PDF(s):

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

Join the PDFs together: 将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.

If you find a better solution please let me know. 如果您找到更好的解决方案,请告诉我。 The main problem I had was that the converter app is the only one in Batik that converts to pdf and keeps the sizes correctly. 我遇到的主要问题是转换器应用程序是Batik中唯一一个转换为pdf并正确保持大小的应用程序。

rsvg-convert can turn multiple svg-documents into a single PDF. rsvg-convert可以将多个svg文档转换为单个PDF。

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

or for all files in a folder: 或者对于文件夹中的所有文件:

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

Don't know how to do this with Java though. 不过不知道如何用Java做到这一点。 Just a thought... 只是一个想法...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM