我们在其中一个应用程序中使用 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();
答案 0 :(得分:2)
您共享的 PDF 文件中没有与使用 Overlay
相关的错误。
它使用了一个很少使用的 PDF 功能,但页面继承来自其父节点的资源:PDF 中的页面对象排列在树中,实际页面是叶子;该树中的页面对象本身通常携带定义它的所有信息,但许多页面属性也可以由内部节点携带并由后代页面继承,除非它们覆盖它们。
在你分享你的代码之后,你有一个准备步骤,它会丢失所有继承的信息:当你从 finalOverlayDoc
生成 overlayDocument
时,你本质上是这样做的:
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
。
进一步查看您的代码,我看到您重复将页面对象移动到其他文档的反模式,而不是一次又一次地尊重继承的属性。我想您应该彻底修改该代码,删除该反模式。