如何在iText中获取AcroField修订版的名称?

我目前正在研究在pdf文档上应用和验证数字签名的工具 . 据我所知,pdf文档中的每个签名都适用于AcroFields的某个版本 . 每次用户更改某些输入时(即通过填写pdf表单),都会创建新的修订版本 .

我的问题是:如何从AcroFields对象中检索 all revisions ?如果我有这样的名字,我知道如何获得 single 修订:

AcroFields fields = ...;
fields.getRevision("revision1");

但是我怎样才能检索 all revisions (或至少他们的名字)?到目前为止,我还没有在iText API和网络中找到任何内容 .

我在2.1.7版本中使用iText .

谢谢和问候,汤姆

回答(1)

2 years ago

Some backgrounds first

通常,PDF文件由 Headers ,正文,交叉引用信息和预告片组成,请参见下面的图2 . 更新此类PDF文件时,您可以选择

  • 重新构建整个文档并集成所有更改(这导致PDF再次形成像原始文档)

  • 或者您可以将正文元素和交叉引用的更改附加到文档中,并添加一个新的预告片,同时引用前一个预告片(这将导致PDF格式如下图3所示) .

实际上,中间有一些形式 . 例如 . 一些工具只是切断原始文档的交叉引用和预告片,然后添加新的或更改的主体元素,新的完整交叉引用和新的预告片,而不对任何前状态进行任何反向引用 .

Initial structure of a PDF file

Structure of an updated PDF file

(从PDF规范ISO 32000-1:2008复制的图像)

如果PDF形成如图3所示,我们有手头的PDF的不同状态的历史记录,每个状态从文件的开头开始并到达并包括其中一个预告片 . 这些状态通常被命名为文档的修订版,文档的每个修订版显然都反映了PDF的表单信息的某些状态,我认为这是您所谓的AcroFields的修订版 .

与您的假设相反,这些修订本身没有名称 . 除非您使用ID的第二部分(对于不同的修订应该是不同的),但AFAIK不用作iText中任何内容的名称 .

在预告片停止并且下一次身体更新开始的确切点上存在一些不精确性 . 一方面,规范中即将出现一些选择(不同的可能的换行符,忽略的空格,忽略的注释行),另一方面,许多PDF生成器仍然有点超出规范 . 这与上面提到的完全更新和增量更新之间的中间变量相结合,有时可能使得提取修订的过程有些麻烦 .

有一个特殊的修订案例,可以很高的可靠性得到认可:签名修订,即最后一次更新包含文件综合签名的修订 . 由于文档的签名字节范围必须包含所有文档修订版,但签名本身留有差距(至少要被Adobe软件接受并符合PAdES和PDF-2标准),因此确切的结束在这种情况下的修订可以从签名信息中推断出来:

Multiple integrated signatures

更多细节here .

Some answers to your questions

我理解pdf文档中的每个签名都适用于AcroFields的某个版本 .

如上所述,每个都应用于文档的某个修订版,然后暗示某个状态或表单数据的某些状态 .

每次用户更改某些输入(即填写pdf表单)时,都会创建一个新的修订版本 .

不必要 . 如上所述,有许多中间更新方法 .

只有在更改最新修订版已签名的文档的信息时,如果不删除或无效该签名,则必须进行适当的增量更新 . 否则,更新程序可以获取上次签名后添加的所有信息,使用他希望的任何内容创建自己的更新,并将该更新附加到文档的最后签名修订 . 此更新甚至可能包含多个虚拟更新块,目的是让您相信某些中间修订实际存在 .

因此,只有签名的修订才能以某种方式被信任为真 . iText仅提供对此类签名修订的访问权限 .

我的问题是:如何从AcroFields中检索所有修订版宾语?

您可以使用提取所有已签名的文档修订

InputStream revisionStream = fields.extractRevision("name");

并在单独的 PdfReader 实例中打开它们 . 然后,您可以通过查询为该修订打开的相应 PdfReaderAcroFields 实例来访问每个签名修订的PDF表单信息 .

(顺便说一句, String 参数不是修订版的名称,而是签名字段的名称,其签名标记该修订版 . )

但是,如何检索所有修订版(或至少他们的名字)?到目前为止,我还没有在iText API和网络中找到任何内容 .

如前所述,这些修订名称实际上是签名字段名称 . 因此,你可以使用

List<String> names = fields.getSignatureNames()

检索可以提取修订版的所有名称 .