PDFium Delphi Component Docs

註解與表單語意比較

ComparePdfSemantics 比較註解與 AcroForm Widget 屬性,不依賴頁面繪製;即使外觀像素完全相同,表單值也可能已變更

傳入頁面對齊產生的 TPdfDiffPagePairs 或明確對應;nil 使用依位置配對,明確對應則必須將兩份文件的每頁各涵蓋一次,缺少的一側使用 -1

註解識別使用 /NM 名稱,表單 Widget 識別使用完整欄位名稱;識別範圍限定於對應頁面及項目種類

缺少名稱或重複名稱,包括同頁上同一欄位的多個 Widget,會回報 psckAmbiguous 與明確原因;註解陣列順序不決定識別

支援模式比較字串、旗標、色彩、不透明度、邊框、標記、線段、頂點與墨跡幾何、URI 動作、欄位值、選項標籤與選定選項,以及核取方塊或選項按鈕狀態

CompareAppearanceStreams 可選擇比較註解外觀串流內容;預設停用

CompareAnnotations 與 CompareForms 分別選取對應項目種類;GeometryTolerance 預設為 0.001 PDF 使用者空間點

新增、移除與變更項目包含變更前後的屬性與邊界;BuildSemanticDiffOverlays 分別傳回變更前後矩形,並附上頁面與變更索引

所有索引從零起算,邊界維持在以點表示的 PDF 使用者空間;繪製到點陣圖之前,請套用相應頁面的旋轉、裁切與視埠變換

頁面使用獨立原生 Handle 載入,保留呼叫端目前頁面與表單焦點,避免觸發表單動作

此模式不涵蓋非 Widget 欄位、任意自訂字典、內嵌檔案、指令碼動作與非 URI 目的地;明確拒絕 XFA 比較

預設上限為 10,000 組頁面配對、4,096 個掃描項目、4,096 項變更、每個字串 1 MiB、字串總計 16 MiB 及 16,777,216 次比較;預算耗盡時拒絕不完整輸出

Complete 區分成功且完整的比較與遭拒絕的比較;變更可能包含明確的識別歧義,因此將結果視為確定的項目匹配之前,請先檢查 AmbiguousCount

實際 Delphi/FPC Win32/Win64 驗收每個目標涵蓋 92 項斷言,包括儲存/重新開啟文件、相同像素下的值變更、Unicode 識別、頁面移動、歧義及預算

Options := TPdfSemanticDiffOptions.Default;
if not ComparePdfSemantics(BeforePdf, AfterPdf, PagePairs, Options, Report) then
  raise EPdfError.Create(Report.ErrorMessage);
Overlays := BuildSemanticDiffOverlays(Report);

公開宣告

type
  TPdfSemanticItemKind = (psikAnnotation, psikFormWidget);
  TPdfSemanticChangeKind = (psckAdded, psckRemoved, psckChanged, psckAmbiguous);
  TPdfSemanticSide = (pssBefore, pssAfter);
  TPdfSemanticProperty = record
    Name: string;
    Value: WideString;
  end;
  TPdfSemanticProperties = array of TPdfSemanticProperty;
  TPdfSemanticItem = record
    Kind: TPdfSemanticItemKind;
    Identity: WideString;
    PageIndex, AnnotationIndex: Integer;
    HasBounds: Boolean;
    Bounds: TPdfRectangle;
    Properties: TPdfSemanticProperties;
  end;
  TPdfSemanticPropertyChange = record
    Name: string;
    HasBefore, HasAfter: Boolean;
    BeforeValue, AfterValue: WideString;
  end;
  TPdfSemanticPropertyChanges = array of TPdfSemanticPropertyChange;
  TPdfSemanticChange = record
    Kind: TPdfSemanticChangeKind;
    ItemKind: TPdfSemanticItemKind;
    Identity: WideString;
    HasBefore, HasAfter: Boolean;
    BeforeItem, AfterItem: TPdfSemanticItem;
    Properties: TPdfSemanticPropertyChanges;
    AmbiguityReason: string;
  end;
  TPdfSemanticChanges = array of TPdfSemanticChange;
  TPdfSemanticOverlay = record
    Side: TPdfSemanticSide;
    PageIndex, ChangeIndex: Integer;
    Kind: TPdfSemanticChangeKind;
    Bounds: TPdfRectangle;
  end;
  TPdfSemanticOverlays = array of TPdfSemanticOverlay;
  TPdfSemanticDiffOptions = record
    CompareAnnotations, CompareForms, CompareAppearanceStreams: Boolean;
    GeometryTolerance: Double;
    MaxPagePairs, MaxItems, MaxChanges, MaxStringBytes: Integer;
    MaxTotalStringBytes, MaxComparisons: Int64;
    class function Default: TPdfSemanticDiffOptions; static;
  end;
  TPdfSemanticDiffReport = record
    Complete: Boolean;
    Changes: TPdfSemanticChanges;
    AddedCount, RemovedCount, ChangedCount, AmbiguousCount: Integer;
    ComparedItemCount: Integer;
    ErrorMessage: string;
  end;

// Indices are zero based. Nil PagePairs selects positional pairing. Explicit
// pairs must cover both documents exactly once; -1 denotes an absent side
// Identity is scoped to a mapped page and item kind. Missing names and repeated
// names (including repeated widgets of one field) are reported as ambiguous
// No rendering, focus changes, form actions, or positional identity guessing
// are performed. Pages are opened independently of the caller's current page
// The supported profile covers strings, flags, colors, opacity, borders,
// markup/line/vertex/ink geometry, URI actions, field values/options/checks,
// and optionally appearance streams. Arbitrary dictionaries, embedded files,
// script actions, non-URI destinations, and non-widget fields are not compared
function ComparePdfSemantics(BeforePdf, AfterPdf: TPdf;
  const PagePairs: TPdfDiffPagePairs; const Options: TPdfSemanticDiffOptions;
  out Report: TPdfSemanticDiffReport): Boolean;

// Bounds remain in PDF user space, in points. Transform with the destination
// page's rotation/crop/viewport rather than treating them as bitmap pixels
function BuildSemanticDiffOverlays(const Report: TPdfSemanticDiffReport):
  TPdfSemanticOverlays;