ComparePdfSemantics compara propiedades de anotaciones y widgets AcroForm al margen del renderizado; un valor puede cambiar aunque los píxeles de apariencia sigan idénticos
Proporcione TPdfDiffPagePairs de la alineación o un mapeo explícito; nil empareja por posición, y los mapeos deben cubrir ambos documentos exactamente una vez, con -1 para el lado ausente
La identidad de anotaciones usa su nombre /NM, y la de widgets el nombre totalmente cualificado del campo; la identidad se limita a la página mapeada y tipo de elemento
Los nombres ausentes o repetidos, incluidos varios widgets del mismo campo en una página, se notifican como psckAmbiguous con motivo explícito; el orden del array no determina la identidad
El perfil compara strings, flags, colores, opacidad, bordes, markup, geometría de líneas, vértices y tinta, acciones URI, valores de campos, etiquetas y opciones seleccionadas y estado de checkbox o radio
CompareAppearanceStreams permite comparar el contenido de flujos de apariencia de anotaciones; está desactivado por defecto
CompareAnnotations y CompareForms eligen los respectivos elementos; GeometryTolerance vale 0.001 puntos del espacio de usuario PDF por defecto
Los elementos añadidos, eliminados o cambiados incluyen propiedades y límites anteriores y posteriores; BuildSemanticDiffOverlays devuelve rectángulos separados antes/después con índices de página y cambio
Todos los índices tienen base cero y los límites siguen en espacio de usuario PDF, en puntos; aplique el giro, crop y transformación de viewport correspondientes antes de dibujar en un bitmap
Las páginas se cargan con handles nativos independientes, conservando la página actual y foco de formulario del llamador y evitando acciones de formulario
Quedan fuera campos sin widget, dictionaries personalizados arbitrarios, ficheros incorporados, acciones de script y destinos no URI; la comparación XFA se rechaza explícitamente
Los límites predeterminados son 10,000 pares de páginas, 4,096 elementos inspeccionados, 4,096 cambios, 1 MiB por string, 16 MiB de strings totales y 16,777,216 comparaciones; agotar un límite rechaza resultados incompletos
Complete distingue la comparación completa correcta de una rechazada; los cambios pueden incluir identidades ambiguas explícitas, así que examine AmbiguousCount antes de tratar el resultado como emparejamiento definitivo
La aceptación real Delphi/FPC en Win32/Win64 cubre 92 assertions por destino, con documentos guardados/reabiertos, cambios de valor con píxeles idénticos, identidad Unicode, movimiento, ambigüedad y límites
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;