最初にいくつかの背景
通常、PDF ファイルは、ヘッダー、本文、クロス リファレンス情報、およびトレーラーで構成されます。下の図 2 を参照してください。このような PDF ファイルを更新する場合、次の選択肢があります。
- すべての変更を統合して文書全体を新たに構築する (元の PDF のように再び形成された PDF が生成される)
- または、本文要素の変更と相互参照をドキュメントに追加し、以前のトレーラーを参照する新しいトレーラーを追加することもできます (その結果、下の図 3 に示すような PDF が形成されます)。
ただし、実際にはその中間にいくつかの形式があります。たとえば、一部のツールは、元の文書の相互参照とトレーラーを切り取り、新しいまたは変更された本体要素、新しい完全な相互参照、および以前の状態への後方参照なしの新しいトレーラーを追加するだけです。
(PDF 仕様ISO 32000-1:2008からコピーされた画像)
図 3 のように形成された PDF の場合、手元にある PDF のさまざまな状態の履歴があり、それぞれがファイルの先頭から始まり、トレーラーの 1 つまで到達します。これらの状態は一般にドキュメントのリビジョンと呼ばれ、ドキュメントの各リビジョンは明らかに PDF のフォーム情報の状態を反映しています。
あなたの想定とは対照的に、これらのリビジョンには名前自体がありません。IDの2番目の部分(リビジョンごとに異なるはずです)を使用しない限り、iTextの名前としては使用されていません。
予告編が停止して次の本体の更新が開始される正確なポイントには、多少の不正確さがあります。一方で、仕様には差し迫った選択肢がいくつかあります (さまざまな改行、無視される空白、無視されるコメント行) 一方で、多くの PDF プロデューサーはとにかく仕様を少し超えています。これは、上記の完全な更新と増分更新の間の中間の種類と組み合わされて、リビジョンを抽出するプロセスをやや面倒にすることがあります。
高い信頼性で認識できるリビジョンの特殊なケースがあります: 署名されたリビジョン、つまり、最後の本文の更新にドキュメントの統合された署名が含まれるリビジョンです。ドキュメントの署名されたバイト範囲は、ドキュメントのすべてのリビジョンを網羅する必要がありますが、署名自体に残されたギャップ (少なくとも Adobe ソフトウェアによって受け入れられ、PAdES および PDF-2 標準に準拠するため) を含む必要があるため、その場合のリビジョンは、署名情報から推測できます。
詳細はこちら。
あなたの質問に対するいくつかの答え
PDF ドキュメントの各署名が AcroFields の特定のリビジョンに適用されることを理解しています。
前述のように、それぞれがドキュメントの特定のリビジョンに適用され、フォーム データの特定の状態または「リビジョン」が暗示されます。
ユーザーが何らかの入力を変更するたびに (つまり、pdf フォームに記入することによって)、新しいリビジョンが作成されます。
必ずしも。上記のように、更新には多くの中間の方法があります。
最新リビジョンが署名されているドキュメントの情報を変更する場合にのみ、その署名が削除または無効にされない場合は、適切な増分更新が必要です。それ以外の場合、更新者は最後の署名の後に追加されたすべての情報を取得し、任意の内容で独自の更新を作成し、その更新をドキュメントの最後に署名されたリビジョンに追加できます。この更新プログラムには、特定の中間リビジョンが実際に存在すると思わせる目的で、複数の仮想更新ブロックが含まれている場合もあります。
したがって、署名されたリビジョンのみが何らかの形で真であると信頼できます。iText は、そのような署名されたリビジョンへのアクセスのみを提供します。
私の質問は、AcroFields オブジェクトからすべてのリビジョンを取得するにはどうすればよいですか?
を使用して、署名されたすべてのドキュメントのリビジョンを抽出できます
InputStream revisionStream = fields.extractRevision("name");
PdfReader
それらを別々のインスタンスで開きます。次に、そのリビジョンに対して開かれAcroFields
たそれぞれのインスタンスを照会することにより、これらの署名された各リビジョンの PDF フォーム情報にアクセスできます。PdfReader
(ところで、String
引数はリビジョンの名前ではなく、署名がそのリビジョンに署名する署名フィールドの名前です。)
しかし、どうすればすべてのリビジョン (または少なくともその名前) を取得できますか? これまでのところ、iText API と Web で何も見つかりませんでした。
前述のように、これらのリビジョン名は実際には署名フィールド名です。したがって、使用できます
List<String> names = fields.getSignatureNames()
リビジョンを抽出できるすべての名前を取得します。