Java iText PDF 中的矢量图形

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/408042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:16:40  来源:igfitidea点击:

Vector graphics in iText PDF

javaimagepdfvectoritext

提问by Marcus Downing

We use iText to generate PDFs from Java (based partly on recommendations on this site). However, embedding a copy of our logo in an image format like GIF results in it looking a bit strange as people zoom in and out.

我们使用 iText 从 Java 生成 PDF(部分基于本网站的推荐)。但是,将我们徽标的副本嵌入到 GIF 等图像格式中,会导致当人们放大和缩小时,它看起来有点奇怪。

Ideally we'd like to embed the image in a vector format, such as EPS, SVG or just a PDF template. The website claims that EPS support has been dropped, that embedding a PDF or PS within a PDF can result in errors, and it doesn't even mention SVG.

理想情况下,我们希望以矢量格式嵌入图像,例如 EPS、SVG 或只是一个 PDF 模板。该网站声称已取消对 EPS 的支持,在 PDF 中嵌入 PDF 或 PS 可能会导致错误,甚至没有提到 SVG。

Our code uses the Graphics2D API rather than iText directly, but we'd be willing to break out of AWT mode and use iText itself if it achieved the result. How can this be done?

我们的代码直接使用 Graphics2D API 而不是 iText,但如果达到了结果,我们愿意打破 AWT 模式并使用 iText 本身。如何才能做到这一点?

采纳答案by Darin Dimitrov

According to the documentationiText supports the following image formats: JPEG, GIF, PNG, TIFF, BMP, WMF and EPS. I don't know if this might be of any help but I have successfully used iTextSharpto embed vector WMFimage in a pdf file:

根据文档,iText 支持以下图像格式:JPEG、GIF、PNG、TIFF、BMP、WMF 和 EPS。我不知道这是否有帮助,但我已经成功地使用iTextSharp将矢量WMF图像嵌入到 pdf 文件中:

C#:

C#:

using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

public class Program 
{

    public static void Main() 
    {
        Document document = new Document();
        using (Stream outputPdfStream = new FileStream("output.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
        using (Stream imageStream = new FileStream("test.wmf", FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            PdfWriter.GetInstance(document, outputPdfStream);
            Image wmf = Image.GetInstance(imageStream);
            document.Open();
            document.Add(wmf);
            document.Close();
        }
    }
}

回答by David Koelle

I recently learned that you can send your Graphics2D object directly to iText, and the resulting PDF files are just as good as scalable vector graphics. From your post, it sounds like this might solve your problem.

我最近了解到您可以将 Graphics2D 对象直接发送到 iText,生成的 PDF 文件与可缩放矢量图形一样好。从您的帖子中,听起来这可能会解决您的问题。

Document document = new Document(PageSize.LETTER);
PdfWriter writer = null;
try {
    writer = PdfWriter.getInstance(document, new FileOutputStream(your file name));
} catch (Exception e) {
    // do something with exception
}

document.open();

PdfContentByte cb = writer.getDirectContent();
PdfTemplate tp = cb.createTemplate(width, height);
Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());

// Create your graphics here - draw on the g2 Graphics object

g2.dispose();
cb.addTemplate(tp, 0, 100); // 0, 100 = x,y positioning of graphics in PDF page
document.close();

回答by clayzermk1

I found a couple of examples by the iText author that use the Graphics2D API and the Apache Batik library to draw the SVG in a PDF.

我找到了 iText 作者的几个示例,它们使用 Graphics2D API 和 Apache Batik 库在 PDF 中绘制 SVG。

http://itextpdf.com/examples/iia.php?id=269

http://itextpdf.com/examples/iia.php?id=269

http://itextpdf.com/examples/iia.php?id=263

http://itextpdf.com/examples/iia.php?id=263

For my purposes, I needed to take a string of SVG and draw that in a PDF at a certain size and location while maintaining the vector nature of the image (no rasterization).

出于我的目的,我需要取一串 SVG 并将其绘制在特定大小和位置的 PDF 中,同时保持图像的矢量性质(无光栅化)。

I wanted to bypass the SVG file that seems prevalent in the SAXSVGDocumentFactory.createSVGDocument() functions. I found the following post helpful for using a SVG text string instead of a flat file.

我想绕过 SAXSVGDocumentFactory.createSVGDocument() 函数中似乎普遍存在的 SVG 文件。我发现以下帖子有助于使用 SVG 文本字符串而不是平面文件。

http://batik.2283329.n4.nabble.com/Parse-SVG-from-String-td3539080.html

http://batik.2283329.n4.nabble.com/Parse-SVG-from-String-td3539080.html

You have to create a StringReader from your String and pass that to the SAXSVGDocumentFactory#createDocument(String, Reader) method. The URI that you pass as the first parameter as a String will be the base document URI of the SVG document. This should only be important if your SVG references any external files.

Best regards,

Daniel

您必须从您的 String 创建一个 StringReader 并将其传递给 SAXSVGDocumentFactory#createDocument(String, Reader) 方法。您作为字符串的第一个参数传递的 URI 将是 SVG 文档的基本文档 URI。这仅在您的 SVG 引用任何外部文件时才重要。

此致,

丹尼尔

Java Source derived from the iText examples:

从 iText 示例派生的 Java 源代码:

// SVG as a text string.
String svg = "<svg>...</svg>";

// Create the PDF document.
// rootPath is the present working directory path.
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(new File(rootPath + "svg.pdf")));
document.open();

// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 1"));
document.add(new Paragraph(" "));

// Boilerplate for drawing the SVG to the PDF.
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
PdfContentByte cb = writer.getDirectContent();

// Parse the SVG and draw it to the PDF.
Graphics2D g2d = new PdfGraphics2D(cb, 725, 400);
SVGDocument chart = factory.createSVGDocument(rootPath, new StringReader(svg));
GraphicsNode chartGfx = builder.build(ctx, chart);
chartGfx.paint(g2d);
g2d.dispose();

// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 2"));
document.add(new Paragraph(" "));

document.close();

Note that this will draw a SVG to the PDF you are working on. The SVG appears as a floating layer above text. I'm still working on moving/scaling it and having it rest inline with text, but hopefully that is outside the immediate scope of the question.

请注意,这会将 SVG 绘制到您正在处理的 PDF 中。SVG 显示为文本上方的浮动层。我仍在努力移动/缩放它并使其与文本内联,但希望这超出了问题的直接范围。

Hope this was able to help.

希望这能有所帮助。

Cheers

干杯

EDIT: I was able to implement my svg as an inline object using the following. The commented lines are for adding a quick border to check positioning.

编辑:我能够使用以下内容将我的 svg 实现为内联对象。注释行用于添加快速边框以检查定位。

SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
SVGDocument svgDoc = factory.createSVGDocument(rootPath, new StringReader(svg));
PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width")), Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height")));
Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
GraphicsNode chartGfx = builder.build(ctx, svgDoc);
chartGfx.paint(g2d);
g2d.dispose();
Image svgImg = new ImgTemplate(svgTempl);
svgImg.setAlignment(Image.ALIGN_CENTER);
//svgImg.setBorder(Image.BOX);
//svgImg.setBorderColor(new BaseColor(0xff, 0x00, 0x00));
//svgImg.setBorderWidth(1);
document.add(svgImg);

