コンテンツにスキップ
getnextpdf.com

Pro エディション

Diff — 詳細リファレンス

このページは、NextPDF Pro の差分モジュール NextPDF\Pro\Diff の契約レベルのリファレンスです。このモジュールは 2 つの PDF ドキュメントを比較し、テキスト・画像・メタデータの変更を報告します。PdfDiffer はページアライメント済みの Myers 行差分を生成します。StructuredDiffer は段落のグループ化、画像比較、メタデータ比較を追加します。DiffFormatter は構造化結果を JSON または HTML フラグメントへシリアライズします。このページでは、公開 API、観測可能な動作契約、リソース境界、失敗モードを規定します。タスク指向のセットアップとサンプルは Diff 機能ページ にあります。

この機能は NextPDF Pronextpdf/pro)に同梱され、Pro ティアのライセンスエンベロープで有効化されます。その利用資格が無いデプロイでは、この機能のクラスはロードされません。エディションを比較してライセンスを取得

このモジュールをゲートするランタイムのケーパビリティフラグはありません。差分クラスは、nextpdf/pro がインストールされライセンスされている限りいつでも利用できます。

シンボルパラメーターデフォルト動作戻り値送出・失敗条件備考
PdfDiffer::compare()string $sourcePdf, string $targetPdfページごとのテキストを抽出し、ソースのページ i をターゲットのページ i と比較DiffResultバッファに %PDF ヘッダーが無い場合、またはオプションのリーダーが解析に失敗した場合は InvalidArgumentException。リソース境界に達した場合は OverflowException静的なエントリーポイント
PdfDiffer::compareTexts()array $sourcePages, array $targetPages(いずれも list<string>抽出を経由せず、事前抽出済みのページテキストを比較DiffResultリソース境界に達した場合は OverflowException静的。テキストが既に利用可能な場合に使用
PdfDiffer::extractText()string $contentStream1 つの生コンテンツストリームからテキスト表示演算子を解析string—(フォールトトレラント。解析不能な入力は空文字列を返す)静的
StructuredDiffer::__construct()?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = nullnull の引数はデフォルトの差分器を構築テスト向けのコンストラクター注入
StructuredDiffer::compare()string $sourcePdf, string $targetPdfテキスト・段落・画像・メタデータの比較を実行し、サマリーを構築StructuredDiffResultテキスト経路からの InvalidArgumentExceptionOverflowException を伝播モジュール全体のオーケストレーター
DiffFormatter::toJson()StructuredDiffResult $result整形された JSON ドキュメントstringエンコードに失敗した場合は JsonException
DiffFormatter::toHtml()StructuredDiffResult $resultサマリー・段落・メタデータの各セクションを含む HTML フラグメント。テキスト値はエンティティエスケープ済みstring完全なドキュメントではなくフラグメントのみ
DiffFormatter::toArray()StructuredDiffResult $resulttoJson() を支えるシリアライズ配列array<string, mixed>安定した snake_case キー
ImageDiffer::diff()string $sourcePdf, string $targetPdf画像 XObject をハッシュ化し、追加・削除・変更された画像を報告list<ImageDiff>—(デコード不能な構造はフェイルクローズドでスキップ)同一性はページバケットとオブジェクト番号の組
MetadataDiffer::diff()string $sourcePdf, string $targetPdf8 つの /Info フィールド(Title、Author、Subject、Keywords、Creator、Producer、CreationDate、ModDate)を比較list<MetadataChange>—(非準拠の入力でも例外を送出しない)値はデコード済み文字列として比較
DiffEngine::diff()array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = 100002 つの行リストに対する Myers 行差分list<DiffRegion>合算した行数が $maxLines を超える場合、または編集距離がメモリ境界の上限を超える場合は OverflowException静的。すべてのテキスト経路の領域生成器
TextExtractor::fromContentStream()string $contentStreamストリームをトークン化し、テキストステートマシンを実行list<TextBlock>静的
TextExtractor::fromOperations()array $operationslist<ContentStreamOp>事前解析済みの操作に対してテキストステートマシンを実行list<TextBlock>静的
ContentStreamParser::parse()コンストラクターが string $data を受け取る演算子とオペランドをトークン化。辞書とコメントはスキップ。フォールトトレラントlist<ContentStreamOp>認識されないバイトはスキップされ、致命的にならない
ContentStreamOpstring $operator, list<mixed> $operands読み取り専用の操作値オブジェクト。isTextOp() がテキスト関連演算子を分類
DiffResultlist<DiffRegion> $regions, int $sourcePagesCount, int $targetPagesCount領域を $added$removed$modified に振り分け、isIdentical()hasDifferences()totalChanges() を公開読み取り専用。Unchanged の領域は $regions にのみ残る
StructuredDiffResultテキスト差分、段落、画像、メタデータ変更、サマリー集約結果。hasDifferences()isIdentical() はサマリーへ委譲読み取り専用
DiffSummaryカテゴリー別カウントとページ数テキスト・画像・メタデータのカウントに対する hasDifferences()totalChanges()読み取り専用
DiffRegionDiffType $type, string $text, int $pageIndex, int $lineIndex, ?string $counterpartText = null1 件の行レベルの変更$counterpartText は出荷版エンジンでは null のまま
ParagraphDiff種別、テキスト、ページインデックス、開始/終了行、領域1 ページ上の連続する同一種別の領域。lineCount()読み取り専用
ImageDiff種別、ページインデックス、ソースハッシュ、ターゲットハッシュ、オブジェクト ID1 件の画像変更エントリーハッシュは存在しない側では空文字列
MetadataChangestring $field, ?string $sourceValue, ?string $targetValue1 件のフィールド変更。isAdded()isRemoved()isModified()null はフィールドが存在しないことを意味する
TextBlockテキスト、x、y、フォント名、フォントサイズ、行インデックス概略位置を伴う 1 件の抽出テキストラン読み取り専用
DiffTypeenum: Added, Removed, Modified, Unchangedテキスト向けの文字列ベースの変更分類動作契約の Modified に関する注記を参照
ImageDiffTypeenum: Added, Removed, Modified, Unchanged画像向けの文字列ベースの変更分類
public static function compare(string $sourcePdf, string $targetPdf): DiffResult
public static function compareTexts(array $sourcePages, array $targetPages): DiffResult
public static function extractText(string $contentStream): string
public function __construct(
?ImageDiffer $imageDiffer = null,
?MetadataDiffer $metadataDiffer = null,
)
public function compare(string $sourcePdf, string $targetPdf): StructuredDiffResult
public function toJson(StructuredDiffResult $result): string
public function toHtml(StructuredDiffResult $result): string
public function toArray(StructuredDiffResult $result): array
public static function diff(
array $sourceLines,
array $targetLines,
int $pageIndex = 0,
int $maxLines = self::MAX_DIFF_LINES,
): array

PdfDiffer::compare() はページごとのテキストを抽出し、ソースのページ i をターゲットのページ i と比較します。ページ数が異なる場合、不足している側は超過分のページについて空のテキストとして扱われます。各ページペアの内部では、テキストは改行で分割され、ページごとに Myers 行差分が実行されます。エンジンは AddedRemovedUnchanged の領域を出力します。変更された行は RemovedAdded の領域の組として現れます。出荷版エンジンは Modified のテキスト領域を出力しません。Modified のケースと DiffResult::$modified バケットは、DiffResult のコンストラクターが公開されているため、呼び出し側が構築した結果のために用意されています。totalChanges() は追加・削除・変更された領域を数え、変更のない領域は除外します。

抽出には 2 つの経路があります。

  • オプションの Artisan リーダーが存在する場合。 オプションの NextPDF\Parser\PdfReader クラスがインストールされている場合、ページのコンテンツストリームはページ正確なテキストを得るためにそれを通して読み取られます。トレーラーのページ数がループを駆動します。読み取りに失敗したページは、比較を中止する代わりに空のテキストを提供します。
  • フォールバック。 境界付きのバイトレベルスキャナーが strposstream/endstream のペアを特定し、50 MB の厳格な出力上限で FlateDecode データを展開し、ストリーム辞書が /DecodeParms を通じて要求する場合は ISO 32000-2:2020 §7.4.4.4 に従って PNG プレディクターを逆フィルタリングします。不正または未対応のプレディクターの場合、デコード済みバイトは変更されません。フォールバックは復元したすべてのテキストを単一のページバケットへ連結するため、ページレベルのアライメントはリーダー経路でのみページ正確です。

どちらの経路も、§9.4 のテキスト表示演算子 TjTJ' を解析します。ステートマシンは BT/ETTm(原点のみ)、Td/TDT*Tf を追跡します。

StructuredDiffer::compare() はテキスト差分を実行し、同一ページ上で連続する同一種別の領域を段落へグループ化し(変更のないランも含む)、続いて画像とメタデータの比較を実行して DiffSummary を組み立てます。サマリーの段落数は、追加・削除・変更された段落のみを対象とします。

画像比較は PDF オブジェクトを構造的に列挙します。ストリーム本体の範囲は §7.3.8.2 に従って /Length エントリーによって決まるため、単にオブジェクト構文に似ているだけのバイナリバイトが幻のオブジェクトとして登録されることはありません。圧縮オブジェクトストリーム(/Type /ObjStm)は §7.5.7 に従ってデコードされるため、その内部にネストされた画像 XObject も可視化されます。検出された各画像は、非暗号の xxh128 関数でコンテンツハッシュ化されます。同一性はページバケットとオブジェクト番号の組です。ストリーム順で所有ページを持たない画像はページ 0 に帰属されます。

メタデータ比較は、可能な場合はトレーラーを通じて実際の /Info 辞書を解決するため、コンテンツストリーム内のおとりのフィールドトークンがドキュメントメタデータと誤認されることはありません。フィールド値は PDF 文字列としてデコードされます。すなわち §7.3.4.2 に従うリテラル形式と、§7.3.4.3 に従う 16 進形式です。解決可能なトレーラーが無い場合、探索は入力全体へフォールバックします。日付は、解析されたタイムスタンプではなくデコード済み文字列として比較されます。

DiffFormatter::toJson() は整形された JSON を返し、JSON_THROW_ON_ERROR でエンコードするため、エンコード失敗時には false を返す代わりに JsonException を送出します。toHtml()<div class="nextpdf-diff"> フラグメントを返します。段落テキストとメタデータ値は HTML エンティティエスケープを通ります。視覚的なサイドバイサイドのレッドライン PDF 出力はありません。同一の入力に対しては、領域と整形済み出力は決定的です。

  • ページアライメントは位置ベースです。ページが 1 つ挿入または削除されると、後続するすべてのページのアライメントがずれ、下流の変更カウントが水増しされます。
  • フォールバックの抽出経路では、すべてのテキストがページインデックス 0 に配置されます。リーダーで抽出したドキュメントを、フォールバック経路による期待値と比較すると、ページ帰属が異なります。
  • %PDF で始まらないソースまたはターゲットのバッファは、比較の前に InvalidArgumentException で失敗します。
  • 1 つのページペアで合算した行数が 10,000 を超えると、OverflowException(行数境界)で失敗します。
  • 共有する行が少なすぎる 2 つのページテキストは、Myers 編集距離がメモリ境界の上限を超えると OverflowException で失敗します。正当なリビジョンはほとんどの行を共有するため影響を受けません。共通性の低い敵対的入力はこの境界に抵触します。
  • 50 MB を超えるフォールバックストリームの展開出力は、OverflowException(解凍爆弾境界)で失敗します。スキャナーは無制限な正規表現ではなく strpos を使用するため、細工された入力が壊滅的なバックトラッキングを引き起こすことはできません。
  • " テキスト表示演算子は 3.1.0 ではトークン化されますがテキストブロックを生成しません。" のみで表示されるテキストは差分に参加しません。
  • スキャンされた画像のみの PDF は、テキスト差分をほとんど、または全く生成しません。OCR は実行されません。
  • 画像変更検出は知覚的ではなく構造的です。ページをラスタライズせず、同一ピクセルで再エンコードされた画像も、そのバイトが異なれば変更として報告されます。
  • リビジョン間でページバケットまたはオブジェクト番号が変わる画像は、変更としてではなく、削除と追加の組として報告されます。
  • FlateDecode 以外のフィルターで圧縮されたオブジェクトストリームは、フェイルクローズドでスキップされます。そのメンバー画像は比較されません。
  • このモジュールでは暗号操作は一切行われないため、FIPS モード固有の挙動はありません。画像ハッシュは変更検出のみを目的とし、完全性や証拠としての重みを持ちません。
主張標準条項
抽出のために TjTJ のテキスト表示演算子を解析ISO 32000-2:2020§9.4
フォールバックのストリームデータは stream キーワードに続く CRLF または LF の後から開始ISO 32000-2:2020§7.3.8.1
画像スキャンのストリーム範囲は辞書の /Length エントリーによって決まるISO 32000-2:2020§7.3.8.2
オブジェクトストリームのメンバーは /N ペアテーブルと /First オフセットを通じて特定ISO 32000-2:2020§7.5.7
PNG プレディクターの逆変換は /DecodeParmsPredictor パラメーターに従うISO 32000-2:2020§7.4.4.4
メタデータ値はリテラルおよび 16 進の文字列形式をデコードISO 32000-2:2020§7.3.4.2, §7.3.4.3
視覚的なサイドバイサイドのレッドライン PDF 出力未対応(JSON/HTML のみ)

すべての条項は言い換えたものであり、NextPDF は規範テキストを複製しません。これらは能力に関する記述であり、認証ではありません。NextPDF はいかなる認証も保有せず、付与もしません。テキスト復元はテキスト表示演算子から行テキストを再構成します。§9.4 の完全なテキストステートマシンは実行しないため、差分はジオメトリレベルではなくコンテンツレベルです。

  • Pro パッケージ内での提供状況: PdfDifferDiffEngineTextExtractor およびそれらの値オブジェクトは 1.8.0 から。StructuredDifferDiffFormatterImageDifferMetadataDiffer およびそれらの値オブジェクトは 2.2.0 から。すべて nextpdf/pro 3.1.0 で最新です。
  • ページテキストが既に利用可能な場合は PdfDiffer::compareTexts() を優先してください。抽出とその失敗モードを完全にスキップします。
  • オプションの Artisan リーダーは抽出精度とページ帰属を向上させます。ランタイムで検出され、必須になることはありません。
  • 信頼できない入力を差分する際は OverflowException を捕捉してください。これらの境界は意図的なフェイルクローズドの拒否であり、一時的なエラーではありません。
  • DiffFormatter::toHtml() はクラス名(diff-addeddiff-removeddiff-modifieddiff-unchanged)を出力しますが、スタイルシートは出力しません。独自の CSS を用意してください。
  • テストでは StructuredDiffer をスタブの差分器で構築し、テキスト経路を画像・メタデータのスキャンから分離してください。

このページは、外部から観測可能な動作とサポート対象の公開 API サーフェスのみを文書化します。内部の名前空間パス、ヘルパークラス、メカニズム表、Runbook のファイル名、チケットのプレフィックスは対象外です。