Drawing vector images on PDF with PDFBox

前端 未结 3 701
夕颜
夕颜 2021-02-13 20:41

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.getDocumen         


        
相关标签:
3条回答
  • 2021-02-13 20:52

    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));
    
    0 讨论(0)
  • 2021-02-13 20:53

    The final working solution for me that loads an SVG file and overlays it on a PDF file (this renders the SVG in a 500x500 box at (0,0) coordinate which is bottom left of the PDF document):

    package com.example.svgadder;
    
    import java.io.*;
    import java.nio.*;
    
    import org.apache.pdfbox.pdmodel.*;
    import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
    import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
    
    import de.rototor.pdfbox.graphics2d.PdfBoxGraphics2D;
    
    import java.awt.geom.AffineTransform;
    
    import com.kitfox.svg.SVGDiagram;
    import com.kitfox.svg.SVGException;
    import com.kitfox.svg.SVGUniverse;
    
    public class App 
    {
        public static void main( String[] args ) throws Exception {
            
            App app = new App();
    
        }
    
        public App() throws Exception {
            
            // loading PDF and SVG files
    
            File pdfFile = new File("input.pdf");
            File svgFile = new File("input.svg");
    
            PDDocument doc = PDDocument.load(pdfFile);
            PDPage page = doc.getPage(0);
    
            SVGUniverse svgUniverse = new SVGUniverse();
            SVGDiagram diagram = svgUniverse.getDiagram(svgUniverse.loadSVG(f.toURL()));
            
            PdfBoxGraphics2D graphics = new PdfBoxGraphics2D(doc, 500, 500);
    
            try {
                diagram.render(graphics);
            } finally {
                graphics.dispose();
            }
    
            PDFormXObject xform = graphics.getXFormObject();
    
            try (PDPageContentStream contentWriter = new PDPageContentStream(doc, page, AppendMode.APPEND, false)) {
    
                AffineTransform transform = AffineTransform.getTranslateInstance(0, 0);
                xform.setMatrix(transform);
                contentWriter.drawForm(xform);
            }
    
            doc.save("res.pdf");
            doc.close();
        }
    }
    

    Please use svgSalamander from here: https://github.com/mgarin/svgSalamander

    Please use what Coemgenus suggested for scaling your final overlaid SVG. I tried the 2nd option and it works well.

    Nirmal

    0 讨论(0)
  • 2021-02-13 21:06

    I do this, but not directly. In first transform your SVG documents in PDF documents with FOP librairy and Batik. https://xmlgraphics.apache.org/fop/dev/design/svg.html.

    In second times, you can use LayerUtility in pdfbox to transform your new pdf document in PDXObjectForm. After that, just needs to include PDXObjectForm in your final pdf documents.

    0 讨论(0)
提交回复
热议问题