Technical Article

Импорт и экспорт аннотаций PDF в виде XFDF в Delphi

HotPDF экспортирует и импортирует аннотации PDF в виде XFDF с помощью двух функций, действующих на загруженный в данный момент документ: ExportLoadedAnnotationsToXFDF и ImportLoadedAnnotationsFromXFDF. XFDF — это формат обмена аннотациями на основе XML, стандартизированный как ISO 19444-1. Данная пара функций позволяет приложению на Delphi или C++Builder передавать свои комментарии в Acrobat или сторонний инструмент проверки и получать обратно результаты разметки, и все это без изменения содержимого самой страницы, на которой расположены аннотации

Представьте два направления, которые решает данный подход. Рецензент открывает созданный вами отчет в Acrobat, ставит красную стрелку на неровный рисунок, обводит неправильный итог и пишет заметку на полях, а затем экспортирует комментарии в небольшой файл XFDF. Или наоборот: ваша программа сама создает разметку, и вам нужно отправить ее кому-то, чьим инструментом является не HotPDF. В обоих случаях аннотации передаются в формате XML, который понимают обе стороны, а страницы PDF байт в байт остаются прежними

В чем разница между FDF и XFDF?

Форматы FDF и XFDF несут одну и ту же информацию в двух разных синтаксисах, и это различие имеет значение, как только вы решите передать файл другому инструменту. FDF — это более старый формат данных форм (Forms Data Format), определенный в самой спецификации PDF: он использует синтаксис объектов PDF, поэтому файл FDF выглядит как урезанный PDF и требует для чтения парсера, понимающего PDF. XFDF — это XML-представление тех же данных, стандартизированное независимо как ISO 19444-1, что означает, что любая библиотека XML на любой платформе может открыть, сравнить или сгенерировать его. Оба формата могут содержать значения полей форм в дереве <fields>, которым управляет пункт 6.3 стандарта ISO 19444-1, и аннотации в дереве <annots>. HotPDF разделяет эти обязанности, направляя данные форм через ExportLoadedFormToXFDF и резервируя ExportLoadedAnnotationsToXFDF для стороны <annots>. При обмене комментариями с веб-службой, сервером проверки на Java или скриптом, XFDF — это формат, который не заставляет другую сторону внедрять парсер PDF

Как экспортировать аннотации PDF в виде XFDF в Delphi?

HotPDF экспортирует аннотации путем обхода каждой страницы загруженного документа, генерируя один элемент XFDF для каждой поддерживаемой аннотации и возвращая количество записанных аннотаций. Сначала загрузите PDF, а затем вызовите ExportLoadedAnnotationsToXFDF с целевым путем. Результатом функции является количество сериализованных аннотаций; результат равный нулю или меньше означает, что ничего не было экспортировано и файл не был записан, что является сигналом о том, что документ не содержал аннотаций поддерживаемого подтипа

var
  Pdf: THotPDF;
  Written: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report-reviewed.pdf', '') > 0 then
    begin
      // Write one XFDF element per supported annotation on every page
      Written := Pdf.ExportLoadedAnnotationsToXFDF('comments.xfdf');
      if Written <= 0 then
        ShowMessage('No supported annotations were found');
    end;
  finally
    Pdf.Free;
  end;
end;

Полученный XFDF представляет собой простой читаемый XML. HotPDF записывает корневой тег <xfdf> в пространстве имен ISO 19444-1, контейнер <annots> и по одному дочернему элементу для каждой аннотации с ее индексом страницы от нуля, цветом и геометрией в качестве атрибутов или дочерних элементов. Линия с желтой заливкой и открытой стрелкой, расположенная рядом с заполненным многоугольником, сериализуется следующим образом

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/">
  <annots>
    <line page="0" start="72,700" end="220,700"
          color="#FF0000" interior-color="#FFFF00"
          head="OpenArrow" tail="None">
      <contents-richtext>Baseline looks off</contents-richtext>
    </line>
    <polygon page="0" color="#0000FF" interior-color="#CCE5FF">
      <vertices>72,120;180,120;180,200;72,200</vertices>
    </polygon>
  </annots>
</xfdf>

Как подтипы аннотаций сопоставляются с элементами XFDF

Каждый подтип аннотации сопоставляется с определенным элементом ISO 19444-1 со своим геометрическим представлением, и HotPDF следует этим структурам, а не изобретает собственные. Линейные аннотации несут атрибуты start и end, содержащие координаты двух конечных точек, взятые непосредственно из массива L аннотации, в то время как стили окончаний линий LE становятся атрибутами head и tail. Аннотации многоугольников (polygon) и ломаных линий (polyline) переносят свой список точек в дочерний элемент <vertices> в виде разделенных точкой с запятой пар x,y, а не атрибута, поскольку средство чтения, ожидающее дочерний элемент, просто пропустит точки, скрытые где-либо еще. Рисунки от руки (ink), которые могут содержать несколько отдельных штрихов, вкладывают элемент <inklist> с одним дочерним элементом <gesture> для каждого штриха, поэтому подпись, состоящая из нескольких штрихов, сохраняется в виде отдельных жестов, а не одной объединенной кривой

