使用 PDFBox 从生成的 PDF 复制粘贴文本导致垃圾

Copy-pasting text from generated PDF using PDFBox results in garbage

我有一些代码采用模板 PDF、创建新 PDF、将新 PDF 覆盖在模板 PDF 上并将结果写入流。所有这些都使用 PDFBox 2.0.4.

问题是将生成的 PDF 中的文本复制粘贴到文本编辑器会导致出现垃圾文本。

这只发生在我的代码添加的文本上,原始模板中的文本仍然可以正常工作。我添加的文本是使用自定义字体添加的。

如何修复生成的 PDF 以便可以复制粘贴文本?

SSCCE:

public class PDFTest {

    private static final String FONT = "/fonts/font.ttf";

    public static void main(final String... args) throws IOException, FontFormatException {
        final Overlay overlay = new Overlay();
        overlay.setInputPDF(newDocument("Input text", 400));
        overlay.setAllPagesOverlayPDF(newDocument("Test text", 200));

        try (final PDDocument document = overlay.overlay(new HashMap<>())) {
            document.save("example.pdf");
        }
    }

    private static PDDocument newDocument(final String text, final int offsetY) throws IOException, FontFormatException {
        final PDDocument document = new PDDocument();
        document.addPage(insertTextInPage(document, text, offsetY));
        return document;
    }

    private static PDPage insertTextInPage(final PDDocument document, final String text, final int offsetY) throws IOException, FontFormatException {
        try (final InputStream fontStream = PDFTest.class.getResourceAsStream(FONT)) {
            final PDFont normalFont = PDType0Font.load(document, fontStream);

            final PDPage page = new PDPage();
            try (final PDPageContentStream contentStream = new PDPageContentStream(document, page, APPEND, false)) {
                addTextBlock(contentStream, normalFont, text, offsetY);
            }
            return page;
        }
    }

    private static void addTextBlock(final PDPageContentStream contentStream, final PDFont font, final String text, final int offsetY)
            throws IOException {
        contentStream.beginText();
        contentStream.setFont(font, 16);
        contentStream.newLineAtOffset(20, offsetY);
        contentStream.showText(text);
        contentStream.endText();
    }
}

这是一个已知问题 (PDFBOX-3243),使用子集字体构建的文件(您使用的是非常高效的 PDType0Font.load())在保存之前处于中间状态,这是子集化发生的时间。

适合您的解决方案:要么保存并重新加载,要么保存为虚拟文件。在 Windows 中,我像这样更改了 newDocument,它起作用了:

private static PDDocument newDocument(final String text, final int offsetY) throws IOException, FontFormatException
{
    final PDDocument document = new PDDocument();
    document.addPage(insertTextInPage(document, text, offsetY));
    document.save("nul"); // NEW!
    return document;
}