PDFBox 2.0.27:从源文档插页后关闭源文档仍可用的方法
问题:PDFBox 2.0.27提取源文档页面到目标文档,关闭源文档后页面失效
在构建文档处理流水线时,需要从源文档(donor document)中提取页面插入到目标文档。目前所有克隆源页面的示例,在源文档关闭后均无法正常工作。需要实现**打开源文档→提取页面插入目标文档→关闭源文档(或超出作用域时自动关闭)**的功能,使用PDFBox 2.0.27版本。
尝试过的方案
方案1:直接克隆页面字典(参考旧方案)
URL donorUrl = this.class.classLoader.getResource("files/DonorDocument.pdf"); File donorFile = new File(donorUrl.toURI()); PDDocument donorDocument = PDDocument.load(donorFile); PDPage donorPage = donorDocument.getPage(0); // 尝试按旧方案克隆页面 COSDictionary donorDictionary = donorPage.getCOSObject(); // 原方案中的getCOSDictionary方法已不存在 COSDictionary newPageDictionary = new COSDictionary(donorDictionary); newPageDictionary.removeItem(COSName.ANNOTS); PDPage newPage = new PDPage(newPageDictionary); targetDocument.addPage(newPage); donorDocument.close(); // 此时获取的页面已失效,因为源文档已关闭 targetDocument.getPage(targetDocument.getNumberOfPages() - 1);
方案2:使用PDFCloneUtility克隆页面字典
PDFCloneUtility cloner = new PDFCloneUtility(donorDocument); COSBase clonedDocument = cloner.cloneForNewDocument(donorPage.getCOSObject()); COSDictionary clonedDictionary = (COSDictionary) clonedDocument; COSDictionary newPageDict = new COSDictionary(clonedDictionary); PDPage newPage = new PDPage(newPageDict); targetDocument.addPage(clonePage); donorDocument.close(); // 获取的页面仍失效 targetDocument.getPage(targetDocument.getNumberOfPages() - 1);
方案3:使用PDFCloneUtility的cloneMerge方法
PDFCloneUtility cloner = new PDFCloneUtility(donorDocument); PDPage clonePage = new PDPage(); cloner.cloneMerge(donorPage, clonePage); targetDocument.addPage(clonePage); donorDocument.close(); // 获取的页面仍失效 targetDocument.getPage(targetDocument.getNumberOfPages() - 1);
补充说明:该操作是流水线中的一个步骤,方法执行完后退出。若不手动关闭源文档,它会在超出作用域时自动关闭,但无论哪种方式,目标文档中的页面都会失效。
正确解决方案:使用importPage方法导入页面
问题根源在于:之前的方案仅克隆了页面的字典结构,但页面依赖的资源(如字体、图片、表单等)仍属于源文档,源文档关闭后这些资源会被释放,导致目标文档中的页面无法正常访问。
PDFBox 2.x提供了PDDocument.importPage()方法,该方法会自动将页面及其所有依赖资源复制到目标文档中,确保源文档关闭后目标文档的页面仍能正常使用。同时推荐使用try-with-resources语法自动管理源文档的关闭,避免资源泄漏。
URL donorUrl = this.getClass().getClassLoader().getResource("files/DonorDocument.pdf"); File donorFile = new File(donorUrl.toURI()); // 使用try-with-resources自动关闭源文档 try (PDDocument donorDocument = PDDocument.load(donorFile)) { PDPage donorPage = donorDocument.getPage(0); // 导入页面到目标文档,自动复制所有依赖资源 PDPage importedPage = targetDocument.importPage(donorPage); // 可选:对导入的页面进行修改操作 // ... // 将导入的页面添加到目标文档 targetDocument.addPage(importedPage); } // 此时访问目标文档的页面完全正常 PDPage validPage = targetDocument.getPage(targetDocument.getNumberOfPages() - 1);
替代方案:正确使用PDFCloneUtility
若需要更精细的控制,也可以使用PDFCloneUtility,但需确保克隆后的页面资源正确关联到目标文档:
URL donorUrl = this.getClass().getClassLoader().getResource("files/DonorDocument.pdf"); File donorFile = new File(donorUrl.toURI()); try (PDDocument donorDocument = PDDocument.load(donorFile)) { PDPage donorPage = donorDocument.getPage(0); PDFCloneUtility cloner = new PDFCloneUtility(donorDocument); // 克隆页面对象,用于新文档 COSBase clonedPageBase = cloner.cloneForNewDocument(donorPage.getCOSObject()); PDPage clonedPage = new PDPage((COSDictionary) clonedPageBase); // 添加到目标文档,PDFBox会自动处理资源引用 targetDocument.addPage(clonedPage); } // 目标文档的页面可正常访问 PDPage validPage = targetDocument.getPage(targetDocument.getNumberOfPages() - 1);
内容的提问来源于stack exchange,提问作者DavesPlanet
相关产品推荐
相关产品推荐

