Convert SVG to PDF
Asked Answered
K

5

27

How would one go about converting a SVG file to a PDF programatically? (I need to alter the SVG in certain respects before generating the PDF so simply pre-converting it using a tool won't be sufficient.)

Ideally using Java but Perl or PHP would be fine too.

Obviously I am basically considering Apache FOP and Batik with Java. However no matter how long I search I cannot find a simple introduction on how to do it. Things like SVGConverter have descriptions like "Defines the interface for classes that are able to convert part or all of a GraphicContext", but I don't really know what that means.

I have this feeling there must be an API to do this quite simply, provided by FOP or Batik, but I'm just not able to find it at the moment (or perhaps it really doesn't exist.)

In terms of the supported SVG features I need, the file has some paths which are filled with some linear gradients.

Ideally if I could pass the SVG in as a DOM Document that would be ideal; then I would load my template SVG file, change it as specified by the user, and then generate the PDF.

Kreisler answered 29/7, 2011 at 15:56 Comment(1)
See here for linked APIs: #6611292Mayfair
G
22

Thanks to Adrian for showing how the Batik rasterizer API is supposed to be used. However, I needed a more lightweight solution--- I can't write to temporary files, and I want fewer dependencies. So, starting from the methods he pointed to, I found a way to access the lower-level code to do the conversion and nothing else.

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

The compile-and-run commands are

javac -cp batik-rasterizer.jar -d build Test.java
java -cp build:batik-rasterizer.jar Test

The important point is that TranscoderInput and TranscoderOutput can work with any InputStream and OutputStream, not just file streams. Note that one of the constructors takes a org.w3c.dom.Document, which means that you don't even need to serialize an SVG DOM into an SVG string, saving an additional step.

This version also doesn't write anything to stdout/stderr, unlike the high-level API.

For JPEG, PNG, or TIFF output, replace org.apache.fop.svg.PDFTranscoder with org.apache.batik.transcoder.image.JPEGTranscoder, PNGTranscoder, or TIFFTranscoder (note that these raster formats are in a different package).

(I'm not quite sure how Java finds the org.apache.batk.transcoder.* and org.apache.fop.svg.PDFTranscoder classes, since I don't see them in the batik-rasterizer.jar.)

Edit:

Although the simple commandline-compilation works with the batik-rasterizer.jar only, it's doing some sort of classloader magic to find all the necessary classes. In a more realistic case (building a project with Ant), you have to find the classes by hand. They can be found in batik-1.7.zip from the Batik project and fop-1.1.zip from the FOP project. From Batik, you need to compile with batik-transcoder.jar and run with

  • 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

From FOP, you need to compile with fop.jar and run with

  • fop.jar
  • avalon-framework-4.2.0.jar
  • xmlgraphics-commons-1.5.jar
Grenville answered 10/7, 2013 at 20:51 Comment(0)
K
6

I finally managed to find the appropriate lines of code to solve this using the Batik.

You need to have the SVG file and the resulting PDF as files on the disk, i.e. I couldn't find a way to do it in-memory (I am writing a HTTP Servlet so I have no intrinsic need to write anything as a file, ideally I would stream the result to the HTTP client). I used File.createTemporaryFile to create a file to dump out my SVG to a file, and for the resulting PDF to be written to.

So the lines I used are the following:

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

And I have the following JARs (search using Google to find the projects and download them):

  • 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
Kreisler answered 11/8, 2011 at 14:25 Comment(0)
W
4

you will need a libray for rendering svg's and pdf's. I recommend SVG salamander for the former, and iText for the latter. With svg salamander you can to read the svg and create an image object, and with itext you can write that image to a pdf.

Whitacre answered 29/7, 2011 at 17:31 Comment(0)
E
1

I use Altsoft Xml2PDF. If I understood correctly all your needs and requirement, you'd better try their Server version of Xml2PDF.

Extravehicular answered 13/3, 2012 at 15:32 Comment(1)
Thanks for the tip! Alas I am deploying on Linux and this solution seems to be Windows-only.Kreisler
S
1

All you need is phantomjs. You don't need the unwieldy Batik for this at all; just get to a point where you can run phantomjs, calling rasterize.js, using the url of the pdf as a source, and a location as the output. Depending on what you want to do with the .pdf, you don't even need Java.

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

Look at the part starting with "Beside PNG format, PhantomJS supports JPEG, GIF, and PDF."

Snips answered 23/4, 2014 at 18:15 Comment(1)
This is pretty creative but in general, this probably isn't the preferable route. Depending on the use case, you'll likely want to retain the vectors from SVG instead of rasterizing the document.Achaea

© 2022 - 2024 — McMap. All rights reserved.