繁体   English   中英

用 PDFBox 在 PDF 上绘制矢量图

[英]Drawing vector images on PDF with PDFBox

我想用 Apache PDFBox 在 PDF 上绘制矢量图像。

这是我用来绘制常规图像的代码

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

如果我使用svgwmf图像而不是 png,则生成的 PDF 文档会损坏。

我希望图像成为矢量图像的主要原因是使用 PNG 或 JPG 图像看起来很糟糕,我认为它会以某种方式被压缩,所以看起来很糟糕。 对于矢量图像,这不应该发生(好吧,当我在 Inkscape 中将 svg 路径导出为 PDF 时,它不会发生,矢量路径被保留)。

有没有办法使用 Apache PDFBox 将 svg 或 wmf (或其他矢量)绘制到 PDF ?

如果这很重要,我目前正在使用 PDFBox 1.8。

请参阅此 Jira中吹捧的库pdfbox-graphics2d

您可以通过BatikSalamander或其他方式将 SVG 绘制到与 iText 的template.createGraphics()平行的 class PdfBoxGraphics2D上。 有关示例,请参见 GitHub 页面。

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

而且...如果您还想将 SVG 图形缩放到 25% 大小:

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

我这样做,但不是直接这样做。 首先使用 FOP 库和蜡染在 PDF 文档中转换您的 SVG 文档。 https://xmlgraphics.apache.org/fop/dev/design/svg.html

第二次,您可以使用 pdfbox 中的 LayerUtility 将您的新 pdf 文档转换为 PDXObjectForm。 之后,只需在最终的 pdf 文档中包含 PDXObjectForm 即可。

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

请从这里使用 svgSalamander: https://github.com/mgarin/svgSalamander

请使用 Coemgenus 建议的方法来缩放最终覆盖的 SVG。 我尝试了第二个选项,效果很好。

尼尔马尔

暂无
暂无

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

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