使用 PDFBox 的 addPage() 直接添加来自其他文档的页面会导致内容未正确复制,从而生成空白页;应改用 importPage() 方法将源页面内容完整导入当前文档。
使用 pdfbox 的 `addpage()` 直接添加来自其他文档的页面会导致内容未正确复制,从而生成空白页;应改用 `importpage()` 方法将源页面内容完整导入当前文档。
在使用 Apache PDFBox 进行多 PDF 合并时,一个常见却容易被忽视的陷阱是:直接调用 PDDocument.addPage(PDPage) 添加来自其他 PDDocument 实例的页面,会导致输出 PDF 中对应页面完全空白——尽管页数统计正确、文档结构完整,但视觉上无任何内容渲染。
根本原因在于:addPage() 仅将页面对象(PDPage)的引用加入当前文档的页面树,而该页面底层的资源(如字体、图像、流内容等)仍绑定在原始文档的 COSDocument 和内存缓存中。一旦源文档关闭或其资源被释放(例如 doc.close() 或 GC 回收),目标文档中该页面便失去有效内容来源,最终渲染为空白。
✅ 正确做法是使用 PDDocument.importPage(PDPage) 方法。该方法会深度复制页面内容(包括资源字典、内容流、字体、图像等),将其完全迁移至当前文档的上下文中,确保独立可渲染。
以下是修复后的核心代码示例(兼容 PDFBox 2.x):
立即学习“Java免费学习笔记(深入)”;
// 创建最终合并文档
PDDocument finalDoc = new PDDocument();
// 加载固定页模板(如CGV条款页)
File cgvFile = new File(context.repertoire_advendio + "conf/CGV.pdf");
try (PDDocument cgvDoc = Loader.loadPDF(cgvFile)) {
PDPage cgvTemplate = cgvDoc.getPage(0);
// 遍历待合并的发票PDF文件
File inputDir = new File(context.repertoire_output_docone);
for (String filename : inputDir.list()) {
if (!filename.startsWith("fact_") && !filename.startsWith("agence_fact_")) {
continue;
}
File sourceFile = new File(inputDir, filename);
try (PDDocument sourceDoc = Loader.loadPDF(sourceFile)) {
// 逐页导入(非 addPage!)
for (int i = 0; i < sourceDoc.getNumberOfPages(); i++) {
PDPage sourcePage = sourceDoc.getPage(i);
finalDoc.importPage(sourcePage); // ✅ 关键:使用 importPage
// 插入固定条款页
finalDoc.importPage(cgvTemplate); // ✅ 同样需 import,不可复用 addPage
}
}
}
}
// 保存并关闭
String outputPath = context.repertoire_output_docone
+ "output/docone_" + context.id_legal_entity
+ "_" + context.input_invoice_date.replace("-", "") + ".pdf";
finalDoc.save(outputPath);
finalDoc.close();? 关键注意事项:
- importPage() 返回的是新导入的 PDPage 对象,可选接收(常用于后续调整页码或元数据),但即使忽略返回值,导入动作本身已生效;
- 所有源文档(如 cgvDoc、sourceDoc)必须通过 try-with-resources 或显式 close() 释放,避免内存泄漏与文件句柄占用;
- 不要混用 addPage() 与跨文档页面——即使页面来自同一 PDDocument 实例,若涉及资源复用,也建议统一使用 importPage() 保证健壮性;
- PDFBox 3.x 中 API 保持兼容,importPage() 仍是推荐方式;若使用旧版 1.8,请替换为 copyPage()(行为类似)。
? 总结:addPage() 适用于向当前文档添加本地产出的新页面(如 new PDPage()),而跨文档页面集成必须使用 importPage() ——这是 PDFBox 文档对象模型(PDOM)资源隔离机制决定的硬性约束。理解并遵守这一原则,即可彻底规避“页数正确、内容全空”的典型合并故障。










