java - PDFBox 1.8.10 : Fill and Sign PDF produces invalid signatures

标签 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_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:https://www.dropbox.com/s/ev8x9q48w5l0hof/doc.pdf?dl=0
  • doc_filled.pdf:https://www.dropbox.com/s/fxn4gyneizs1zzb/doc_filled.pdf?dl=0
  • doc_filled_signed.pdf:https://www.dropbox.com/s/xm846sj8f9kiga9/doc_filled_signed.pdf?dl=0
  • doc_filled_and_signed.pdf:https://www.dropbox.com/s/5jftje6ke87jedr/doc_filled_and_signed.pdf?dl=0

  • 通过使用以下方法一次性签名并填写文档来创建最后一个
        doc.saveIncremental(); 
    

    正如我在评论中所写,
        setNeedToBeUpdate(true);
    

    不过似乎丢失了。
    引用@mkl的第二条评论,我发现了这一点
    这样的问题:Saved Text Field value is not displayed properly in PDF generated using PDFBOX,它也覆盖了一些未显示的输入文本。我尝试了一下,申请了
        setBoolean(COSName.getPDFName("NeedAppearances"), true); 
    

    到字段和表单的字典中,该字典随后显示字段上下文,但是最后没有添加签名。我仍然需要进一步研究。

    更新:
    故事在这里继续:PDFBox 1.8.10: Fill and Sign Document, Filling again fails

    最佳答案

    OP原始问题的原因,即在用PDFBox加载PDF(用于表单填充)然后保存它之后,该新PDF无法使用PDFBox签名代码成功签名,已在this answer中进行了详细说明,在短的:

  • 当定期保存文档时,PDFBox会使用交叉引用表来保存。
  • 如果已使用交叉引用流从PDF加载了要定期保存的文档,则交叉引用流字典的所有条目都将保存在尾部字典中。
  • 在应用签名的过程中保存文档时,PDFBox将创建增量更新。由于此类增量更新要求更新使用与原始修订相同的交叉引用,因此本例中的PDFBox尝试使用相同的技术。
  • 为了识别最初使用的PDFBox技术,请查看其文档表示中已加载了预告片或交叉引用流词典的字典的类型条目:如果存在类型条目,其值为 XRef (即因此为交叉引用流指定),则假定使用流,否则使用表格。

  • 因此,对于具有交叉引用流的OP原始PDF doc.pdf:
  • 加载并填写表格后,即使用交叉引用表定期保存文档,但是所有以前的交叉引用流条目(包括类型)都被复制到预告片中。 (doc_filled.pdf)
  • 在使用交叉引用表加载此保存的PDF以进行签名后,将使用增量更新再次保存它。 PDFBox假定(由于类型预告片条目)现有文件具有交叉引用流,因此,在增量更新结束时也使用交叉引用流。 (doc_filled_signed.pdf)
  • 因此,最后,已填充然后签名的PDF具有两个修订版本,一个是内部版本,带有一个交叉引用表,另一个是外部版本,带有一个交叉引用流。
  • 由于这是无效的,因此Adobe Reader在加载PDF时会以其内部文档表示形式对其进行修复。修复会更改文档字节。因此,Adobe Reader眼睛中的签名被打断了。
  • 大多数其他签名 validator 都不会尝试进行此类修复,而是会按原样检查文档的签名。他们成功地验证了签名。

  • The answer referenced above还提供了一些解决方法:
  • 答:加载用于表单填写的PDF后,在定期保存之前,从预告片中删除类型条目。如果对此文件应用了签名,PDFBox将使用一个交叉引用表(因为不存在误导性的类型条目。因此,签名增量更新将是有效的。
  • B:也可以使用增量更新来保存表单填写更改,无论是在单独运行中还是在与签名相同的运行中。这也会导致有效的增量更新。

  • 通常,我会建议使用后一个选项,因为如果使PDFBox保存例程相互兼容,则前一个选项可能会中断。

    但是,遗憾的是,后一种选项要求将添加和更改的对象标记为已更新,包括来自文档目录的路径。如果这不可能或至少太麻烦,则首选第一个选项。

    在当前情况下,OP尝试了后一种选项(doc_filled_and_signed.pdf):

    At the Moment the text box's content is only visible, when the text box is selected (with Acrobat reader and Preview the same behaviour). I flag the PDField, all of its parents, the AcroForm, the Catalog as well as the page where it is displayed.



    他将更改的字段标记为已更新,但未标记关联的外观流,该外观流在设置表单字段值时由PDFBox自动生成。

    因此,在结果PDF文件中,该字段具有新值,但是旧的,空的外观流。仅当单击该字段时,Adobe Reader才会根据要编辑的值创建新外观。

    因此,OP还必须标记新的正常外观流(表单字段字典包含引用字典的 AP 条目,其中 N 引用正常外观流)。另外(如果查找更改或添加的条目变得太麻烦了),他可以尝试其他选择。

    关于java - PDFBox 1.8.10 : Fill and Sign PDF produces invalid signatures,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32884607/

    相关文章:

    java - 24 小时制在 dateformat android 中不起作用

    java - HASHMAP - 阈值和负载因子以及容量

    java - Shell脚本java程序不能正确写入文件

    html - 在新的浏览器窗口中打开 .pdf 立即显示打印设置,如何解决这个问题?

    java - 如何使用 PDFBox 确定实际 PDF 内容的位置?

    java - 在 PDF 文档中嵌入 OTF 字体

    java - Tomcat6 中的类路径资源(适用于 Jetty)

    ios - iOS 9-强制共享扩展以获取public.file-url

    php - ajax成功打开新窗口显示pdf

    java - PDF-A 文件验证