PDFBox 2.0.28增量保存后添加可见签名报Header无版本信息错误
PDFBox 2.0.28 签名流程中
saveIncremental导致的"Header doesn't contain versioninfo"问题 问题背景
我开发了一个基于PDFBox 2.0.28的Java应用,在给PDF添加签名时遇到异常。流程为:先在文档中创建空表单字段,填充字段内容,最后通过CreateVisibleSignature示例代码添加可见签名。
相关代码片段
主流程代码
// 将内容字节数组写入磁盘 _filesManipulator.writeFil( documentToSigne.Content, baseNameFiles + FilesManipilator.ORIGINAL_PDF); // 检测文档是否包含签名 boolean isConatinSignature = _pdfManipulator.isDocumentContainsSignature(content); if (!isConatinSignature) { // 给PDF添加空字段并保存到磁盘 _pdfManipulator.PrepaireEmptyFieldsToDocument(baseNameFiles + FilesManipilator.ORIGINAL_PDF, baseNameFiles + FilesManipilator.ORIGINAL_PDF, documentToSigne, event.CurrentMemberInfo); } // 填充字段并增量保存到磁盘 _pdfManipulator.populateFieldsInDocument(baseNameFiles + FilesManipilator.ORIGINAL_PDF, baseNameFiles + FilesManipilator.ORIGINAL_PDF, event.CurrentMemberInfo.Configs); // 使用CreateVisibleSignature示例添加签名 _pdfManipulator.addSignatureFormConfigs(baseNameFiles, event, event.CurrentMemberInfo, documentToSigne);
PrepaireEmptyFieldsToDocument方法
public void PrepaireEmptyFieldsToDocument(String pathSource, String pathdestination, DocumentToSignDto documentToSigne, MemberSignerConfigsDto CurrentMemberInfo) throws IOException { PDDocument document = PDDocument.load(new File(pathSource)); PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm(); if (acroForm == null) { acroForm = new PDAcroForm(document); document.getDocumentCatalog().setAcroForm(acroForm); } // 获取需要添加的字段配置列表 List<DocumentMemberConfigDto> LastConfigList = documentToSigne.MemberSignerConfigs.stream() .flatMap(doc -> doc.Configs.stream()) .collect(Collectors.toList()); creatFilds(document, acroForm, LastConfigList); List<DocumentMemberConfigDto> CurrentConfigList = CurrentMemberInfo.Configs.stream() .filter(p -> p.docOrder == documentToSigne.Order) .collect(Collectors.toList()); creatFilds(document, acroForm, CurrentConfigList); document.save(pathdestination); document.close(); }
populateFieldsInDocument方法
public void populateFieldsInDocument(String pathSource, String pathdestination, java.util.List<DocumentMemberConfigDto> configList) throws IOException { PDDocument document = PDDocument.load(new File(pathSource)); // 获取文档的AcroForm PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm(); // 遍历配置列表填充字段 for (DocumentMemberConfigDto config : configList) { PDField field = acroForm.getField(config.id); if (field != null && !config.fieldLibelle.equals("Signature")) { // 设置字段值 } } document.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true); document.getDocumentCatalog().getAcroForm().getCOSObject().setNeedToBeUpdated(true); FileOutputStream fileOutputStream = new FileOutputStream(new File(pathdestination)); document.saveIncremental(fileOutputStream); document.close(); }
问题现象
调用populateFieldsInDocument方法中的document.saveIncremental(fileOutputStream)后,后续签名步骤失败,报错信息如下:
message : [B@4d8a41c1Error while processing the message: Error: Header doesn't contain versioninfo java.io.IOException: Error: Header doesn't contain versioninfo at org.apache.pdfbox.pdfparser.PDFParser.parse(PDFParser.java:221) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1110) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1093) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1052) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1000) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner.calculatePageSizeFromFile(PDVisibleSignDesigner.java:171) ~[pdfbox-2.0.28.jar!/:2.0.28] at org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner.<init>(PDVisibleSignDesigner.java:72) ~[pdfbox-2.0.28.jar!/:2.0.28] at co.netcom.signature.CreateVisibleSignature.setVisibleSignDesigner(CreateVisibleSignature.java:73) ~[classes!/:0.0.1-SNAPSHOT]
解决思路与建议
根本原因:
saveIncremental是增量更新PDF,会在原文件末尾追加更新内容,但你当前代码中源文件和目标文件路径完全相同,导致原文件被覆盖破坏,后续加载时PDFParser无法识别有效PDF头部信息。修复方案:
- 增量更新时,源文件和目标文件必须使用不同路径,先写入临时文件,完成后再替换原文件。
- 修改
populateFieldsInDocument方法的输出逻辑:public void populateFieldsInDocument(String pathSource, String pathdestination, java.util.List<DocumentMemberConfigDto> configList) throws IOException { PDDocument document = PDDocument.load(new File(pathSource)); PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm(); for (DocumentMemberConfigDto config : configList) { PDField field = acroForm.getField(config.id); if (field != null && !config.fieldLibelle.equals("Signature")) { // 设置字段值 } } document.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true); document.getDocumentCatalog().getAcroForm().getCOSObject().setNeedToBeUpdated(true); // 使用临时文件存储增量更新内容 String tempFilePath = pathdestination + ".tmp"; FileOutputStream fileOutputStream = new FileOutputStream(new File(tempFilePath)); document.saveIncremental(fileOutputStream); document.close(); fileOutputStream.close(); // 替换原文件 Files.move(Paths.get(tempFilePath), Paths.get(pathdestination), StandardCopyOption.REPLACE_EXISTING); }
额外优化:检查
PrepaireEmptyFieldsToDocument中的document.save(pathdestination),如果同样存在源路径和目标路径相同的情况,建议也采用临时文件替换的方式,避免潜在的文件损坏风险。
内容的提问来源于stack exchange,提问作者rahim soufiane
相关产品推荐
相关产品推荐

