iText:从现有 PDF 导入带样式的文本和信息

iText: Importing styled Text and informations from an existing PDF

我正在使用 iText 生成 PDF,它工作正常。但我需要一种方法在某个时候从现有 PDF 导入 html 样式信息。 我知道我可以使用 XMLWorker class 直接从我自己的文档中的 html 生成文本。但是因为我不确定它是否真的支持我希望解决的所有 html 功能。 因此,使用 XSLT 从 html 生成 PDF。然后应将此 PDF 的内容复制到我的文档中。 书中描述了两种方法("iText in Action")。 一种解析 PDF 并使用 PdfReaderContentParser 和 TextExtractionStrategy 从文档中获取文本(或其他信息)的方法。 它看起来像这样:

PdfReader reader = new PdfReader(pdf);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
TextExtractionStrategy strategy;
for(int i=1;i<=reader.getNumberOfPages();i++){
strategy = parser.processContent(i, new LocationTextExtractionStrategy());
document.add(new Chunk(strategy.getResultantText()));
}

但这只会将纯文本打印到文档中。显然还有更多的 ExtractionStrategys,也许其中之一正是我想要的,但我还没有找到它。

第二种方法是将 PDF 每一面的 itextpdf.text.Image 复制到您的文档中。这显然不是一个好主意,因为即使现有 PDF 中只有一行文本,它也会将整个页面添加到您的文档中。它是这样完成的:

PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
PdfReader reader = new PdfReader(pdf);
PdfImportedPage page;
for(int i=1;i<=reader.getNumberOfPages();i++){
page = writer.getImportedPage(reader,i);
document.add(Image.getInstance(page));
}

就像我说的那样,这也会复制 PDF 末尾的所有空行,但我需要在最后一行文本之后立即继续我的文本。 如果我可以将此 itext.text.Image 转换为 java.awt.BufferedImage 我可以使用 getSubImage();以及我可以从 PDF 中提取的信息以删除所有空行。但是我找不到解决这个问题的方法。

这是我找到的两种方法。但是因为 none 适合我的目的,因为我的问题是: 有没有一种方法可以导入除最后空行之外的所有内容,但包括文本样式信息、表格和使用 iText 从 PDF 到我的文档的所有其他内容?

您可以 trim 将 XSLT 生成的 PDF 清空 space,然后按照您的代码导入 trimmed 页面。

示例代码

以下代码借鉴了我对Using iTextPDF to trim a page's whitespace的回答中的代码。但是,与那里的代码相反,我们必须操纵媒体框,而不是裁剪框,因为这是 PdfWriter.getImportedPage.

唯一尊重的框

在从给定 PdfReader 导入页面之前,使用此方法对其进行裁剪:

static void cropPdf(PdfReader reader) throws IOException
{
    int n = reader.getNumberOfPages();
    for (int i = 1; i <= n; i++)
    {
        PdfReaderContentParser parser = new PdfReaderContentParser(reader);
        MarginFinder finder = parser.processContent(i, new MarginFinder());
        Rectangle rect = new Rectangle(finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());

        PdfDictionary page = reader.getPageN(i);
        page.put(PdfName.MEDIABOX, new PdfArray(new float[]{rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}));
    }
}

(摘自ImportPageWithoutFreeSpace.java

扩展渲染监听器 MarginFinder 是从上面链接的问题中提取的。您可以在此处找到副本:MarginFinder.java.

示例运行

使用此代码

PdfReader readerText = new PdfReader(docText);
cropPdf(readerText);
PdfReader readerGraphics = new PdfReader(docGraphics);
cropPdf(readerGraphics);
try (   FileOutputStream fos = new FileOutputStream(new File(RESULT_FOLDER, "importPages.pdf")))
{
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, fos);
    document.open();
    document.add(new Paragraph("Let's import 'textOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
    document.add(Image.getInstance(writer.getImportedPage(readerText, 1)));
    document.add(new Paragraph("and now 'graphicsOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
    document.add(Image.getInstance(writer.getImportedPage(readerGraphics, 1)));
    document.add(new Paragraph("That's all, folks!", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));

    document.close();
}
finally
{
    readerText.close();
    readerGraphics.close();
}

(摘自ImportPageWithoutFreeSpace.java中的单元测试方法testImportPages

我从 docText 文档中导入了两个页面

以及 docGraphics 文档中的页面

进入一个新文档,在之前、之间和之后添加一些文本。结果:

如您所见,保留了源样式,但丢弃了 space 周围的免费样式。