Форматированный текст, цвет и стиль границы сохраняются вместе с геометрией. Текст заметки записывается как дочерний элемент <contents-richtext>; внутренняя заливка, которую PDF сохраняет в массиве IC (заливка внутри круга, квадрата, многоугольника или стрелки линии, а также заливка области удаления конфиденциальных данных), передается как атрибут interior-color в формате #RRGGBB; а ширина границы, шаблон штрихов и эффект облачной границы сопоставляются с атрибутами width, dashes, style и intensity, поэтому выноска с облачным контуром сохраняет свой вид. HotPDF также сохраняет всплывающее окно, прикрепленное к аннотации разметки, импортируя геометрию дочернего элемента всплывающего окна и его состояние (открыто или закрыто) в словарь Popup аннотации, а также переносит состояние открытой аннотации и рецензирования, благодаря чему проверенный документ сохраняет не только свои формы, но и метаданные рабочего процесса, на которые полагаются рецензенты

Импорт XFDF обратно в загруженный документ

HotPDF импортирует XFDF путем разбора XML, создавая новую аннотацию для каждого элемента через NewLoadedAnnotation, прикрепляя ее к странице, имя которой указано в элементе, и возвращая количество добавленных аннотаций. Этот рабочий процесс симметричен экспорту: загрузите базовый PDF, вызовите ImportLoadedAnnotationsFromXFDF с файлом рецензента, а затем сохраните загруженный документ, чтобы записать новые разметки. Если файл отсутствует или XML не разбирается, функция возвращает ноль, а загруженный документ остается нетронутым

var
  Pdf: THotPDF;
  Added: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf', '') > 0 then
    begin
      Added := Pdf.ImportLoadedAnnotationsFromXFDF('comments.xfdf');
      if Added > 0 then
        Pdf.SaveLoadedDocument('report-annotated.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Поскольку каждый элемент XFDF содержит собственный индекс страницы, аннотации попадают на те страницы, для которых они были созданы, даже если вы импортируете несколько файлов последовательно. Это делает безопасным сбор комментариев от нескольких рецензентов в один загруженный документ перед сохранением. Приведенный ниже пример объединяет комментарии от двух рецензентов в одну мастер-копию. О том, как создавать и редактировать объекты аннотаций в коде, а не обмениваться ими в виде файлов, см. статью о том, как HotPDF создает и редактирует объекты аннотаций PDF напрямую из Delphi

var
  Pdf: THotPDF;
  Total, I: Integer;
  Files: array[0..1] of string;
begin
  Files[0] := 'alice-comments.xfdf';
  Files[1] := 'bob-comments.xfdf';
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('master.pdf', '') > 0 then
    begin
      Total := 0;
      for I := Low(Files) to High(Files) do
        Inc(Total, Pdf.ImportLoadedAnnotationsFromXFDF(Files[I]));
      if Total > 0 then
        Pdf.SaveLoadedDocument('master-merged.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Что передается корректно, а что нет

HotPDF полностью поддерживает подтипы аннотаций, определенные стандартом ISO 19444-1, и намеренно пропускает остальные, вместо того чтобы генерировать некорректный XML, который средство чтения может истолковать неверно. Поддерживаемый набор охватывает типы разметки, которые преобладают в реальной работе по рецензированию: текстовые заметки, свободный текст, линии, квадраты, круги, многоугольники, ломаные линии, четыре типа разметки текста (выделение, подчеркивание, зачеркивание и волнистая линия), штампы, рисунки от руки и вставки, а также вложения файлов, звук, удаление конфиденциальных данных и ссылки — всего восемнадцать подтипов. Аннотация, подтип которой не входит в этот список, пропускается при экспорте, и поскольку она пропускается, а не записывается пустой, она не влияет на число, возвращаемое функцией

Форматированный текст имеет свои нюансы. HotPDF сохраняет тело <contents-richtext>, поэтому форматированный текст и обычное содержимое переносятся, но XFDF переносит текст комментария и разметку стиля, а не готовый поток внешнего вида. Принимающее приложение перерисовывает всплывающее окно со своими собственными шрифтами и макетом, а не воспроизводит точные пиксели HotPDF. Относитесь к переносу как к сохранению содержимого и намерений автора, а не точного экранного рендеринга до пикселя. Если ваше форматированное содержимое находится в данных формы XFA, а не в потоках аннотаций, правила будут иными, и статья о том, как HotPDF обрабатывает exData XFA, форматированный текст и гиперссылки, описывает этот отдельный путь

Работа с символами на посимвольном уровне строже, чем кажется на первый взгляд, что гарантирует надежность. HotPDF применяет правила экранирования пункта 5.8.2 стандарта ISO 19444-1 при записи текста, кодируя XML-значимые символы и управляющие байты, поэтому комментарий, содержащий амперсанд, угловую скобку или разрыв строки, создает корректный XML, который принимает любой совместимый парсер, и декодирует те же правила при импорте. Вот почему заметка, скопированная из таблицы со всеми знаками препинания, возвращается неповрежденной, не нарушая структуру файла

Обмен аннотациями — это лишь одна из функций API загруженных документов, и она отлично сочетается с остальными: импортируйте XFDF рецензента, настройте страницы или отредактируйте метаданные документа, сделайте плоским или переопределите разрешения файла, а затем экспортируйте свежий XFDF для следующего раунда проверки. Все эти функции входят в стандартную поставку компонента HotPDF для Delphi и C++Builder, справочное руководство к которому содержит информацию о поддержке всех подтипов аннотаций и функциях обмена данными форм в XFDF