PDFium Delphi Component Docs

Comparaison sémantique des annotations et formulaires

ComparePdfSemantics compare les propriétés des annotations et widgets AcroForm indépendamment du rendu des pages ; les valeurs d’un formulaire peuvent changer alors que les pixels de son apparence restent identiques

Passez les TPdfDiffPagePairs issus de l’alignement des pages ou une correspondance explicite ; nil sélectionne les paires par position ; une correspondance explicite doit couvrir chaque document exactement une fois, avec -1 pour le côté absent

L’identité d’une annotation repose sur son nom /NM, celle d’un widget sur le nom pleinement qualifié du champ ; cette identité est limitée à la page associée et au type d’élément

Les noms absents ou répétés, y compris plusieurs widgets d’un même champ sur une page, donnent lieu à psckAmbiguous avec une raison explicite ; l’ordre dans le tableau des annotations ne détermine pas leur identité

Le profil pris en charge compare les chaînes, indicateurs, couleurs, opacité, bordures, balisages, géométries des lignes, sommets et tracés à main levée, actions URI, valeurs des champs, libellés et options sélectionnées, ainsi que l’état des cases à cocher et boutons radio

CompareAppearanceStreams permet de comparer le contenu des flux d’apparence des annotations ; cette option est désactivée par défaut

CompareAnnotations et CompareForms sélectionnent les types d’éléments concernés ; GeometryTolerance vaut par défaut 0.001 point dans l’espace utilisateur PDF

Les éléments ajoutés, supprimés et modifiés comprennent leurs propriétés et limites avant et après ; BuildSemanticDiffOverlays renvoie des rectangles distincts avant/après avec les indices de page et de changement

Tous les indices commencent à zéro et les limites restent exprimées en points dans l’espace utilisateur PDF ; appliquez la rotation, le recadrage et la transformation de la zone d’affichage de la page avant de dessiner dans un bitmap

Les pages sont chargées avec des handles natifs indépendants, ce qui préserve la page courante et le focus du formulaire appelant et évite de déclencher des actions de formulaire

Le profil exclut les champs sans widget, les dictionnaires personnalisés arbitraires, les fichiers incorporés, les actions de script et les destinations autres qu’URI ; la comparaison XFA est explicitement refusée

Les limites par défaut sont de 10,000 paires de pages, 4,096 éléments inspectés, 4,096 changements, 1 MiB par chaîne, 16 MiB pour l’ensemble des chaînes et 16,777,216 comparaisons ; un budget épuisé fait rejeter le résultat incomplet

Complete distingue une comparaison complète réussie d’une comparaison rejetée ; ses changements peuvent contenir des identités explicitement ambiguës, consultez donc AmbiguousCount avant de considérer les associations comme définitives

La validation réelle Delphi/FPC Win32/Win64 couvre 92 assertions par cible, dont les documents enregistrés et rouverts, les changements de valeur à pixels identiques, les identités Unicode, les déplacements de page, les ambiguïtés et les budgets

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

Déclarations publiques

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;