Декларативный 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, если у целевого документа язык не задан
Компоненты
THPDFDOMTextоборачивает текст Unicode, кэширует границы строк по ширине и унаследованным метрикам текста и разбивается через диапазоны символов источника без копирования исходного текстаTHPDFDOMSpacerрезервирует вертикальное пространство и может разрываться между страницамиTHPDFDOMStackраскладывает дочерние компоненты вертикально с унаследованными отступами и интерваламиTHPDFDOMContainerдобавляет стилизованную рамку вокруг единственного дочернего компонента и пробрасывает продолжения при разрывеTHPDFDOMTableвычисляет взвешенные колонки, рисует стилизованные строки и ячейки и повторяет начальные строки заголовка на страницах продолженияTHPDFDOMListсоздаёт нумерованные и ненумерованные элементы списка с компонентами метки и содержимогоTHPDFDOMImageвладеет клоном изображения, разрешает явные размеры и предоставляет семантику рисунка и управление сжатием
Все компоненты предоставляют стабильные контракты 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 экспортирует те же интерфейсы документа, стилей, компонентов, таблиц, секций, рендерера и статистики