声明式布局 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 启动和结束目标文档,为每个新部分创建新页面,在延续页面上重复部分家具,并返回页面、放置、拆分、家具、结构、标记内容、工件和最大延续统计

在调用 Render 前设置所有 THotPDF 输出、压缩、一致性、图层和立即刷新选项

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 为 true 时,拆分需要容纳所有前导表头行和至少一个正文行的空间,防止仅表头的延续页面

分页与失败边界

渲染器首先对照剩余正文矩形重新测量每个组件,在可能时将不可拆分的最小片段移动到新页面,并将每个有效拆分委托给 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