HTML:HTML+CSS 转 PDF 绘制子系统
HTML 子系统会通过单趟向前扫描,将 HTML+CSS 转换成 PDF 内容流。它是整个引擎中规模最大、风险最高的子系统(src/Html/ 下有 324 个文件)。
composer require nextpdf/core:^3概念总览
标题为“概念总览”的章节HTML 子系统是一个单趟流式 HTML+CSS 转 PDF renderer。它唯一的公开接口是 Document::writeHtml()。内部,HtmlParser 会在单趟向前扫描中对输入进行 tokenize(标记化)、resolve(解析)样式、计算布局,并输出 PDF 运算符——整个过程中不保留任何文档树。
先明确适用范围。这个子系统不是保留式文档 renderer。它不持有元素图(element graph),不会对已写出的内容重新进行布局,也不允许在解析开始之后改动输入。它只在固定的规格版本上实现一份精选的 CSS 子集。有两份架构决策在约束它。ADR-001 固定了单趟流式模型及其上限。ADR-010 固定了四层契约(CSS 解析、样式状态、布局、绘制),以及分页媒体与测量的附属层。
HtmlParser 在模块清单中被列为 critical(关键)风险等级。有五个文件带有已记载的危险区标注:HtmlParser 协调器(流式 tokenizer,超过 1000 行代码)、HtmlStyleState(含 100 多个 CSS 属性字段,采用堆栈继承模型)、HtmlBlockHandler(块派发,与样式状态耦合)、FlexLayoutEngine(完整的 flex 测量与布局),以及 TableParser(跨分页处理 colspan/rowspan 的分页逻辑)。在这里做变更时,请按 plan-mode(规划模式)处理。
本页是入口点。详细内容请参阅这些页面:pipeline 说明各阶段顺序、css-resolver 说明层叠与优先级、layer-contracts-adr010 说明各层边界,以及 streaming-constraints-adr001 说明不保留文档树的模型及其上限。
从右至左与双向文本
标题为“从右至左与双向文本”的章节writeHtml() 能渲染从右至左(RTL)的内容。请在 body、某个表格或任意元素上设置 CSS direction: rtl 属性。引擎会通过排版层的双向引擎,以 Unicode 双向算法(UAX #9)解析其视觉顺序——BidiEngine 的细节请见 排版。拉丁文、阿拉伯文与数字混排的内容会正确排序,而阿拉伯文之后的数字会保持其各位数字从左至右。
阿拉伯文还会进行上下文塑形:引擎会为每个字母选择起始形、中间形、结尾形或独立形,并应用 Lam-Alef 连字。塑形需要一个其字符映射涵盖 Arabic Presentation Forms-B 区块的已注册字体;仅含拉丁字符的字样(包括 standard-14 字体)无法绘制阿拉伯文。在表格中,每个单元格都会各自重排与塑形,并在 direction: rtl 下对齐到起始(右)边缘。RTL 适用于阿拉伯文、希伯来文、波斯文与乌尔都文;希伯来文会被重排,但不会被塑形。
请使用 CSS direction 属性设置方向——HTML 的 dir 属性不会映射到它。非表格的块级与内联文本的水平对齐,以及 text-align: justify,尚未应用。可运行的阿拉伯文发票范例与当前限制的完整列表,请见 渲染从右至左的阿拉伯文 HTML。
API 接口
标题为“API 接口”的章节| 符号 | 位置 | 角色 |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | 公开入口点。在当前光标位置绘制 HTML。 |
Document::createStandalone(): self | src/Core/Document.php | 构建独立(standalone)文档。 |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | 内部协调器。 |
HtmlRenderResult | src/Html/HtmlRenderResult.php | 不可变结果:流、结束光标、已使用的字体。 |
DefaultHtmlSecurityPolicy | src/Html/DefaultHtmlSecurityPolicy.php | 默认 tag/attribute/CSS/URL 策略。 |
HtmlSecurityPolicyInterface | src/Contracts/HtmlSecurityPolicyInterface.php | 供自定义策略使用的策略契约。 |
代码示例——快速上手
标题为“代码示例——快速上手”的章节取自 examples/08-html-basic.php。
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();$doc->writeHtml('<h1 style="color:#1E3A8A;">HTML Rendering</h1><p>Direct to PDF.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');代码示例——生产环境
标题为“代码示例——生产环境”的章节一份带内嵌样式块的表格报表,模板来自 examples/09-html-table.php。
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInventory(string $rowsHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Inventory'); $doc->addPage();
$html = '<style>table { width: 100%; } ' . 'th { background-color: #1E3A8A; color: #FFFFFF; }</style>' . '<table border="1" cellpadding="5">' . $rowsHtml . '</table>';
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Input cap, element cap (50,000), or nesting cap (100). Do not retry. throw $e; }
$doc->save($out);}边界情况与注意事项
标题为“边界情况与注意事项”的章节- 精选的 CSS 子集。 支持程度因模块而异,且已固定版本。依赖某个属性之前,请先查阅 CSS 支持对照表。
- 硬性上限会抛出异常。 10 MB 输入、
50,000个元素、100 层嵌套——每一项超出都会抛出HtmlParsingException。参见 流式限制。 - 不会重新进行布局。 输出按文档顺序一次写出;较晚出现的样式无法改变先前的输出。
:has()受开关控制,需开启css.has实验性功能。- 关键风险子系统。 有五个危险区文件。在
src/Html/下做变更时请使用 plan mode(规划模式)。
单趟流式限制(ADR-001)
标题为“单趟流式限制(ADR-001)”的章节renderer 不保留任何文档树,而是以单趟向前扫描执行。元素、嵌套与输入的上限都是硬性限制。完整细节与 worker 安全契约请见 流式限制(ADR-001)。
各层契约(ADR-010)
标题为“各层契约(ADR-010)”的章节CSS 解析、样式状态、布局与绘制被切分成四层,彼此通过单向契约相连,另有分页媒体与测量的附属层。完整细节请见 各层契约(ADR-010)。
大型文档的内存预算
标题为“大型文档的内存预算”的章节样式状态与光标的内存用量是 O(嵌套深度),而非 O(元素数量)。每页的 performance_budget 是 peak_mb: 64。50,000 个元素的上限是硬性上限;较大的输入请拆分为多次 writeHtml() 调用。细节请见 流式限制。
遍历的复杂度为 O(token 数量)。表格列宽计算还会为每个表额外执行一次有界的行扫描。可选的 :has() 预扫描会额外执行一趟有界的 token 列表扫描。HTML 绘制管线的性能基准测试会强制执行 5% 的回归门槛(已合并的工作,PR #564)。每页的 performance_budget(wall_ms: 1500、peak_mb: 64)是运行层面的上限。
安全说明
标题为“安全说明”的章节DefaultHtmlSecurityPolicy 会强制执行标签、属性、CSS 属性与 URL scheme 的允许列表,并施加 10 MB 的输入上限与 100 层的嵌套上限——而且独立于 parser 之外。CSS 属性允许列表就是安全上限。运行时的支持表是另一个独立的能力上限。若要提供更严格的策略,请实现 HtmlSecurityPolicyInterface。外部资源的获取则由 DefaultExternalResourcePolicy 另行管控。
在 href 与图像 src 值中,URL 允许列表还会拒绝以反斜线为根(\…)以及 UNC(\\host\share)的路径;这一规则与既有的协议相对(//)拒绝规则,以及仅允许 http(s) 或相对路径的允许列表共同生效。反斜线会在检查之前先规范化为正斜线,因此 Windows 绝对路径的本地文件引入,或一次 SMB 共享获取——两者都不带 URI scheme——都不会落入「没有 scheme,因此视为相对路径」这条分支。
CSS 支持对照表节选(仅列已验证的行)
标题为“CSS 支持对照表节选(仅列已验证的行)”的章节本页不重述各属性的支持状态。CSS 支持对照表 是各 W3C 模块已验证状态的唯一权威来源,其中也列明哪些模块属于 Verified(已验证),哪些属于 Claimed(声称)。
符合性
标题为“符合性”的章节这个子系统在固定的规格版本上实现一份精选的 CSS 子集。层叠行为的规格映射已连同条号与 chunk 标识符记载于 css-resolver 一节。各模块的符合性状态列于 CSS 支持对照表。
商业情境
标题为“商业情境”的章节企业版能力。 Premium 在完全相同的单趟管线上扩大了 CSS 覆盖范围(高级打印与额外模块)。各版本之间的架构、上限与各层契约都相同。请见 CSS 支持对照表。