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 的細節請見 Typography。混合的拉丁文、阿拉伯文與數字內容會正確排序,而阿拉伯文後面的數字會保持其數位由左至右。
阿拉伯文也會採用情境字形塑形:引擎會為每個字母選用起始、中間、結尾或孤立形式,並套用 Lam-Alef 連字。塑形需要一個字元對映涵蓋 Arabic Presentation Forms-B 區塊的已註冊字型;僅含拉丁字元的字體,包括 standard-14 字型,無法繪製阿拉伯文。在表格中,每個儲存格會各自重排與塑形,並在 direction: rtl 之下對齊到起始(右側)邊緣。RTL 適用於阿拉伯文、希伯來文、波斯文與烏爾都文;希伯來文會被重排,但不會被塑形。
請以 CSS direction 屬性設定方向——HTML dir 屬性不會對映到它。非表格區塊與行內文字的水平對齊,以及 text-align: justify,皆尚未套用。如需可執行的阿拉伯文發票範例與目前限制的完整清單,請見 Render right-to-left Arabic 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)路徑;這與既有對協定相對(//)URL 的拒絕,以及僅允許 http(s) 或相對路徑的允許清單規則並行。反斜線會在檢查之前正規化為正斜線,因此 Windows 絕對路徑的本機檔案引入或 SMB 共享擷取——兩者皆不帶 URI scheme——都無法落入「無 scheme,因此視為相對路徑」的分支。
CSS 支援對照表節錄(僅列已驗證的列)
標題為「CSS 支援對照表節錄(僅列已驗證的列)」的區段本頁不重複列出各屬性的支援狀態。CSS 支援對照表 是各 W3C 模組已驗證狀態的唯一權威來源,其中也標示哪些模組屬於 Verified(已驗證)、哪些屬於 Claimed(聲稱)。
符合性
標題為「符合性」的區段這個子系統在固定的規格版本上實作一份精選的 CSS 子集。階層的行為規格對映已連同條號與 chunk 識別碼記載於 css-resolver 一節。各模組的符合性狀態列於 CSS 支援對照表。
商業情境
標題為「商業情境」的區段企業版能力。 Premium 以完全相同的單趟管線擴大 CSS 涵蓋範圍(進階列印與額外模組)。各版本之間的架構、上限與各層契約都相同。請見 CSS 支援對照表。