Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java PDFBox 1.8.10:填充并签名PDF生成无效签名_Java_Pdf_Pdfbox_Sign_Pdf Form - Fatal编程技术网

Java PDFBox 1.8.10:填充并签名PDF生成无效签名

Java PDFBox 1.8.10:填充并签名PDF生成无效签名,java,pdf,pdfbox,sign,pdf-form,Java,Pdf,Pdfbox,Sign,Pdf Form,我(按程序)在PDF文档中填写表格(AcroPdf),然后在文档上签名。我从doc.pdf开始,使用PDFBox的setFields.java示例创建doc_filled.pdf。然后我签署doc_filled.pdf,创建doc?filled_signed.pdf,使用一些代码,基于签名示例,并在Acrobat Reader中打开pdf。输入的字段数据可见,签名面板告诉我 “此签名中包含的格式或信息有错误(签名字节数组无效)” 到目前为止,我知道: 单独应用的签名代码(即直接创建一些doc_

我(按程序)在PDF文档中填写表格(AcroPdf),然后在文档上签名。我从doc.pdf开始,使用PDFBox的setFields.java示例创建doc_filled.pdf。然后我签署doc_filled.pdf,创建doc?filled_signed.pdf,使用一些代码,基于签名示例,并在Acrobat Reader中打开pdf。输入的字段数据可见,签名面板告诉我

“此签名中包含的格式或信息有错误(签名字节数组无效)”

到目前为止,我知道:

  • 单独应用的签名代码(即直接创建一些doc_signed.pdf)会创建有效的签名
  • 将“不可见签名”、可见签名和可见签名添加到现有签名字段时存在问题
  • 如果我不填写表单,而只打开并保存表单,甚至会出现问题,即:

    PDDocument doc = PDDocument.load(new File("doc.pdf"));
    doc.save(new File("doc_filled.pdf"));
    doc.close();
    
足以中断随后应用的签名代码

另一方面,如果我使用相同的doc.pdf,在Adobe中手动输入字段值,则签名代码将生成有效的签名

我做错了什么

更新:

@mkl要求我提供我所说的文件(我目前没有足够的声誉,无法将所有文件作为链接发布,对于由此带来的不便,我深表歉意):

  • odc.pdf:
  • doc_filled.pdf:
  • 已填写的文件已签名.pdf:
  • 已填写的文件和已签名的文件.pdf:
最后一个是通过使用

    doc.saveIncremental(); 
正如我在评论中所写的,一些

    setNeedToBeUpdate(true);
但似乎不见了。 关于@mkl的第二条评论,我发现 所以问题:,也包括一些输入的文本没有显示。我第一次试了一下,申请了

    setBoolean(COSName.getPDFName("NeedAppearances"), true); 
添加到字段和表单的字典,该字典随后显示字段上下文,但签名不会添加到最后。不过,我还需要进一步研究

更新:
故事在这里继续:

OP最初问题的原因,即在用PDFBox加载其PDF(用于填写表单)并保存后,无法使用PDFBox签名代码成功签名此新PDF,简言之,已详细解释如下:

  • 定期保存文档时,PDFBox使用交叉引用表进行保存

    • 如果要定期保存的文档是从带有交叉引用流的PDF加载的,则交叉引用流字典的所有条目都保存在拖车字典中
  • 在应用签名的过程中保存文档时,PDFBox创建增量更新;由于此类增量更新要求更新使用与原始版本相同的交叉引用,因此PDFBox在本例中尝试使用相同的技术

    • 为了识别最初使用的技术,PDFBox在其文档表示中查看已加载拖车或交叉引用流字典的字典的类型条目:如果有类型条目的值为XRef(这是为交叉引用流指定的),假定为流,否则为表
因此,在OP的原始PDF
doc.PDF
具有交叉引用流的情况下:

  • 加载并填写表单后,文档会定期保存,即使用交叉引用表,但所有以前的交叉引用流条目(其中包括类型)都会复制到尾部。(
    doc\u filled.pdf

  • 加载此保存的PDF以及用于签名的交叉引用表后,将使用增量更新再次保存此PDF。PDFBox假定(由于类型尾部条目),现有文件具有交叉引用流,因此在增量更新结束时也使用交叉引用流。(
    doc\u filled\u signed.pdf

  • 因此,最终,填写后签名的PDF有两个版本,内部版本有一个交叉引用表,外部版本有一个交叉引用流

  • 由于这是无效的,Adobe Reader在加载PDF时会在其内部文档表示中修复此问题。修复会更改文档字节。因此,Adobe Reader眼中的签名被打破了

  • 大多数其他签名验证器不会尝试这样的修复,而是按原样检查文档的签名。他们成功地验证了签名

还提供了一些解决此问题的方法:

  • 答:在加载用于填写表单的PDF后,在定期保存之前,从尾部删除Type条目。如果对该文件应用签名,PDFBox将采用交叉引用表(因为不存在误导性的类型条目)。因此,签名增量更新将有效

  • B:在单独运行或与签名相同的运行中,也可以使用增量更新保存表单填写更改。这也会导致有效的增量更新

一般来说,我会建议后一种选择,因为如果PDFBox保存例程彼此兼容,前一种选择可能会中断

但遗憾的是,后一个选项需要将添加和更改的对象标记为已更新,包括来自文档目录的路径。如果这不可能,或者至少过于繁琐,则第一个选项可能更可取


在手头的案例中,OP尝试了后一种选择(
doc\u filled\u and\u signed.pdf
):

目前,文本框的内容仅在选中文本框时可见(使用Acrobat reader和Preview的行为相同)。我标记PDField、其所有父项、AcroForm、目录以及其中的页面