【问题标题】:Drawing vector images on PDF with PDFBox使用 PDFBox 在 PDF 上绘制矢量图像
【发布时间】:2015-10-21 11:23:10
【问题描述】:

我想使用 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。

【问题讨论】:

  • 快速提示,位图(.png、.jpg 等)与矢量图像 (.svg) 完全不同,并且很可能在 PDFBox 库中实现完全不同。
  • @insidesin 感谢您的评论。我认为实现方式也不同,因为矢量图像不能作为位图读取......但我似乎无法找到成功加载矢量图像并将其绘制为 PDF 的人。我用 iText 成功地做到了,在 PDFBox 中也必须有办法做到这一点......
  • 是的,我已经使用了很多 iText,鉴于我刚才快速浏览了 API,它比 PDFBox 更容易阅读......我认为 iText 很难.
  • “加载矢量图像并绘制它们”的问题在于就像位图图像一样您需要解释数据(您并不完全了解这些数据——显然PDFBox 在必要时方便地将位图图像转换为正确的 PDF 语法)。因此,要添加 SVG 图像,您需要编写代码以将 所有 SVG 命令 转换为其 PDF 等效项(包括将过滤器、阴影和箭头等“元”内容扩展为基元)。对于 WMF,同样如此。对于EPS,同样如此。对于 AI ......对于 CorelDraw ......好吧,我想你明白了。
  • .. 也就是说,一些搜索建议使用 Batik 作为中间体来创建一个单独的 PDF,然后可以将该 PDF 插入到您的 PDF 中。

标签: java image pdf vector pdfbox


【解决方案1】:

请参阅 pdfbox-graphics2d 库,在 this Jira 中吹捧。

您可以通过BatikSalamander 或其他方式将SVG 绘制到与iText 的template.createGraphics() 平行的类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));

【讨论】:

  • 如果要添加到现有 PDF,请在 PDPageContentStream 构造函数中将第五个参数设置为 true。 (参见 javadoc 为什么)
  • 要将 Salamander 与 SVG 文件一起使用,您可以创建一个 SVGUniverse,然后创建一个 SVGDiagram(参见 stackoverflow.com/questions/2397492/svg-salamander-example),然后执行 diagram.render(graphics);
  • 你好。 drawSVG(svg, graphics, x, y); 你能说得更具体点吗:即..如何用 Batik 绘制 SVG 文件?
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    对我来说,加载 SVG 文件并将其覆盖在 PDF 文件上的最终工作解决方案(这会将 SVG 呈现在位于 PDF 文档左下角 (0,0) 坐标的 500x500 框中):

    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。我尝试了第二个选项,效果很好。

    普通

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-07
      • 1970-01-01
      • 1970-01-01
      • 2018-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多