在 PDFBox 中使用覆盖后,Adobe 中的 PDF 字体问题

PDF issue with fonts in adobe, after using overlays in PDFBox

我们在我们的一个应用程序中使用了 pdfbox。 一些叠加的 pdf 会导致输出和字体“损坏”。

下面是我用来叠加 pdf 的示例代码。 pdf 有时有不同的页数。 我们将 acroforms 展平并将注释设置为只读。 PDF 页面旋转和 bbox 大小有时设置不同(尤其是扫描仪),因此我们尝试对此进行更正。

    PDDocument baseDocument = PDDocument.load(new File("base.pdf"));
    PDDocument overlayDocument = PDDocument.load(new File("overlay.pdf"));
    Iterator<PDPage> baseDocumentIterator = baseDocument.getPages().iterator();
    Iterator<PDPage> overlayIterator = overlayDocument.getPages().iterator();
    PDDocument finalOverlayDoc = new PDDocument();
    while(baseDocumentIterator.hasNext() && overlayIterator.hasNext()) {
        PDPage backing = baseDocumentIterator.next();
        //locking annotations per page
        List<PDAnnotation> annotations = backing.getAnnotations();
        for (PDAnnotation a :annotations) {
            a.setLocked(true);
            a.setReadOnly(true);
        }
        // setting size so there's no weird overflow issues
        PDRectangle rect = new PDRectangle();
        rect.setLowerLeftX(0);
        rect.setLowerLeftY(0);
        rect.setUpperRightX(backing.getBBox().getWidth());
        rect.setUpperRightY(backing.getBBox().getHeight());
        backing.setCropBox(rect);
        backing.setMediaBox(rect);
        backing.setBleedBox(rect);
        PDPage pg = overlayIterator.next();
        //setting rotation if different. Some scanners cause issues.
        if(backing.getRotation()!= pg.getRotation())
        {
            pg.setRotation(-backing.getRotation());
        }
        finalOverlayDoc.addPage(pg);
    }
    finalOverlayDoc.close();
    //flatten acroform
    PDAcroForm acroForm = baseDocument.getDocumentCatalog().getAcroForm();
    if (acroForm != null) {
        acroForm.flatten();
        acroForm.setNeedAppearances(false);
    }
    Overlay overlay = new Overlay();
    overlay.setOverlayPosition(Overlay.Position.FOREGROUND);
    overlay.setInputPDF(baseDocument);
    overlay.setAllPagesOverlayPDF(finalOverlayDoc);

    Map<Integer, String> ovmap = new HashMap<Integer, String>();
    overlay.overlay(ovmap);
    PDPageTree allOverlayPages = overlayDocument.getPages();
    if(baseDocument.getPages().getCount() < overlayDocument.getPages().getCount()) //Additional pages in the overlay pdf need to be appended to the base pdf.
    {
        for(int i=baseDocument.getPages().getCount();i<allOverlayPages.getCount(); i++)
        {
            baseDocument.addPage(allOverlayPages.get(i));
        }
    }
    PDDocument finalDocument = new PDDocument();
    for(PDPage p: baseDocument.getPages()){
        finalDocument.addPage(p);
    }

    String filename = "examples/merge_pdf_examples/debug.pdf";
    filename = filename + new Date().getTime() + ".pdf";
    finalDocument.save(filename);
    finalDocument.close();
    baseDocument.close();
    overlayDocument.close();

您共享的 PDF 文件中没有与使用 Overlay 有关的错误。

它使用了一个很少使用的 PDF 功能,不过,页面 从其父节点继承 资源:PDF 中的页面对象与实际页面排列在树中是树叶;此树中的页面对象通常本身包含定义它的所有信息,但许多页面属性也可以由内部节点携带并由后代页面继承,除非它们覆盖它们。

在您共享您的代码后,您发现您有一个丢失所有继承信息的准备步骤:当您从 overlayDocument 生成 finalOverlayDoc 时,您实际上是:

while(overlayIterator.hasNext()) {
    PDPage pg = overlayIterator.next();
    //setting rotation if different. Some scanners cause issues.
    finalOverlayDoc.addPage(pg);
}

(OverlayDocuments 测试 testOverlayPreparationExampleBroken)

这里只传输页面对象本身,丢失所有继承的属性。

对于手头的文档,您可以通过将页面资源显式设置为继承的资源来解决此问题:

while(overlayIterator.hasNext()) {
    PDPage pg = overlayIterator.next();
    pg.setResources(pg.getResources());
    //setting rotation if different. Some scanners cause issues.
    finalOverlayDoc.addPage(pg);
}

(OverlayDocuments 测试 testOverlayPreparationFixedExampleBroken)

注意,虽然:这只会显式设置页面 资源,但还有其他可以继承的页面属性。

因此,我建议您根本不要创建新的 PDDocument;不要将 overlayDocument 页面移动到 finalOverlayDoc,而只是将它们原地更改。如果 overlayDocument 的页面多于 baseDocument,您还必须从 overlayDocument 中删除多余的页面。然后在叠加中使用 overlayDocument 而不是 finalOverlayDoc.


进一步查看您的代码,我看到您一次又一次地重复将页面对象移动到其他文档而不尊重继承属性的反模式。我想您应该彻底检查该代码,删除该反模式。