PDFium Delphi Component Docs

Семантическое сравнение аннотаций и форм

ComparePdfSemantics сравнивает свойства аннотаций и виджетов AcroForm независимо от рендеринга страниц; значения форм могут измениться, даже если пиксели отображения остались прежними

Передайте TPdfDiffPagePairs от выравнивания страниц или явное сопоставление; nil выбирает позиционные пары, а явное сопоставление должно покрывать оба документа ровно по одному разу, используя -1 для отсутствующей стороны

Идентичность аннотации задаётся её именем /NM, а идентичность виджета формы — полностью квалифицированным именем поля; идентичность ограничена сопоставленной страницей и видом элемента

Отсутствующие и повторяющиеся имена, включая несколько виджетов одного поля на одной странице, сообщаются как psckAmbiguous с явной причиной; порядок аннотаций в массиве не определяет идентичность

Поддерживаемый профиль сравнивает строки, флаги, цвета, прозрачность, границы, разметку, геометрию линий, вершин и чернил, URI-действия, значения полей, подписи вариантов и выбранные опции, а также состояние флажков и переключателей

CompareAppearanceStreams опционально сравнивает содержимое потоков отображения аннотаций; по умолчанию отключено

CompareAnnotations и CompareForms включают соответствующие виды элементов; GeometryTolerance по умолчанию 0.001 пункта пользовательского пространства PDF

Добавленные, удалённые и изменённые элементы содержат свойства и границы «до/после»; BuildSemanticDiffOverlays возвращает отдельные прямоугольники «до/после» с индексами страницы и изменения

Все индексы нуль-базированные, а границы остаются в пользовательском пространстве PDF в пунктах; перед отрисовкой в bitmap примените поворот, crop и преобразование области просмотра соответствующей страницы

Страницы открываются с независимыми нативными дескрипторами, сохраняя текущую страницу и фокус формы вызывающего и избегая действий форм

Профиль исключает поля, не являющиеся виджетами, произвольные пользовательские словари, вложенные файлы, действия-скрипты и назначения, отличные от URI; сравнение XFA явно отклоняется

Лимиты по умолчанию: 10 000 пар страниц, 4 096 просканированных элементов, 4 096 изменений, 1 МиБ на строку, 16 МиБ на все строки и 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;