声明式布局 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
组件
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 为 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 导出相同的文档、样式、组件、表格、部分、渲染器和统计表面