回答by Nick Russler

This what i derived from posts i found here and the official examples:

这是我从我在这里找到的帖子和官方示例中得出的内容:

/**
 * Reads an SVG Image file into an com.itextpdf.text.Image instance to embed it into a PDF
 * @param svgPath SVG filepath
 * @param writer PdfWriter instance 
 * @return Instance of com.itextpdf.text.Image holding the SVG file
 * @throws IOException
 * @throws BadElementException
 */
private static Image getSVGImage(String svgPath, PdfWriter writer) throws IOException, BadElementException {
    SVGDocument svgDoc = new SAXSVGDocumentFactory(null).createSVGDocument(null, new FileReader(svgPath));

    // Try to read embedded height and width
    float svgWidth = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width").replaceAll("[^0-9.,]",""));
    float svgHeight = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height").replaceAll("[^0-9.,]",""));

    PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, svgWidth, svgHeight);
    Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
    GraphicsNode chartGfx = (new GVTBuilder()).build(new BridgeContext(new UserAgentAdapter()), svgDoc);
    chartGfx.paint(g2d);
    g2d.dispose();

    return new ImgTemplate(svgTempl);
}

The Image instance can the be added easily to the pdf (in my case as a signature).

Image 实例可以轻松添加到 pdf(在我的情况下作为签名)。

回答by Yahini priya Raja

This worked for me using itext 7.1.3 to render SVG image by SVGConverter.

这对我有用,使用 itext 7.1.3 通过 SVGConverter 渲染 SVG 图像。

PdfWriter writer = new PdfWriter(new FileOutputStream("/home/users/Documents/pdf/new.pdf"));

        PdfDocument pdfDoc = new PdfDocument(writer);

        Document doc = new Document(pdfDoc);

        URL svgUrl = new File(svg).toURI().toURL();

        doc.add(new Paragraph("new pikachu"));                      

        Image image = SvgConverter.convertToImage(svgUrl.openStream(), pdfDoc);                 
        doc.add(image);

        doc.close();

回答by user3327560

The new version of iText is supporting SVG files also. Please refer to thispage.

新版本的 iText 也支持 SVG 文件。请参阅页面。

回答by Rafael S. Fijalkowski

The only way I could make it works is converting the vectorial SVG file to a vectorial PDF file, before inserting it to my itext/openpdf PDF.

我可以使它工作的唯一方法是将矢量 SVG 文件转换为矢量 PDF 文件,然后再将其插入我的 itext/openpdf PDF。

You understood right: I am inserting a vectorial PDF inside my PDF and works like a charm. You can make zoom in and everything works well.

你理解正确:我在我的 PDF 中插入了一个矢量 PDF,并且效果很好。您可以放大,一切正常。

I am using this code in a Spring Boot app:

我在 Spring Boot 应用程序中使用此代码:

public void addVectorToPDF(PdfWriter writer) throws IOException {

    // My SVG image that I converted to PDF format, keeping the vectorial format.
    URL resource = this.getClass().getResource("/resources/my-vectorial-image-pdf-format.pdf");

    PdfReader reader = new PdfReader(resource);

    // Getting the page 01 of the PDF. The PDF has only the
    // SVG image inside, so the page 01 is everything.
    PdfImportedPage page = writer.getImportedPage(reader, 1);

    float posX = 50;
    float posY = 300;
    float scale = 0.75F;
    PdfContentByte canvas = writer.getDirectContent();

    // adding vectorial image pdf to my pdf
    canvas.addTemplate(page, scale, 0, 0, scale, posX, posY);

}

You can use zamzar.com to convert your vectorial SVG to PDF. It worked well for me.

您可以使用 zamzar.com 将您的矢量 SVG 转换为 PDF。它对我来说效果很好。

The solutions with Batik and Graphics2D did not keep the vectorial format in my case.

Batik 和 Graphics2D 的解决方案在我的情况下没有保留矢量格式。