关于观察
第 3 页和第 4 页的签名不是原始签名,但它们与第 1 页和第 2 页的签名相同。为了验证签名不同,我在签名中添加了唯一的“原因”代码。
如果文档中签名字段的名称一致,则可能会发生这种情况。具有相同名称的多个 PDF 字段被视为同一字段的多个可视化。在这种情况下,合并过程可能会丢弃重复的值。
不过,我不确定您的文件是否属于这种情况。如果你想知道,请分享。
...
检查示例文件后,很明显问题确实是由合并文档中相同的签名字段名称引起的:
- Doc1-signed.pdf 有
- 第 1 页上的签名签名字段
Signature1(字段和小部件合并),其值为 Reason Doc1-Page1 和
- 第 2 页上的签名签名字段
Signature2(字段和小部件合并),其值为 Reason Doc1-Page2。
- Doc2-signed.pdf 有
- 第 1 页上的签名签名字段
Signature1(字段和小部件合并),其值为 Reason Doc2-Page1 和
- 第 2 页上的签名签名字段
Signature2(字段和小部件合并),其值为 Reason Doc2-Page2。
MERGED-PDF.pdf 中的合并结果
- 一个签名的签名字段
Signature1,其值为Reason Doc1-Page1,第1页和第3页上有明确的小部件和
- 一个签名的签名字段
Signature2,其值是Reason Doc1-Page2,第2页和第4页上有明确的小部件。
因为整个 PDF 被视为单个表单,所以表单字段名称只能有一个关联值。
因此,将两个源文档中具有相同名称的多个字段合并为具有多个小部件的单个字段(就像PdfCopyFields 似乎所做的那样)是一个明智的做法。
我尝试使用在线 pdf 合并服务,签名字段已正确合并
正确合并我假设您的意思是它们仍然具有原始的不同值。这反过来又表明该服务没有像上述那样合并字段。
但这并不比PdfCopyFields更正确,它更笨,因为现在字段 Signature1 的值不清楚,就像 Signature2 的值一样。
如果您想保留具有重复名称的源字段的不同值,正确的做法是在合并过程中重命名此类重复字段 . (如果在线 PDF 合并服务也这样做了,那就不傻了。但是你没有表明字段名称有任何变化......)
您可以在iText in Action chapter 6 中找到合并文档的示例代码,并在chapter 6 中使用现有的PDF 示例ConcatenateForms2.java:
PdfCopyFields copy
= new PdfCopyFields(new FileOutputStream(RESULT));
// add a document
PdfReader reader1 = new PdfReader(renameFieldsIn(DATASHEET, 1));
copy.addDocument(reader1);
// add a document
PdfReader reader2 = new PdfReader(renameFieldsIn(DATASHEET, 2));
copy.addDocument(reader2);
// Close the PdfCopyFields object
copy.close();
reader1.close();
reader2.close();
使用辅助方法
private static byte[] renameFieldsIn(String datasheet, int i)
throws IOException, DocumentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Create the stamper
PdfStamper stamper = new PdfStamper(new PdfReader(datasheet), baos);
// Get the fields
AcroFields form = stamper.getAcroFields();
// Loop over the fields
Set<String> keys = new HashSet<String>(form.getFields().keySet());
for (String key : keys) {
// rename the fields
form.renameField(key, String.format("%s_%d", key, i));
}
// close the stamper
stamper.close();
return baos.toByteArray();
}
显然,您可以通过仅重命名签名字段来进行调整。这会将其他字段与“正常”表单内容合并,但保留签名原样。
(请记住,我不是指签名本身的有效性,而是指签名字段)。
作为事后的想法,在合并之前展平签名字段可能是一种替代方法。视觉表示仍然存在,但验证失败消息消失了,因为不再验证任何内容。
关于合并已签名 PDF 的一般说明
你的意图
我有 2 个要合并的文档,每个文档有 2 页,每个文档中的每一页都有不同的签名
如果不完全使签名无效,就无法实施,至少来自除一个文档之外的所有签名。查看here 以了解集成 PDF 签名的介绍。特别注意同一文档中的多个集成签名如何工作:
合并两个文档后,您可以保持一个文档中的签名有效,但另一个文档的添加签名仅涵盖其文档中的数据,而合并后它们必须涵盖两个文档中的数据。
因此,如果不破坏至少一些签名,就不可能进行合并。
合并到更当前的 iText 版本
OP 使用 iText 版本 4.2.0。在当前的 iText 版本 (5.5.x) 中,大部分表单感知逻辑已从 PdfCopyFields 移动到 PdfCopy。如果您使用这样的版本或更新的版本,请尝试使用PdfCopy。
@Bruno 关于合并签名字段
上述合并的结果在 PDF-2 中将完全无效,这不仅是因为签名本身无效,还因为签名具有多个外观。您可能需要重新考虑 Pdf*Copy* 类族在签名字段方面的行为。