Content:文字與結構化內容的模型
快速概覽
標題為「快速概覽」的區段Content 模組負責建構文字顯示運算子、文字狀態運算子、文字陰影、文件層級的 JavaScript,以及標記內容(marked-content)的屬性字典。它位於排版與內容串流(content stream)之間。
composer require nextpdf/core:^3概念總覽
標題為「概念總覽」的區段Content 提供將已 resolve(解析)的文字轉成 PDF 運算子的基礎元件。TextRenderer 是核心元件,會為字串建構文字顯示運算子,以及位於其前方的文字狀態運算子。Tj 運算子會以目前的字型與其他文字相關繪圖參數,繪製字串的字形 —— ISO 32000-2 §9。TextRenderer 會依據目前作用中的 TypographyMode,在單一顯示運算子與帶定位的 TJ 陣列之間選擇。當該模式使用 TJ 陣列時,它會套用字距調整。
文字狀態已完整建模。setTextRenderingMode() 接受一個 TextRenderingMode 列舉(enum)。它的八個列舉值一對一對應 ISO 32000-2 的文字繪製模式:填滿、描邊、先填滿再描邊、不可見,以及四種裁剪變體(表 104)。此 renderer(渲染器)也會控制描邊寬度、字元與單字間距、水平拉伸、文字上移(text rise)、由右至左方向,以及一個選用的 Hyphenator。呼叫 buildTextStateOperators() 會將累積的狀態輸出為單一運算子區塊。
TextShadow 是一個值物件(value object)—— 包含顏色、以使用者單位表示的 X 與 Y 偏移量,以及不透明度。renderer 會取用它,輸出第二道帶有偏移的繪製。預設偏移量是細緻的 0.5/−0.5,搭配 0.5 不透明度,對應 CSS 風格的柔和陰影。
JavaScriptManager 掌管文件層級的指令稿。includeJs() 會註冊一段文件指令稿。addJsObject() 會註冊一個具名的指令稿物件。writeJavaScript() / writeOpenAction() 會將它們序列化到目錄(catalog)與 OpenAction 中。在輸出前,此管理器會檢核每一段指令稿主體,並以 PDF 字串進行編碼。
PropertiesRegistry 是標記內容的屬性儲存區。register() 會為一個屬性字典回傳穩定的標籤 Index(索引)。registerOcg() / registerOcgs() 會依物件編號綁定選用內容群組。writeProperties() 會將此登錄序列化到頁面資源字典中。當 ContentStream 模組以屬性清單開啟一段標記序列時,參照的就是這份資料。
有兩個影像解碼器放在這裡,因為它們是 PDF 原生、可直接傳遞(pass-through)的格式。JBig2Loader 與 JpxLoader 會剖析 JBIG2 與 JPEG 2000 的區段結構,並回傳 ImageData,過程中完全不會將像素點陣化。編碼後的位元組會原封不動地傳給檢視器。當 JBIG2 來源帶有獨立的全域區段時,JBig2Loader 會透過影像 XObject 上的 /JBIG2Globals 串流參照將它嵌入;in-stream/in-line 形式則一如既往可正常往返。這只是結構性接線 —— 全域位元組是未點陣化地直接傳遞,並未經過解碼。
API 介面
標題為「API 介面」的區段| 類別 | 主要方法 | 角色 |
|---|---|---|
TextRenderer | buildTextShowOperator(), buildTextStateOperators(), setTextRenderingMode(), setTextStrokeWidth(), setTextShadow(), setFontSpacing(), setWordSpacing(), setFontStretching(), setTextRise(), setRTL(), setHyphenation() | 文字顯示 + 文字狀態運算子建構器 |
TextRenderingMode(列舉) | Fill, Stroke, FillStroke, Invisible, FillClip, StrokeClip, FillStrokeClip, Clip | ISO 32000-2 文字繪製模式 |
TextShadow | __construct(Color, offsetX, offsetY, opacity) | 帶有偏移繪製的值物件 |
JavaScriptManager | includeJs(), addJsObject(), hasJavaScript(), writeJavaScript(), writeOpenAction() | 文件層級 JavaScript 的目錄接線 |
PropertiesRegistry | register(), getTagIndex(), registerOcg(), registerOcgs(), getAll(), writeProperties() | 標記內容 + OCG 屬性儲存區 |
JBig2Loader | load(), loadFromString(), parseSegments() | JBIG2 直接傳遞解碼器 |
JpxLoader | load(), loadFromString(), parseBoxes() | JPEG 2000 直接傳遞解碼器 |
執行 composer docs:generate-api-php -- --module=Content 可取得完整的 PHPDoc 表格。
程式碼範例 —— 快速上手
標題為「程式碼範例 —— 快速上手」的區段來源:examples/28-text-rendering.php。
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;use NextPDF\Content\TextRenderingMode;
$renderer = new TextRenderer();$renderer ->setTextRenderingMode(TextRenderingMode::FillStroke) ->setTextStrokeWidth(0.3) ->setWordSpacing(0.5);
$stateOps = $renderer->buildTextStateOperators();程式碼範例 —— 正式環境
標題為「程式碼範例 —— 正式環境」的區段這會加上一道柔和陰影與一個斷字器,接著以呼叫端提供的逸出函式建構顯示運算子(也就是 ADR-015 所定義的標準 PdfStringEscaper 接縫)。
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;use NextPDF\Content\TextShadow;use NextPDF\Graphics\Color;use NextPDF\Support\PdfStringEscaper;
$renderer = new TextRenderer();$renderer ->setTextShadow(new TextShadow(Color::rgb(0, 0, 0), 0.4, -0.4, 0.45)) ->setRTL(false);
$showOp = $renderer->buildTextShowOperator( text: 'Quarterly report', fontKey: 'F1', metrics: $fontMetrics, escapeSegment: static fn (string $s): string => PdfStringEscaper::escapeLiteral($s),);
$pageContent = $renderer->buildTextStateOperators() . $showOp;邊界情況與陷阱
標題為「邊界情況與陷阱」的區段buildTextShowOperator()對空輸入會回傳空字串。不要輸出空的Tj—— 若你的排版可能產生空白文字段,請在上游加以防護。- 逸出回呼是必填的,並負責字串安全。請傳入標準的
PdfStringEscaper::escapeLiteral()(ADR-015)。不完整的逸出器會產生語法上損壞的常值字串。 TextShadow::offsetY在左上角為原點的座標系中,負值代表向下。正的 Y 值會把陰影往上推,這通常並非你想要的結果。JavaScriptManager會檢核指令稿輸入。無效的指令稿主體會在註冊時被拒絕,而不是在寫入時被靜默丟棄。JBig2Loader與JpxLoader從不進行點陣化。它們會驗證並把編碼後的位元組直接傳遞下去。損壞的區段會以剖析錯誤的形式浮現,而不是變成一張空白影像。PropertiesRegistry::register()對每個字典都是冪等的 —— 相同的屬性字典會重用同一個標籤索引。
運算子建構的時間複雜度與字串長度成 O(n);當排版模式使用 TJ 陣列時,還會多一道 O(n) 的字距處理。這裡沒有任何排版或字形塑形成本 —— 那些留在 Typography 與 Layout 模組裡。JavaScript 與屬性序列化的時間複雜度為 O(項目數)。直接傳遞的影像載入器是 O(位元組數) 的剖析,解碼成本為零。這正是它們在掃描文件工作負載上的主要優勢。參考工作負載的 performance_budget 為 1500 ms 牆鐘時間與 64 MB 峰值記憶體。
安全性注意事項
標題為「安全性注意事項」的區段JavaScriptManager 接受的指令稿主體可能來自不受信任的模板。它會檢核每一段主體,並以 PDF 字串進行編碼,但文件 JavaScript 仍是一個主動內容(active-content)攻擊面。對不受信任的輸出請停用它,或以 /modules/core/security/ 所述的淨化路徑將其移除。JBig2Loader 與 JpxLoader 會剖析不受信任的區段結構:請限制輸入大小與剖析時間,並在來源為使用者提供時,於受限的 worker 中執行擷取。文字逸出邊界是呼叫端提供的回呼。請務必傳入標準逸出器,讓控制位元組無法從常值字串中跳脫出來。
符合性
標題為「符合性」的區段本模組輸出的文字顯示運算子與文字狀態運算子,與 ISO 32000-2 §9 的文字模型一致。這包含 Tj 運算子的語義,以及 TextRenderingMode 列舉所對應的表 104 繪製模式。這些是實作事實:運算子的形狀由 src/Content/TextRenderer.php 與 TextRenderingMode 列舉產生,並由 tests/Unit/Content/TextRenderer*、JavaScriptManagerIsoTest 與 PropertiesRegistryTest 加以驗證。它們並未斷言端對端的 PDF 2.0 符合性。字串逸出契約遵循 ADR-015 與 ISO 32000-2 §7.3.4.2。JBIG2 與 JPEG 2000 的直接傳遞路徑會原封不動地保留編碼後的串流。獨立的 JBIG2 全域區段會以影像 XObject 上的 /JBIG2Globals 串流參照嵌入 —— 已驗證為結構性接線,而非解碼保真度的聲明。文件層級的符合性由 /modules/core/conformance/ 中的 oracle 與黃金測試套件加以驗證。