Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing vector images on PDF with PDFBox

I would like to draw a vector image on a PDF with Apache PDFBox.

This is the code I use to draw regular images

PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(1);
PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);

BufferedImage _prevImage = ImageIO.read(new FileInputStream("path/to/image.png"));
PDPixelMap prevImage = new PDPixelMap(document, _prevImage);
contentStream.drawXObject(prevImage, prevX, prevY, imageWidth, imageHeight);

If I use a svg or wmf image instead of png, the resulting PDF document comes corrupted.

The main reason I want the image to be a vector image is that with PNG or JPG the image looks horrible, I think it gets somehow compressed so it looks bad. With vector images this shouldn't happen (well, when I export svg paths as PDF in Inkscape it doesn't happen, vector paths are preserved).

Is there a way to draw a svg or wmf (or other vector) to PDF using Apache PDFBox?

I'm currently using PDFBox 1.8, if that matters.

like image 581
BackSlash Avatar asked Jul 30 '15 07:07

BackSlash


People also ask

Which is better iText or PDFBox?

One major difference is that PDFBox always processes text glyph by glyph while iText normally processes it chunk (i.e. single string parameter of text drawing operation) by chunk; that reduces the required resources in iText quite a lot.

What is PDFBox used for?

Apache PDFBox is an open source Java library that can be used to create, render, print, split, merge, alter, verify and extract text and meta-data of PDF files.

Is PDFBox free to use?

Bookmark this question. Show activity on this post. PDFbox is that PDFbox is the free version.

Is PDFBox thread safe?

Is PDFBox thread safe? No! Only one thread may access a single document at a time. You can have multiple threads each accessing their own PDDocument object.


1 Answers

See the library pdfbox-graphics2d, touted in this Jira.

You can draw the SVG, via Batik or Salamander or whatever, onto the class PdfBoxGraphics2D, which is parallel to iText's template.createGraphics(). See the GitHub page for samples.

PDDocument document = ...;
PDPage page = ...; // page whereon to draw

String svgXML = "<svg>...</svg>";
double leftX = ...;
double bottomY = ...; // PDFBox coordinates are oriented bottom-up!

// I set these to the SVG size, which I calculated via Salamander.
// Maybe it doesn't matter, as long as the SVG fits on the graphic.
float graphicsWidth = ...;
float graphicsHeight = ...;

// Draw the SVG onto temporary graphics.
var graphics = new PdfBoxGraphics2D(document, graphicsWidth, graphicsHeight);
try {
    int x = 0;
    int y = 0;
    drawSVG(svg, graphics, x, y); // with Batik, Salamander, or whatever you like
} finally {
    graphics.dispose();
}

// Graphics are not visible till a PDFormXObject is added.
var xform = graphics.getXFormObject();

try (var contentWriter = new PDPageContentStream(document, page, AppendMode.APPEND, false)) { // false = don't compress
    // XForm objects have to be placed via transform,
    // since they cannot be placed via coordinates like images.
    var transform = AffineTransform.getTranslateInstance(leftX, bottomY);
    xform.setMatrix(transform);

    // Now the graphics become visible.
    contentWriter.drawForm(xform);
}

And ... in case you want also to scale the SVG graphics to 25% size:

// Way 1: Scale the SVG beforehand
svgXML = String.format("<svg transform=\"scale(%f)\">%s</svg>", .25, svgXML);

// Way 2: Scale in the transform (before calling xform.setMatrix())
transform.concatenate(AffineTransform.getScaleInstance(.25, .25));
like image 177
Coemgenus Avatar answered Oct 11 '22 04:10

Coemgenus