HTML5 分页媒体导入

THPDFHTMLImporter.RenderHTML5 将宽容的 HTML5 标记和打印 CSS 转换为分页 PDF 内容,同时保留紧凑的旧版 RenderHTML 路径

CSS 长度和导入器的 Margin、BaseFontSize、ListIndent、BlockSpacing 都以 point 为单位,因此无论 THotPDF.Resolution 设成多少,两个渲染器产出的页面都一致;导入前后你自己绘制的内容仍使用 1/Resolution inch

声明

function RenderHTML5(
  const HTML: WideString;
  const AuthorStyleSheet: WideString = ''
): Boolean;

function HPDFRenderHTML5Document(
  Doc: THotPDF;
  const HTML: WideString;
  const AuthorStyleSheet: WideString = '';
  MarginPt: Single = 72;
  const FontName: AnsiString = 'Arial';
  FontSize: Single = 12
): Boolean;

配置文件契约

HTML5ProfileVersion 返回 1,HTML5ProfileMilestones 报告解析器与级联、分页布局、表格与表单以及有界资源

测量段落与书写方向

段落换行使用当前字体测得的步进,包括字体切换、粗体和斜体走向、字距、词距、显式换行和东亚字符边界;对齐与装饰分别作用于得到的每一行

direction: ltr、direction: rtl 和 HTML dir 属性选择段落方向;dir="auto" 采用第一个强字符的 Unicode 方向

在 Windows 上,双向文字走向用 Uniscribe 解析并跨样式边界重排,既有的 PDF 文本引擎负责每个走向内的字形整形;该行的文档方向、查看器偏好和已保存的页面文本状态随后恢复

内联方向覆盖、bdi 和 bdo 目前沿用段落排序并产生 hdkLayoutFallback 诊断;unicode-bidi 不在此配置文件内,文字整形仍遵循文档的整形配置

段落跨页拆分

widows 和 orphans 是可继承的正整数,默认都是 2;分页使用测得的行盒,而不是估算的字符数

导入器会移动段落或调整拆分位置,使分页符前后都保留所请求的最少行数;break-inside: avoid 在段落能放进新的一页时保持段落完整

当一页放不下所请求的约束时,渲染会放宽约束继续推进并记录 hdkPaginationConstraint;每个页面片段都有自己的背景和边框

可选连字符

hyphens: none 抑制自由断行,默认的 hyphens: manual 使用 U+00AD 或 ­;只有选中的断点被使用时才输出可见连字符

hyphens: auto 还会带着单词和继承的 HTML lang 值调用 OnHyphenate;没有回调时保留手动断点并报告布局回退,因为不附带任何语言词典

断点位置从单词起点按 UTF-16 代码单元计数;无效、越界、拆在代理对中间以及基本的拆在组合附标中间的位置会被忽略

THPDFHTMLHyphenationEvent = procedure(
  Sender: TObject;
  const WordText, Language: WideString;
  var BreakPositions: TArray<Integer>
) of object;

有界的 flex 和 grid 盒子

display: flex 支持 row、row-reverse、column 和 column-reverse;行内子项使用显式宽度或分享剩余宽度,正的 flex-grow 值按权重分配额外空间

行支持 justify-content 的 start、end、center、space-between、space-around 和 space-evenly,以及 start、end、center 和 stretch 的交叉轴对齐;列流支持自然的竖向布局,对不支持的固定高度分配或交叉轴对齐发出诊断

display: grid 支持正的固定长度和 fr 列轨道,包括最多 64 列的有界 repeat(n, tracks);单元格按源顺序放置,逐行填充

grid-column: span N 和 grid-column-end: span N 允许子项占据连续的轨道及其间的间隙;放不进当前行的条目移到下一行,跨度超过轨道数会产生布局回退

flex-wrap: wrap 在下一个条目的显式宽度和间隙放不下时另起一行;每行独立应用 flex-grow 和 justify-content,而 row-reverse 和 RTL 只在行内反转位置,不在行间移动条目

gap 接受一个或两个长度,并可用 row-gap 和 column-gap 分别覆盖;平行的行保持在同一页上,并在绘制之前检查

