PDFium Component Docs

Semantyczne porównanie adnotacji i formularzy

ComparePdfSemantics porównuje właściwości adnotacji i widgetów AcroForm niezależnie od renderowania strony; wartości formularzy mogą się zmienić nawet wtedy, gdy piksele wyglądu pozostają identyczne

Przekaż TPdfDiffPagePairs z wyrównania stron albo jawne mapowanie; nil wybiera pary pozycyjne, a jawne mapowania muszą obejmować oba dokumenty dokładnie raz, używając -1 dla brakującej strony

Tożsamość adnotacji opiera się na jej nazwie /NM, a tożsamość widgetu formularza na w pełni kwalifikowanej nazwie pola; tożsamość jest ograniczona do zmapowanej strony i rodzaju elementu

Brakujące i powtórzone nazwy, włącznie z wieloma widgetami jednego pola na tej samej stronie, są raportowane jako psckAmbiguous z jawnym powodem; kolejność tablicy adnotacji nie decyduje o tożsamości

Obsługiwany profil porównuje ciągi, flagi, kolory, przezroczystość, obramowania, markup, geometrię linii, wierzchołków i tuszu, akcje URI, wartości pól, etykiety list i wybrane opcje oraz stan checkboxów i przycisków radio

CompareAppearanceStreams opcjonalnie porównuje treść strumieni wyglądu adnotacji; domyślnie jest wyłączone

CompareAnnotations i CompareForms wybierają odpowiednie rodzaje elementów; GeometryTolerance domyślnie wynosi 0.001 punktu przestrzeni użytkownika PDF

Dodane, usunięte i zmienione elementy zawierają właściwości i granice przed/po; BuildSemanticDiffOverlays zwraca osobne prostokąty przed/po z indeksami strony i zmiany

Wszystkie indeksy liczą się od zera, a granice pozostają w przestrzeni użytkownika PDF, w punktach; przed malowaniem do bitmapy zastosuj odpowiedni obrót, przycięcie i transformację viewportu strony

Strony są wczytywane z niezależnymi uchwytami natywnymi, zachowując bieżącą stronę i fokus formularza wywołującego oraz unikając akcji formularzy

Profil wyklucza pola inne niż widgety, dowolne słowniki własne, pliki osadzone, akcje skryptów i cele inne niż URI; porównanie XFA jest jawnie odrzucane

Domyślne limity to 10,000 par stron, 4,096 skanowanych elementów, 4,096 zmian, 1 MiB na ciąg, 16 MiB łącznej objętości ciągów i 16,777,216 porównań; wyczerpanie budżetu odrzuca niekompletne wyjście

Complete odróżnia udane pełne porównanie od odrzuconego; jego zmiany mogą obejmować jawnie niejednoznaczne tożsamości, więc przed uznaniem wyników za ostateczne dopasowanie elementów sprawdź AmbiguousCount

Rzeczywista akceptacja Delphi/FPC Win32/Win64 obejmuje 92 asercje na cel, w tym zapisane/ponownie otwarte dokumenty, zmiany wartości przy identycznych pikselach, tożsamość Unicode, przeniesienia stron, niejednoznaczności i budżety

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

Public declarations

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;