Декларативный Layout DOM

HPDFLayoutDOM строит переиспользуемые компоненты документа поверх THPDFLayoutElement, MeasureLayoutElement, PlaceLayoutElement, принадлежащих фрагментов переполнения и ImmediateFlushLayout

Композиция документа и секций

Document := THPDFDOMDocument.Create;
Renderer := THPDFDOMRenderer.Create;
try
  Section := Document.AddSection;
  Section.PageWidth := 595.28;
  Section.PageHeight := 841.89;
  Section.Header := THPDFDOMText.Create('Quarterly report');
  Section.Footer := THPDFDOMText.Create('Confidential');
  Section.Body.Style.Padding := 12;
  Section.Body.Style.Spacing := 8;
  Section.Body.AddText(BodyText, 'Narrative');

  PDF.OutputStream := Output;
  PDF.ImmediateFlushLayout := True;
  Statistics := Renderer.Render(Document, PDF);
finally
  Renderer.Free;
  Document.Free;
end;

THPDFDOMDocument владеет своими секциями, каждая THPDFDOMSection владеет телом, колонтитулами и стилем, а каждый стек или контейнер владеет присоединёнными к нему компонентами

THPDFDOMRenderer.Render открывает и закрывает целевой документ, создаёт новую страницу для каждой секции, повторяет оформление секции на страницах продолжения и возвращает статистику по страницам, размещению, разрывам, оформлению, структуре, marked-content, артефактам и максимальной глубине продолжения

Настройте все опции THotPDF — вывод, сжатие, соответствие стандартам, слои и immediate flush — до вызова Render

GenerateStructure по умолчанию равен True, поэтому рендерер дополнительно строит логическое дерево структуры, устойчивое к разрывам страниц, и подставляет THPDFDOMDocument.Language, если у целевого документа язык не задан

Компоненты

Все компоненты предоставляют стабильные контракты Name, Path, Style, Clone, Measure, Draw и Split, а также семантическую роль, язык, альтернативный текст, замещающий текст, текст расширения и переопределения артефактов

Обход тела верхнего уровня линеен и не клонирует компоненты: продолжения текста и таблиц сохраняют метаданные диапазонов или срезов строк вместо копирования всего дерева содержимого

Наследование стилей

THPDFDOMStyle разрешает имя шрифта, размер, начертания, цвет текста, фон, границу, отступы, интервалы и межстрочный интервал по цепочке родителей

Стиль секции — родитель для её тела и оформления, стиль стека или контейнера — родитель для его дочерних компонентов, а стиль таблицы передаётся от строк к ячейкам

Родителя переопределяют только явно заданные значения: Clear удаляет локальные присваивания и ссылку на родителя, а Assign копирует локальные присваивания, не копируя владение и наследование

Цепочки родителей глубже 64 уровней отклоняются как циклические или бесконечные

Фабрики переиспользуемых компонентов

THPDFDOMComponentFactory — анонимная функция, которая при каждом вызове создаёт один экземпляр THPDFDOMComponent, которым владеет вызывающий код

Document.RegisterComponent('notice',
  function: THPDFDOMComponent
  begin
    Result := THPDFDOMContainer.Create(
      THPDFDOMText.Create('Reusable notice'));
  end);

Section.Body.Add(Document.CreateComponent('notice'));

Имена фабрик уникальны и не зависят от регистра, каждый вызов обязан возвращать новый экземпляр компонента, а принимающий контейнер получает владение после Add

Используйте SetHeaderClone, SetFooterClone или Clone, когда один объявленный компонент нужно переиспользовать в нескольких местах владения

Таблицы с повторяющимся заголовком

Table := THPDFDOMTable.Create('Orders');
Table.AddColumn(1);
Table.AddColumn(3);
Header := Table.AddRow(18, True);
Header[0].Text := 'ID';
Header[1].Text := 'Description';

Row := Table.AddRow(22);
Row[0].Text := '1001';
Row[1].Text := 'Bounded streaming layout';
Section.Body.Add(Table);

Строки заголовка должны идти подряд перед строками данных, положительные веса колонок делят доступную ширину, а высоты строк задаются явными положительными значениями

Когда RepeatHeaders включён, разрыв требует места для всех начальных строк заголовка и хотя бы одной строки данных — страницы продолжения из одних заголовков исключены

Пагинация и границы отказов

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

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

MaximumContinuationDepth по умолчанию равен 100 000 и ограничивает некорректные компоненты, которые раз за разом возвращают продолжение без продвижения

Размеры страниц секции должны быть положительными, поля и зазоры оформления — неотрицательными, а геометрия колонтитулов обязана оставлять прямоугольник тела положительной площади

C++Builder

std::unique_ptr<THPDFDOMDocument> document(new THPDFDOMDocument());
THPDFDOMSection* section = document->AddSection();
section->Header = new THPDFDOMText(L"Report", "Header");
section->Body->AddText(L"Declarative content", "BodyText");

std::unique_ptr<THPDFDOMRenderer> renderer(new THPDFDOMRenderer());
THPDFDOMRenderStatistics statistics =
    renderer->Render(document.get(), pdf.get());

Сгенерированный HPDFLayoutDOM.hpp экспортирует те же интерфейсы документа, стилей, компонентов, таблиц, секций, рендерера и статистики

Связанные API