并行子项支持带内联样式的文本块、可递归嵌套的普通块容器(含内边距、边框和背景)、嵌套的 flex 和 grid 容器、图像,以及静态或原生表单控件

图像使用回调提供或 data URI 字节,未指定高度时保持固有纵横比,每个 DOM 节点只解码一次;预检和回退复用同一份缓存图像,不再消耗额外的资源请求

所有子盒在任何并行行绘制之前完成测量,因此不支持或超限的内容会回退到竖向页面流,不会重复绘制已画好的行;嵌套规划以 64 层为界,并消耗既有的布局操作预算

没有显式宽度的可换行子项独占一整行;并行子项内的表格和列表、flex basis 与 shrink、wrap-reverse、固有轨道尺寸、grid 行轨道与行跨度以及显式 grid 放置仍在此配置文件之外,会产生可观察的诊断

不支持的 CSS 诊断

Diagnostics 暴露包含 Kind、Subject、Value 和 MessageText 的记录;OnDiagnostic 在渲染期间接收同样的信息

未知属性、不支持的值、不支持的选择器和不支持的 at 规则会被忽略并产生诊断,包括本就未被使用的样式表规则里的声明;伪选择器会被跳过,而不是当作普通类型选择器

StrictCSS 默认关闭,开启后在出现诊断时抛出 EHPDFHTMLUnsupportedCSS;此前可能已有内容输出,需要全有或全无导入的调用方应使用单独的文档

MaxDiagnostics 默认 256,限制保留的记录数;达到存储上限后 DiagnosticCount 和回调投递仍然可观察,非正的上限会禁用记录存储

有界资源

外部样式表、图像和 @font-face 字体默认禁用,除非 OnResource 提供其字节,因此 HTML 导入绝不会隐式打开文件或网络连接

@font-face 支持一个 url(...) 来源、可选的 format('truetype') 或 format('opentype')、字族别名、normal 或 italic 样式,以及 normal、bold、400 或 700 字重;font-display 接受标准策略,因为离线导入是同步加载资源

字体必须是可嵌入的 TrueType 或 OpenType sfnt 资源,且 ASCII Windows 字族名不超过 31 个字符;WOFF、字体集合、local(...)、可变字体描述符和来源列表会产生诊断

接受的字体在 Windows 上私密注册进进程内存,并一直由文档持有到文档销毁,因此在 EndDoc 之前释放导入器不会使延迟字体嵌入失效

data: 资源和回调结果共享 MaxResources、MaxResourceBytes 和 MaxTotalResourceBytes 限制

MaxDecodedImageBytes 默认 128 MiB,按每像素四字节独立约束解码图像缓存;BMP 和 PNG 的尺寸在解码前检查,每个接受的图像在保留前也会检查

MaxDOMNodes、MaxCSSRules 和 MaxLayoutOperations 分别约束解析、级联构建和布局工作

THPDFHTMLResourceEvent = procedure(
  Sender: TObject;
  const URI: WideString;
  ResourceKind: THPDFHTMLResourceKind;
  var Data: TBytes;
  var ContentType: string;
  var Handled: Boolean
) of object;

统计

THPDFHTMLImportStatistics 报告配置文件版本、解析节点、CSS 规则、布局操作、分页符、表格、表单控件、资源请求、接受和拒绝的加载、接受的资源字节、测得的文本行、加连字符的行、诊断数、flex 容器和 grid 容器

OnLineLayout 在实际 PDF 文本输出之后接收该行从零开始的页面与段落行索引、原点、测得的宽高、逻辑文本、方向和连字符标志

每次 RenderHTML5 调用都会重置统计记录,预算违规会抛出 EHPDFHTMLImportBudget

示例

Importer := THPDFHTMLImporter.Create(Doc);
try
  Importer.CreateAcroForms := True;
  Importer.MaxResources := 16;
  Importer.RenderHTML5(
    '<style>@page { margin: 36pt } ' +
    'table { width: 100% }</style>' +
    '<h1>Invoice</h1>' +
    '<table><tr><td>Total</td><td>42</td></tr></table>' +
    '<input name="approved" type="checkbox">'
  );
finally
  Importer.Free;
end;

另请参阅: THPDFPage.TextOutHTML、声明式布局 DOM、AcroForm 支持