HotPDF 繁體中文更新日誌

HotPDF 面向最終使用者的版本歷史,包含功能增強、修復、相容性更新和文件變更。

Version 2.137.6

  • 新增 THotPDF.DACopyFile,面向只需要頁數和原樣位元組儲存副本的大檔案 workflow,避免建構完整 Normal API 物件圖。
  • 改進基於檔案的 encrypted PDF 載入路徑:password open 不再為了恢復 raw encryption dictionary 值而快取整份來源 PDF。
  • 減少 AES-256 stream 解密時的記憶體複製,盡量直接從既有 buffer 解密,包括大尺寸 encrypted image stream 的已載入 stream memory。
  • HugeFileBenchmark demo 新增 direct-copy 行,同時預設操作集仍覆蓋完整 LoadFromFile + SaveLoadedDocument 路徑。

Version 2.137.5

  • Added Direct File API object-source editing for large-file workflows: applications can open a PDF with DAOpenFileReadOnly, inspect object counts and source bodies, replace or append object bodies, update document information, and save a full rewritten copy.
  • Expanded Direct File API indexing to cover traditional xref tables and xref streams, including compressed object entries, so image-heavy PDFs and object-heavy PDFs can use the lightweight path.
  • Optimized Direct File API full rewrites by copying unchanged direct objects in source-offset order and merging contiguous ranges, greatly reducing random I/O on PDFs with hundreds of thousands of objects.
  • The HugeFileBenchmark demo now includes a direct-rewrite operation and documents HTML/CSV benchmark runs for image-only and mixed text/image huge PDFs.

Version 2.137.4

  • 將 Delphi PreflightReport demo 從 console sample 升級為互動式 VCL GUI 工具,用於單一檔案 preflight workflow。
  • GUI 現在涵蓋 standard text、JSON、HTML report,可選 password、profile INI、內建 preset、單一檔案 PDF/VT validation、embedded-report PDF 輸出、report preview、status logging、automatic output naming,以及快速開啟產生的檔案。
  • 移除舊的啟動行為:未提供 command-line argument 時不再自動建立 sample PDF 和 report。

2026-05-26 Version 2.137.3

  • PDF/VT validation 現在同時識別以 RDF attribute 形式和 element text 形式寫入的 XMP property,覆蓋常見的 pdfvtid:GTS_PDFVTVersionpdfvtid:GTS_PDFVTModDatexmp:ModifyDate packet 樣式。
  • 新增 Delphi regression coverage,確保 attribute-style PDF/VT metadata detection 與其餘 structural PDF/VT checks 分開驗證。

2026-05-26 Version 2.137.2

  • 改進 embedded preflight report validation:source PDF 在 %%EOF 後合法保留 final line break 時,也能繼續匹配已存 fingerprint。
  • Preflight profile 以 UTF-8 BOM 保存且首行為 section header 時,現在可正確載入。
  • 加固 PDF literal string escape decoding,改善 owner 或 user entry 帶轉義字節的 encrypted PDF password validation 與 unencrypted-copy 輸出。

2026-05-26 Version 2.137.1

  • 將 CFF parser 的安全處理擴展到 direct byte-array check:malformed input 後恢復 reader position,並在 failed check 時清理 stale layout state。
  • 加固 C++Builder wrapper-compatible CFF stream loader:nil stream input 會返回 False 並重置 wrapper state,而不是解引用該 stream。

2026-05-26 Version 2.137.0

  • 新增 THotPDF.ValidatePDFVT 及 password-aware overload,用於聚焦 PDF/VT validation。文本報告會檢查 XMP PDF/VT claim、metadata namespace、PDF/VT modification date matching、PDF/X base marker、output intent、catalog DPartRoot structure、loadable pages 與 page-level DPart coverage。
  • 獨立 HotPDFPreflight CLI 新增 --pdfvt 參數,可為單個 PDF 或遞歸目錄掃描寫出 .pdfvt.txt validation report。

2026-05-26 Version 2.136.8

  • 改進 Type 1 PFB 與 CFF parser 的失敗處理:malformed stream check 會保留輸入位置,並清除舊中繼資料,避免 failed check 後仍暴露上一次解析得到的字體名。
  • 補充 Type 1/CFF smoke 覆蓋,加入 malformed CFF 與 Type 1 stream,檢查失敗呼叫後的 stream-position preservation 與 stale-metadata cleanup。

2026-05-26 Version 2.136.7

  • 加固 Type 1 PFB 與 CFF parser 入口:stream-based check 會保留呼叫方 stream 位置,遇到 malformed data 時安全返回失敗,並透過 Delphi 與 C++Builder wrapper 路徑暴露基礎 Type 1/CFF 字體中繼資料。
  • 擴展 Type 1/CFF smoke test,加入 in-memory CFF data、ASCII Type 1 font data、wrapper-level PFB file loading 與 wrapper-level CFF stream loading,覆蓋 Delphi 和 C++Builder 兩側集成面。

2026-05-26 Version 2.136.6

  • 新增 Delphi 功能範例,覆蓋 CJK Unicode 文本輸出、大型多頁文件生成、PFX 簽章,並擴展圖像壓縮範例以輸出 CCITT Group 3 1D 與 2D 文件。

2026-05-26 Version 2.136.5

  • Preflight 報告現在遇到已載入頁面無法返回 MediaBox 時會繼續生成報告。該頁會標記為 unavailable,而不是中斷整份診斷輸出,因此大型或不一致的頁樹仍可得到報告。
  • 優化多處 byte-level preflight 掃描,避免反覆複製文件尾部字串和線性查找重複物件號。10,000 頁 implementation-limit 樣本現在可在 120 秒壓力測試預算內完成。
  • Preflight 壓力 runner 的預設單文件超時提高到 120 秒;PreflightReport demo 在 profile-aware 輸出路徑後也可以乾淨重編。

2026-05-26 Version 2.136.4

  • 新增 preflight cookbook、自動生成的 preflight API map,以及面向 HotPDFPreflight 命令列工具的大目錄壓力測試 workflow。壓力 runner 對每個 PDF 設置單文件超時,並記錄 JSON、Markdown、CSV、report 和 log 證據。
  • 修復 preflight fingerprint helper 的完整重編譯問題:在 CreatePreflightReport 使用該 helper 前先聲明它,因此從原始碼重編 HPDFDoc.pas 的 console tools 可以乾淨編譯。
  • 記錄了基於 D:\PDFdoc\PDF-Samples 的 1000-file baseline:997 passed、1 failed、2 timed out、耗時 111.422 seconds,吞吐 8.975 files per second。

2026-05-25 Version 2.136.3

  • 獨立 HotPDFPreflight CLI 工具新增 --aggregate <file> 選項,per-file 報告寫完後呼叫 THotPDF.AggregatePreflightReports 輸出批量彙總到指定文件。彙總列出每個處理的 PDF 的狀態、大小、警告數加總計。
  • 支援單文件和遞歸目錄掃描,可與 --profile / --preset 協同使用。彙總基於每份報告的 text body 計算,profile 過濾的效果會反映到彙總裡。
  • 範例:HotPDFPreflight C:\Archive -r --preset silent-actions -f json -o C:\Archive\reports --aggregate C:\Archive\Aggregate.txt 對每個 PDF 輸出 JSON 報告並寫一份批量彙總。

2026-05-25 Version 2.136.2

  • 獨立 HotPDFPreflight CLI 工具新增 --profile <file>--preset <name> 選項,在寫每份報告前先經 preflight profile 過濾。與既有 -f text|json|html-p <password>-r 遞歸目錄掃描協同使用。
  • 兩個新選項互斥(同時給定時後者勝)。preset 值與 THotPDF.GetBuiltInPreflightProfile 識別的名稱一致,CI pipeline 無需上傳 INI 文件即可使用標準配置。
  • 範例:HotPDFPreflight C:\Archive -r --preset silent-actions -f json -o C:\Archive\reports 對目錄樹中每個 PDF 輸出 JSON 報告,並應用 silent-actions 預設。

2026-05-25 Version 2.136.1

  • Delphi PreflightReport demo 現在接受 profile=<file>preset=<name> 作為額外 CLI 參數,在寫報告前先經 profile 過濾。與既有 json / html / embed 輸出格式 flag 協同使用。
  • 範例:PreflightReport.exe Input.pdf Report.txt "" text profile=tuned.inipreset=compact / preset=silent-actions
  • preset 取值與 THotPDF.GetBuiltInPreflightProfile 識別的名稱一致,所以無需自己寫 INI 文件即可在 demo 中試用 profile。

2026-05-25 Version 2.136.0

  • 新增 THotPDF.MergePreflightProfiles 支援 profile 分層。結果是兩個輸入的去重並集(DisableChecksDisableWarnings 合併去重,DisableHints 取邏輯或),適用於把 compact 之類預設與項目特定微調組合。
  • 新增 THotPDF.DiffPreflightProfiles 做 profile 結構對比。兩個 profile 等價時返回 True,否則 OnlyInAOnlyInB out 參數以換行分隔列出每側獨有的條目,形如 check:<name> / warn:<name> / option:hints=false
  • 兩個新 helper 配齊 profile 生命週期:Load / GetBuiltIn / Save / Apply / Validate / Merge / Diff

2026-05-25 Version 2.135.0

  • 新增 THotPDF.CreatePreflightReportWithProfile 一站式便捷 wrapper,把 CreatePreflightReportLoadPreflightProfileApplyPreflightProfile 和格式轉換器組合為單一呼叫。
  • 新 overload 接受源 PDF、可選密碼、可選 profile 文件、目標格式(pfText / pfJSON / pfHTML),返回最終報告 body。傳入空 ProfileFile 跳過 profile 步驟,呼叫方無論是否配置了 profile 都可保持單一呼叫點。
  • 底層四個 API 保持可用,既有呼叫鏈不受影響;新 wrapper 純粹增量。

2026-05-25 Version 2.134.0

  • 新增 THotPDF.SavePreflightProfileTHPDFPreflightProfile 記錄寫回 INI 文件。輸出格式與 LoadPreflightProfile 消費的一致,兩個函數對良構 profile 是精確的逆操作。
  • 支援 "載入預設、調整、保存" 工作流程:用 v2.133.0 GetBuiltInPreflightProfile 取內置預設,修改列表或 flag,然後 SavePreflightProfile 寫出供後續複用或跨項目共享。
  • 無內容的 section 不輸出,空 profile 僅產生一行註釋而不是三個空 section header。

2026-05-25 Version 2.133.0

  • 新增 THotPDF.GetBuiltInPreflightProfile,為常見工作流程返回開箱即用的 THPDFPreflightProfile 記錄,呼叫方無需為標準配置維護 INI 文件。
  • 識別名稱(大小寫不敏感):default 或空字串返回空 profile;compact 屏蔽所有 Hint 行以縮短報告;silent-actions 屏蔽所有 PDF 1.7 §12.6.4 action warning 加 EmbeddedFileRichMedia,適用於有意嵌入多媒體或交互動作的工作流程。
  • 未知名稱也返回空 profile,函數永不因 typo 拋錯;如需讓 typo 報錯,配合 v2.132.0 ValidatePreflightProfile 使用。

2026-05-25 Version 2.132.0

  • 新增 THotPDF.ValidatePreflightProfile 用於防禦性 profile 檢查。函數遍歷已載入 profile 的 DisableChecksDisableWarnings 列表,標記當前 preflight 實現無法識別的名稱,並將未知名稱用 ', ' 連接放入 UnknownNames out 參數。
  • 用於檢測針對其他 HotPDF 版本編寫的 profile 文件。不驗證時,typo(如 OpneAction 而非 OpenAction)或被重命名的 check 會靜默 disable 任何東西。
  • 該檢查純防禦性,不修改 profile 本身。呼叫方自行決定是中止、記錄 warning 還是繼續使用部分生效的 profile。

2026-05-25 Version 2.131.0

  • 新增 THotPDF.ConvertPreflightReportToVeraPDFStyle 轉換器,把 HotPDF preflight 報告塑形為參照 veraPDF 驗證輸出結構的 JSON 文件:頂層 profilejobs 數組(含 itemDetails / taskResult / validationResult),以及 validationResult.details 下的 ruleViolations 數組。
  • HotPDF 風格而非與 veraPDF wire-level 相容;目標是讓已經消費 veraPDF JSON 的下游工具用最小的欄位重命名適配 HotPDF 輸出,而不必重新學習另一套資料結構。
  • Rule violations 保留原生 HotPDF JSON 輸出中相同的 specification ISO 章節交叉引用,呼叫方走 veraPDF-style 路徑仍保留 spec 級別的可追溯性。

2026-05-25 Version 2.130.0

  • 新增 THotPDF.EmbedPreflightReportAsXMP,含兩個 overload(帶/不帶可選 Password 參數)。函數把源 PDF 複製到目標文件,並在末尾追加一段 PDF 註釋塊,payload 是帶 xmlns:hotpdf 命名空間的 XMP / RDF。
  • 報告每行映射為 hotpdf:<name> 元素。PASS / FAIL check 把 severity 寫入屬性;warning、hint、info 行用 warnhintinfo 前綴加在元素名前。
  • 掃描 xpacket 標記的 XMP 工具可看到嵌入報告。PDF 閱讀器繼續忽略追加字節(不在物件圖內)。這是歸檔友好的 XMP 嵌入,不是 spec 完整的 XMP 集成;XMP payload 沒有從 catalog /Metadata 引用過來。

2026-05-25 Version 2.129.0

  • 新增 THotPDF.LoadPreflightProfileTHotPDF.ApplyPreflightProfile,配合新 THPDFPreflightProfile record。Profile 讓呼叫方在不重跑分析的前提下定製報告輸出:屏蔽特定 check / warning 名稱,或屏蔽所有 Hint 行。
  • Profile 文件用 INI 風格:[disable-checks][disable-warnings][options] 三個可選段。註釋和空行忽略。空 profile 透傳原報告。
  • 過濾後,結尾 SummaryWarnings 行重新計算,被屏蔽條目不再計入 Failed / Warnings 總數。其他行原樣透傳,JSON / HTML 轉換器、diff helper、validate / embed / aggregate 等 API 無需改動即可在過濾後報告上繼續工作。

2026-05-25 Version 2.128.2

  • 新增 Delphi PreflightDashboard console demo,掃描一個 PDF 目錄並輸出自包含的靜態 HTML dashboard:每個 PDF 生成 <stem>.preflight.html,外加一份 index.html 彙總表。
  • Dashboard 頂部顯示 total / passed / failed 計數,下面是每個 PDF 的狀態、大小、summary 和詳細報告鏈接的表格。失敗行高亮;PASS / FAIL 徽章著色,掃一眼即知。
  • 輸出是一個靜態目錄(無需 HTTP server);發佈到 CI artifact 頁面、用任意 web server 提供,或者直接在瀏覽器開啟 index.html

2026-05-25 Version 2.128.1

  • 新增 tools/validate-preflight-json.py Python 工具,對照已發佈的 schema(Docs/preflight-schema.json)驗證 HotPDF preflight JSON 輸出。腳本對每個輸入列印一行 PASS/FAIL,驗證失敗時退出碼非零,CI pipeline 可據此做 schema 合規性門禁。
  • 因 schema 在每個物件上都聲明 additionalProperties: false,驗證為嚴格模式:未知欄位觸發硬失敗,而不是悄悄混入。所需依賴為標準 jsonschema Python 包。

2026-05-25 Version 2.128.0

  • 新增 THotPDF.AggregatePreflightReports 用於批量彙總。函數接受 per-file preflight 報告數組,輸出單一彙總:每個文件一行 PASS/FAIL 狀態 + 字節大小 + 警告數,加上 passed / failed / warnings / 總掃描字節數 等總計行。
  • 與 v2.125.1 HotPDFPreflight 獨立 CLI 天然成對:跑 CLI 對每個 PDF 產出獨立報告,然後把報告 body 餵給 AggregatePreflightReports,拿到 dashboard-ready 批量彙總。
  • 空輸入數組返回空字串,呼叫方可以無條件追加該彙總輸出,不必為零文件目錄單獨防禦。

2026-05-25 Version 2.127.0

  • 新增 THotPDF.RepairPDFFromPreflightReport,含兩個 overload(帶/不帶可選 Password 參數)。函數對損壞的 PDF 應用一組保守的字節級修復:截掉最後一個 %%EOF 標記之後的所有追加字節、補上完全缺失的 %%EOF 標記。
  • 當至少應用了一次修復時返回 TrueRepairsApplied 是 out 參數,每行列一項修復,呼叫方據此判斷保留修復版還是升級到更強力的恢復工具。
  • 物件圖層面的修復(重建 xref、修復 stream length、補全 trailer)刻意排除在外,因為此類修復可能把部分可恢復的文件變得更不可恢復。本接口的修復都限於在"完好/輕損"PDF 上都明確安全的操作。

2026-05-25 Version 2.126.1

  • Docs/preflight-schema.json 發佈 preflight JSON 輸出的正式 JSON Schema,符合 JSON Schema draft 2020-12 規範。
  • Schema 描述每個頂層欄位(inputsizepdfVersionxrefStyle)、checks / info / hints / warnings 數組和 summary 物件,讓消費 pipeline 在解析前先做結構驗證。
  • 說明主題現在指向該 schema 文件供下游消費方參考。

2026-05-25 Version 2.126.0

  • 新增 THotPDF.ComparePreflightReports,逐行比對兩份 preflight 報告。函數輸出 unified-diff 樣式:共享行用兩個空格前綴;僅在 ReportA 出現的行用 ;僅在 ReportB 出現的行用
  • LoadAndValidatePreflightReport 天然成對:歸檔驗證失敗時把 OriginalReport 與 CurrentReport 傳入 ComparePreflightReports,可直接看出哪幾行變了。
  • diff 算法是一個小型 greedy 遍歷,針對 CreatePreflightReport 的確定性 key/value 輸出做了優化;對典型輸入產出緊湊 diff,不引入通用 LCS 實現。

2026-05-25 Version 2.125.1

  • 新增獨立 Delphi console 工具 HotPDFPreflight,用於批量對單個文件或整個目錄跑 preflight 報告。支援 -o 輸出目錄、-f text|json|html 輸出格式、-p 密碼、-r 遞歸目錄遍歷、-v 詳細進度日誌等參數。
  • 退出碼遵守標準 CLI 約定:0 成功、1 用法錯誤、2 輸入不存在、3 至少一個 PDF preflight 失敗,便於集成進 CI pipeline 和 shell 腳本。
  • 每個報告文件命名為 <basename>.preflight.<ext>,擴展名取決於請求的格式。

2026-05-25 Version 2.125.0

  • 新增 THotPDF.LoadAndValidatePreflightReport,含兩個 overload(帶/不帶可選 Password 參數)。該函數從 EmbedPreflightReportInPDF 寫出的 PDF 中提取嵌入報告,重跑當前 preflight 算法,對比嵌入的 InputFingerprint 與新生成的指紋,一致時返回 True
  • out 參數 OriginalReportCurrentReport 同時返回兩份報告,便於驗證失敗時呼叫方比對差異,定位嵌入後到驗證之間的變更。
  • EmbedPreflightReportInPDF 天然成對:歸檔時嵌入一次,稍後任意時間驗證是否被篡改或意外修改。

2026-05-25 Version 2.124.2

  • THotPDF.CreatePreflightReport 新增兩條指紋行,便於 CI 穩定性比對。InputFingerprintSize: 行之後輸出源 PDF 字節的 64-bit FNV-1a 哈希(16 位小寫 16 進制)。ReportFingerprint 在報告末尾輸出已組裝報告內容(指紋行之上一切)的 64-bit FNV-1a 哈希。
  • CI pipeline 可跨多次執行比對兩個指紋,檢測輸入文件或報告內容的意外漂移,無需逐行解析。
  • 兩個指紋都是非密碼學;選用 FNV-1a 是為低開銷、內聯實現,不依賴外部哈希模塊。
  • JSON 輸出把 InputFingerprint 放入 info 數組,ReportFingerprint 放在 info 末尾;兩條 entry 的 spec 欄位都標為 "FNV-1a 64-bit (non-cryptographic)"。

2026-05-25 Version 2.124.1

  • THotPDF.CreatePreflightReport 新增兩條條件性增量更新版本診斷行。當 IncrementalUpdates > 0 時,報告新增 RevisionStartXRefPositions(每個 startxref 關鍵字的字節偏移,按從舊到新排序)和 RevisionXRefTargets(每個標記指向的 xref 偏移),呼叫方無需手工解析即可追蹤增量更新鏈。
  • 無增量更新或僅單次 revision 的 PDF 保持字節級穩定:新行僅在找到一個以上 startxref 標記時輸出。
  • JSON 輸出中為新欄位添加 ISO 32000-1 sec 7.5.6 規範引用。

2026-05-25 Version 2.124.0

  • 新增 THotPDF.EmbedPreflightReportInPDF,含兩個 overload:一個帶可選 Password 參數支援加密 PDF。該方法把源 PDF 複製到目標文件,並在最後一個 %%EOF 之後以 PDF 風格的註釋行追加 preflight 報告。
  • 報告隨文件一同歸檔:文本編輯器、grep 和審計工具在文件離開原始工作站後很久還能查閱。
  • PDF 閱讀器繼續按原樣渲染文件,因為追加的字節落在物件圖之外;交叉引用表與 trailer 字典未變。
  • Delphi PreflightReport demo 新增 embed CLI 參數,在生成獨立報告的同時寫出嵌入版本。

2026-05-25 Version 2.123.1

  • 新增 regression 測試:手工構造包含重複物件編號、錯誤 xref 行和不平衡 stream/endstream 對的 PDF,驗證 Phase F 的三個根因診斷行(DuplicateObjectListFirstMalformedXRefOffsetStreamEndStreamDelta)按預期觸發。
  • 庫行為無變更:本次僅填補 regression 套件之前只覆蓋"乾淨"與"非 PDF"兩種情況的盲區。

2026-05-25 Version 2.123.0

  • THotPDF.CreatePreflightReportTHotPDF.SavePreflightReport 新增 HTML 輸出格式。THPDFPreflightFormat 枚舉新增第三個值 pfHTML,與 pfTextpfJSON 並列。
  • HTML 輸出是自包含的 dashboard 樣式文件:內聯 CSS、severity 著色(PASS 綠、FAIL 紅、WARN 黃)、checks / hints / info / warnings 分表 + summary 卡片。無需外部 CSS、JavaScript 或字體。
  • 每行表格包含 ISO 32000-1 / ISO 19005 / ISO 15930 / ISO 14289 規範引用,與 v2.122.1 在 JSON 輸出加入的 spec 欄位同源。
  • HTML 輸出做了字節安全轉義:& < > " ' 都轉義,UTF-8 字節序列保真。
  • Delphi PreflightReport demo 接受 html 作為第 4 位 CLI 參數請求 HTML 輸出。

2026-05-25 Version 2.122.4

  • 新增 PDF/X subset 檢測。檢測到 PDF/X 聲明時,新的 Hint PDFXVersion 行給出具體子集(X-1a:2001X-1a:2003X-3:2002X-3:2003X-4X-4pX-5gX-5pgX-5nX-5)。
  • 新增 PDF/UA part 提取。檢測到 PDF/UA 聲明時,新的 Hint PDFUAPart 行從 XMP 中繼資料中的 pdfuaid:part 報告值。
  • JSON 輸出中為新 hint 條目添加 ISO 15930 和 ISO 14289 規範交叉引用。
  • 無 PDF/X / PDF/UA 聲明的乾淨 PDF 保持字節級穩定:新 hint 僅在底層聲明被檢測到時輸出。

2026-05-25 Version 2.122.3

  • THotPDF.CreatePreflightReport 新增根因診斷行。當損壞的 PDF 觸發缺陷計數時,報告現在給出可操作的細節。
  • DuplicateObjectList 僅當 DuplicateObjectNumbers > 0 時出現,列出最多 5 個重複的物件編號,便於呼叫方定位衝突。
  • FirstMalformedXRefOffset 僅當 XRefMalformedEntries > 0 時出現,給出第一個錯誤交叉引用行的 1-based 字節偏移。
  • StreamEndStreamDelta 僅當 streamendstream 標記數量不等時出現,給出有符號差值,提示缺多少標記。
  • 乾淨的 PDF 保持字節級穩定:新診斷行僅在底層缺陷計數非零時輸出。

2026-05-25 Version 2.122.2

  • 擴展 preflight action warning 覆蓋 PDF 1.7 §12.6.4 全部動作類型。新增 15 個諮詢性 warning:GoToRActionGoToEActionThreadActionURIActionSoundActionMovieActionHideActionNamedActionSubmitFormActionResetFormActionImportDataActionSetOCGStateActionRenditionActionTransActionGoTo3DViewAction
  • 僅當檢測到對應 action token 時才輸出 warning;不含任何 action 的乾淨 PDF 保持字節級穩定。
  • JSON 輸出中的 ISO 32000-1 規範交叉引用現在同樣覆蓋這 15 個新 warning。

2026-05-25 Version 2.122.1

  • 擴展 THotPDF.CreatePreflightReport JSON 輸出,新增 ISO 規範交叉引用。每個 checkshintswarnings entry 現在攜帶 spec 欄位,指向 ISO 32000-1、ISO 19005、ISO 15930 或 ISO 14289 中對應的章節。
  • plain-text 報告保持不變,字節級穩定;spec 欄位只出現在 pfJSON 輸出中。
  • 映射覆蓋報告到 v2.122.0 為止 emit 的每個 check、hint 和 warning,JSON 消費者無需外部 lookup 表即可把診斷路由到對應規範章節。

2026-05-25 Version 2.122.0

  • THotPDF.CreatePreflightReportTHotPDF.SavePreflightReport 新增機器可讀 JSON 輸出。新增 THPDFPreflightFormat 枚舉包含 pfText(預設 plain-text 路徑)和 pfJSON(CI 友好的 JSON 文件)兩個值。
  • 新增格式參數 overload 接受 Format 參數;既有 text overload 保持字節級穩定,現有應用無需任何代碼改動。
  • JSON 輸出分組:頂層欄位 inputsizepdfVersionxrefStyle,加上 checksinfohintswarnings 數組和包含 failedwarningsresult 計數器的 summary 物件。
  • 內置 JSON encoder 處理 "\、控制字節轉義,UTF-8 字節序列保真,無需外部 JSON 庫。
  • Delphi PreflightReport demo 接受第四個 CLI 參數 json,對輸入 PDF 請求 JSON 格式輸出。

2026-05-25 Version 2.121.36

  • 增強 preflight 報告,新增合規標記 hint。報告現在輸出 Hint PDFAClaimedHint PDFAPartHint PDFAConformanceHint PDFXClaimedHint PDFUAClaimedHint TaggedPDFHint HasTransparency 行,便於下游工具據此決策。
  • 新增 PDFAWithEncryptionPDFAWithJavaScriptPDFA1WithTransparency 互斥 warning,在文件同時聲明 PDF/A 又攜帶加密、JavaScript 或 PDF/A-1 禁止的 transparency 標記時觸發。
  • hint 行不計入 Failed 計數,所有 helper 保持諮詢性質;不替代完整 PDF/A、PDF/X、PDF/UA 或 ISO 32000 合規驗證引擎。

2026-05-25 Version 2.121.35

  • 增強 preflight 報告,新增內容資源完整性診斷。報告現在包含資源字典、字體、嵌入字體程序、圖像 XObject、Form XObject、ColorSpace、註釋、widget 和 link 計數。
  • 報告現在包含 FlateDecodeDCTDecodeCCITTFaxDecodeJBIG2DecodeLZWDecodeASCIIHexDecodeASCII85DecodeRunLengthDecodeJPXDecode 的 filter chain 使用計數。
  • 新增 FontsHaveEmbeddedPrograms pass/fail 檢查,在聲明字體資源時驗證至少有一份 /FontFile/FontFile2/FontFile3 嵌入字體程序。
  • 新增 AnnotationCountConsistent pass/fail 檢查,驗證 widget 與 link 註釋計數之和不超過整體註釋計數。

2026-05-25 Version 2.121.34

  • 增強 preflight reports,新增 trailer root type diagnostics。報告現在驗證 trailer /Root indirect reference 指向的物件是否聲明為 /Type /Catalog

2026-05-25 Version 2.121.33

  • 增強 preflight reports,新增 trailer ID diagnostics。報告現在統計 trailer /ID array 中的 hex string entries,並在提供 ID array 時驗證 file identifier 是否為有效的 two-entry pair。

2026-05-25 Version 2.121.32

  • 增強 preflight reports,新增 trailer indirect-reference diagnostics。報告現在顯示 trailer /Root/Info object references,並驗證這些引用物件是否在文件中定義。

2026-05-25 Version 2.121.31

  • 增強 preflight reports,新增 stream length coverage diagnostics。報告現在統計 stream /Length entries,並驗證檢測到的 streams 是否具備對應的 length entries。

2026-05-25 Version 2.121.30

  • 增強 preflight reports,新增 revision marker diagnostics。報告現在統計 %%EOF markers 和 startxref sections,驗證二者數量是否平衡,並檢查最後一個 startxref marker 是否位於最後一個 EOF marker 之前。

2026-05-25 Version 2.121.29

  • 增強 preflight reports,新增 page tree consistency diagnostics。報告現在包含 page tree 聲明的 /Count,並增加 pass/fail 檢查,用於比較該值以及統計到的 page objects 是否與 HotPDF 載入到的頁數一致。

2026-05-25 Version 2.121.28

  • 增強 preflight reports,新增 xref table row diagnostics。報告現在包含 xref subsection、entry、free-entry、in-use-entry 和 malformed-row counts,並增加 xref row syntax 以及 xref 覆蓋範圍是否達到最高 object number 的 pass/fail 檢查。

2026-05-25 Version 2.121.27

  • 增強 preflight reports,加入有邊界的 PDF name-pair counting 和更多一致性檢查。報告現在能區分 catalog、page tree 和 page objects,驗證 object numbers 是否唯一,並檢查 trailer /Size 是否覆蓋最高 object number 以及 trailer /Root 是否存在。

2026-05-25 Version 2.121.26

  • 增強 preflight report 的 object 和 trailer diagnostics。報告現在包含 indirect object definition counts、最高 object number、重複 object number count、stream/endstream 平衡檢查,以及 /Size/Root/Info/ID/Encrypt trailer details。

2026-05-25 Version 2.121.25

  • 增強 THotPDF.CreatePreflightReportTHotPDF.SavePreflightReport 的 cross-reference diagnostics。報告現在會驗證最終 %%EOF marker 是否靠近文件尾部,解析最後一個 startxref offset,識別其目標是 xref table 還是 xref stream,幷包含 xref table、xref stream、object stream、trailer、incremental update 和 linearization counts。

2026-05-25 Version 2.121.24

  • 擴展 preflight report helpers,新增 password-aware overloads 和更完整的診斷資訊。報告現在包含 PDF header version、xref style、已載入頁面解析出的 MediaBox、form field count、stream count、feature presence flags、JavaScript/action/media attachment warnings、warning totals,以及損壞文件的 pass/fail summary。Delphi PreflightReport 範例支援為受支援的加密 PDF 傳入可選密碼參數。

2026-05-25 Version 2.121.23

  • 新增 library-level preflight report helpers:THotPDF.CreatePreflightReportTHotPDF.SavePreflightReport。應用現在可以為輸入 PDF 生成文本摘要,覆蓋 header、EOF marker、startxref、trailer 或 XRef stream、可載入頁數、加密狀態、catalog、page tree、page object、page box、information dictionary、root reference、indirect object count 和整體 pass/fail 狀態。Delphi PreflightReport 範例現在直接使用這些 API。

2026-05-25 Version 2.121.22

  • 新增 Delphi PreflightReport 控制台範例,用於建立樣例 PDF,並寫出包含輕量結構檢查的文本報告,覆蓋 PDF header、EOF marker、可載入頁數、加密狀態、catalog、page tree、page box 和 document information dictionary。該 workflow 保持 AutoLaunch 關閉,也支援從命令列對現有輸入 PDF 生成報告。

2026-05-25 Version 2.121.21

  • 新增 Delphi SearchAndSelect 控制台範例,用於生成報表、搜索受控文本行,並用 PDF highlight annotations 和 /QuadPoints 標記每一個匹配詞。範例保持 AutoLaunch 關閉,適合命令列和自動化驗證。

2026-05-25 Version 2.121.20

  • 新增 RC4-40 和 RC4-128 Standard 加密 PDF 的密碼載入能力。應用現在可以用帶密碼的 LoadFromFileLoadFromStream,也可以載入後呼叫 DecryptLoadedDocument,再透過 SaveLoadedDocument 保存未加密的已載入文件副本。新的 Delphi DecryptPDF 控制台範例會建立帶密碼的樣例文件,並在不啟動 PDF 檢視器的情況下寫出解密副本。

2026-05-25 Version 2.121.19

  • 新增 Delphi Printer 控制台範例,用於生成帶列印預設的 PDF。範例會寫入列印相關 /ViewerPreferences、頁面 BleedBoxTrimBox、可列印註釋標誌以及 print-control ExtGState,同時不會自動開啟 PDF 檢視器,也不會向物理列印機發送任務。

2026-05-25 Version 2.121.18

  • 新增 Delphi ConvertTo 控制台範例,用於把支援的源圖形轉換為 PDF 輸出文件。該 workflow 會分別從 JPEG、BMP、TIFF 和 EMF 輸入建立 PDF 文件,並關閉 AutoLaunch,便於命令列和自動化檢查使用。

2026-05-25 Version 2.121.17

  • 新增已載入頁面操作 helper:InsertPagesFromDocumentExtractPagesToFileMovePage。應用現在可以從另一個已載入文件插入頁面、把選定頁面抽取到新 PDF,並在重排已載入頁面後讓後續保存和抽取繼續使用更新後的頁面順序。Delphi PageOperations demo 展示了插入、抽取和重排 workflow,且不會自動啟動 PDF 檢視器。

2026-05-25 Version 2.121.16

  • 擴展已載入 AcroForm 編輯能力,新增 RemoveFormFieldFlattenFormFields。應用現在可以按索引或名稱刪除已載入欄位,或把已載入欄位扁平化為靜態頁面內容,同時移除交互式 AcroForm 欄位樹和 widget annotations。Delphi FormFields 範例現在展示欄位說明、欄位刪除和扁平化,並且不會自動啟動 PDF 閱讀器。

2026-05-25 Version 2.121.15

  • 新增已載入書籤標題搜索能力:THotPDF.FindLoadedBookmarkPageIndex。應用現在可以載入現有 PDF,按書籤標題搜索 outline 樹,並把匹配到的 /Dest 或本地 GoTo action 目標解析為 0-based 頁面索引。

2026-05-24 Version 2.121.14

  • 新增 THPDFPage.AddTextWatermark,用於在新建頁面或已載入頁面上繪製旋轉透明文字水印。新的 Delphi Watermark 範例會建立源 PDF、載入它、給每頁應用水印並保存編輯後的文件。

2026-05-24 Version 2.121.13

  • 新增已載入 AcroForm 欄位說明檢查能力:GetFormFieldDescription。應用現在可以按索引或名稱讀取已載入欄位的 /TU 工具提示文本,並與欄位值、選項、只讀狀態和重命名操作配套使用。

2026-05-24 Version 2.121.12

  • 新增已載入 choice 欄位選項檢查能力:GetFormFieldOptionCountGetFormFieldOptionValue。應用現在可以載入現有 combo box 或 list box 欄位,枚舉其允許的 /Opt 值,並繼續使用同一套已載入表單更新和保存流程。

2026-05-24 Version 2.121.11

  • 擴展已載入 AcroForm 編輯能力,新增 IsFormFieldReadOnlyRenameFormField。應用現在可以檢查已載入欄位的只讀標誌,按索引或名稱重命名欄位,保存已載入文件,並在重新載入後保留更新後的欄位名稱。

2026-05-24 Version 2.121.10

  • 新增 THotPDF.GetLoadedPageBox,用於在 LoadFromFile 後檢查頁面邊界。應用現在可以讀取已載入頁面的 MediaBoxCropBoxBleedBoxTrimBoxArtBox,幷包含未直接聲明頁面框時的標準回退鏈。

2026-05-24 Version 2.121.9

  • 新增已載入 AcroForm 欄位檢查和更新 API。應用現在可以載入現有表單 PDF,枚舉欄位名稱和類型,讀取並更新欄位值,切換欄位的只讀標誌,並透過 SaveLoadedDocument 保存已載入文件。新的 Delphi FormFields 範例展示了完整的載入、編輯和保存流程。

2026-05-24 Version 2.121.8

  • 新增 THotPDF.RegisterLineGraphicsState,用於建立可複用的線條繪製 ExtGState 資源。應用現在可以一次性註冊線寬、端點樣式、連接樣式和斜接限制,再在描邊路徑前透過 THPDFPage.SetGraphicsState 應用該命名狀態。

2026-05-24 Version 2.121.7

  • 新增 annotation 交互輔助 API,可寫入 annotation /F flags 和 link /H highlight modes。Link 輔助方法現在會更新 LastAnnotation,因此建立 link 後可以一致地鏈式設置 flags、highlight modes、border styles 和 popup helpers。

2026-05-24 Version 2.121.6

  • 新增可複用 Form XObject 生成 API 與頁面級繪製輔助方法,支援按矩形放置、縮放和旋轉。新增當前變換矩陣便捷方法,以及用於單行對齊、矩形內自動換行輸出和行數計算的文本輔助方法。

2026-05-24 Version 2.121.5

  • 新增 HotPDF 可複用的 Type 1 PFB 與 CFF 解析單元,包含字節數組讀取器、Type 1 字形輪廓命令提取、CFF dictionary、INDEX、charset 與 encoding 讀取,以及 Type 1 PFB 中繼資料和字形查找輔助能力。Delphi 和 C++Builder 包工程已納入這些解析單元。

2026-05-24 Version 2.121.4

  • PDFACompliance='2A'PDFACompliance='3A' 現在只自動啟用 Tagged PDF 基礎結構,不再隱式寫入 PDF/UA-1 XMP 聲明。PDF/A Level A 文件仍保留 /MarkInfo/StructTreeRoot、文件標題、語言和歸檔中繼資料;pdfuaid 中繼資料只在顯式啟用 PDFUACompliance 時輸出。
  • PDF/A-2/3 smoke 覆蓋現在包含 PDF/A-3A,並斷言 Level A 歸檔輸出不會在未顯式請求時宣稱 PDF/UA。生成的 PDF/A-2A 與 PDF/A-3A smoke 文件已透過 veraPDF 驗證。

2026-05-24 Version 2.121.3

  • THPDFPage.UnicodeTextOut 現在會複用 RegisterUnicodeTTF 生成的 Type 0 字體資源輸出補充平面 Unicode,讓頁面文本與 AcroForm 外觀流共享同一套內部 CID 編碼路徑。
  • 共享的最終化步驟現在會透過 FUnicodeUsedCps/CIDToGIDMap、descendant font /W/ToUnicode 聯動同步頁面級 SMP 輸出,不再保留舊的頁面本地 SMP 映射表。

2026-05-24 Version 2.121.2

  • THPDFPage.UnicodeTextOut 現在會在 RegisterUnicodeTTF 已載入當前字體時,利用頁面字體已註冊的 cmap format 12 glyph 映射輸出補充平面 Unicode 字符。emoji 和其他 U+10000+ scalar 會在頁面文本流中寫成單個 glyph CID,而不是兩個 surrogate-half CID。
  • 頁面字體的 /ToUnicode CMap 會把這些 SMP glyph CID 映射回原始 UTF-16BE surrogate pair,在保留現有 /CIDToGIDMap /Identity 頁面字體路徑的同時,保證文本提取和無障礙語義。

2026-05-24 Version 2.121.1

  • RegisterUnicodeTTF 支援的 AcroForm 外觀流現在會把補充平面 Unicode 字符(例如 emoji)寫成單個內部 CID,而不是把 UTF-16 surrogate pair 當作兩個 Identity-H CID。生成的 /CIDToGIDMap 會把該 CID 指向真實 glyph,/ToUnicode 會把它映射回原始 UTF-16BE surrogate pair,供文本提取使用。
  • Unicode 字體的最終化步驟會在所有外觀流完成內部 CID 註冊後刷新 /CIDToGIDMap/W/ToUnicode,讓 TrueType 子集化和生成的表單外觀使用最終 CID 集合。

2026-05-23 Version 2.121.0

  • PDF 1.7 §12.6.4.13–15 多媒體動作(Rendition / Sound / Movie) 三組新 THPDFPage 按鈕 helper 方法落地: AddPushButtonWithRenditionAction 實現 §12.6.4.13 (Screen 註釋 + MediaRendition + MediaClipData 描述音影片片段 + /OP 操作 0..4);AddPushButtonWithSoundAction 實現 §12.6.4.14,兩個 overload(文件路徑 / 原始 TBytes) + 呼叫方提供的 THPDFSoundParams record (SampleRate / Channels / BitsPerSample / Encoding) + 可選 /Volume + /Repeat + /Synchronous; AddPushButtonWithMovieAction 實現 §12.6.4.15 (透過 /Annotation 引用 Movie 註釋 + /Operation Play / Stop / Pause / Resume 四操作)。
  • AddScreenAnnotationAddMovieAnnotation 現在返回建立的 annotation 字典, 呼叫方可直接傳入對應 action helper 完成鏈式接入。procedure 改 function 是 Delphi ABI 相容變更 — 舊呼叫方忽略返回值的代碼繼續 編譯併發出字節級一致的 PDF。
  • Standard 實施深度:每個 helper 發 spec 必填欄位加常用可選 欄位(Sound /Volume /Repeat /Synchronous;Rendition /JS)。 MediaPlayParameters / MediaScreenParameters / Selector Rendition / Sound /Mix 留待後續 — reader 預設行為覆蓋 95% 場景,helper 保持字節最小。
  • PDF/A(全級別)+ PDF/X(全 profile)在三個 helper 入口立即 拋 ISO 引用診斷(ISO 19005-1 §6.6.1 / ISO 19005-2 §6.5.1 / ISO 19005-3 §6.5.1 / ISO 15930)。原有 AddScreenAnnotation / AddSoundAnnotation / AddMovieAnnotation annotation 路徑的 gate 保持不變。
  • Rendition action 的 MediaClipData filespec 自動接 /P /TF (TEMPACCESS) MediaPermissions(§13.2.6.1 Table 280 最低權限級), 讓 reader 把 payload 臨時交給平臺音影片 codec。
  • Sound action stream 的可選欄位(Volume / Repeat / Synchronous) 僅在呼叫方傳入非預設值時發出,預設 case 下 action dict 字節最小。
  • Sound stream metadata(/R 採樣率 / /C 聲道 / /B 位深 / /E 編碼)透過新 THPDFSoundParams record 由呼叫方 顯式提供。v2.16 時代的 AddSoundAnnotation 入口仍 hardcode 22050 / 16-bit / Stereo / Signed;新 Sound action 路徑 避開此坑 — 呼叫方可正確播放 44.1 kHz mp3、8 kHz µ-law 電話音頻等任意源。
  • Win32 + Win64 全平臺 smoke_multimedia_actions(4 個 action variant + Screen / Movie 註釋鏈接的正向路徑全覆蓋)與 smoke_multimedia_actions_pdfa_pdfx(8 個 gate raise 斷言 = 3 actions × PDF/A + PDF/X)透過;迴歸 smoke_button_actions 雙平臺 跑通 — AddScreenAnnotation / AddMovieAnnotation procedure → function 改造不破壞既有 byte-level 輸出。

2026-05-23 Version 2.120.15

  • Fix:EndDoc 先於兩個 post-build mutator 序列化 PDF 物件圖, 兩個 mutator 的修改都進不了輸出文件。受影響的是 v2.84.0 引入的 TrueType subsetter 與 v2.94.0 引入的 PDF/UA-1 §7.18.3 /Tabs /S 自動 stamping:使用 RegisterUnicodeTTF + AddTextField 的文件會嵌入完整字體文件(典型 Latin TTF 約 1 MB / CJK 約 14 MB)而非子集(約 150 KB / 500 KB), /BaseFont 缺失六字母 AAAAAA+ 子集前綴,FontDescriptor 上 PDF/A 強制要求的 /CIDSet stream 完全缺失(veraPDF 報 ISO 19005-1 §6.3.5 / -2 -3 §6.2.11 失敗);PDF/UA-1 文件的 annotated page 缺失 §7.18.3 /Tabs /S 鍵,撞 Matterhorn 檢查規則 21-001 與 PAC 3 "Tabs" 失敗。
  • 兩個 mutator 現在都在 SaveToStream / SaveToFile 遍歷 IndirectObjects 寫入 PDF 之前執行。對未註冊 Unicode TTF 且未啟用 PDFUACompliance 的文件,輸出與 v2.120.14 字節級 一致 —— 這兩類文件下兩個 mutator 本就是 gated no-op, 重排僅修復了 v2.120.14 輸出原本靜默錯誤的情況。
  • Win32 smoke_unicode_ttf_subset 驗證子集字節為系統 Arial 的 33.6%(676 KB 縮減)、Type 0 / CIDFontType2 / FontDescriptor.FontName 三處 /BaseFont 一致為 UYENHH+ArialMT;smoke_pdfua_annot_structparents 驗證 annotated page dict 上 /Tabs /S 正確 stamp,全部五條 §7.18.3 + annotation-structure 接線斷言透過。

2026-05-23 Version 2.120.14

  • PDF/UA-1 strict 結構 role 入口校驗(ISO 14289-1 §7.7 + ISO 32000-1 §14.7.3):PDFUACompliance 啟用時, AddStructureElement 拒絕任何不在 PDF 1.7 §14.8.4 Table 333 41 個標準 structure type(Document / Part / Art / Sect / Div / BlockQuote / Caption / TOC / TOCI / Index / NonStruct / Private / H / H1..H6 / P / L / LI / Lbl / LBody / Table / TR / TH / TD / THead / TBody / TFoot / Span / Quote / Note / Reference / BibEntry / Code / Link / Annot / Ruby / RB / RT / RP / Warichu / WT / WP / Figure / Formula / Form)也未經 AddStructRoleMap 註冊到 StructTreeRoot /RoleMap 的 /S role。診斷異常含違規 role 字面、PDF/UA-1 §7.7 / Table 333 引用、AddStructRoleMap 修復建議。空 Role 單獨分支拋。沒有這個 gate 時,不合規 role 會無聲落入結構樹,下游 veraPDF / PAC tools 才報 "unknown structure type" 錯誤。
  • 新 gate 僅在 PDFUACompliance=True 時觸發;非 PDFUA 呼叫方 保持 pre-v2.120.14 freeform-role 行為字節級穩定。四個 AddStructureElement overload(4-arg AnsiString base、 v2.88.0 6-arg /Alt + /ActualText、v2.95.0 7-arg /ID、 v2.119.41 THPDFStandardStructureType 枚舉)都匯聚到同一 gated path,單點 guard 覆蓋。枚舉重載總是傳 Table 333 標準名因此總透過校驗 —— 呼叫方應優先用,編譯期消除 'Para' vs 'P' / 'Lbody' vs 'LBody' 大小寫筆誤隱患。
  • v2.119.41 已交付 THPDFStandardStructureType 枚舉 (41 個 spec 名按 5 個 PDF role bucket 分組: §14.8.4.1 Grouping / §14.8.4.2 Block-level / §14.8.4.3 Inline-level / §14.8.4.4 Ruby+Warichu / §14.8.4.5 Illustration)+ StandardStructureTypeToName(T) enum→spec名轉換 + IsStandardStructureType(Name) 任意 AnsiString 驗證;v2.120.14 把這些 capability 接入 AddStructureElement 入口讓 strict 檢查自動化。新增私有 helper _IsCustomRoleInRoleMap 用 byte-safe CompareMem 掃 FStructRoleMap,非 ASCII 自定義 role 在 CP_ACP=65001 host 正常 match。

2026-05-23 Version 2.120.13

  • 修復:v2.120.12 原始碼無法在 RAD Studio 編譯 —— 兩個 EnableShapingFeatureForSubset 重載落在 THotPDF 的 published 段,Delphi 拋 E2266("只允許一個重載成員聲明為 published", RTTI 無法按名稱消歧)。v2.120.13 在兩個重載前後加 public / published 括號讓公開 API 面與 v2.120.12 字節級一致, 可在 dcc32 / dcc64 乾淨編譯;前後屬性與 helper 保持 published 不動。執行時行為不變。

2026-05-23 Version 2.120.12

  • EnableShapingFeatureForSubset(Phase 8f 收口): THotPDF.EnableShapingFeatureForSubset(FeatureTag) / THPDFShapingFeature 枚舉重載會在 v2.119.49 SetGSUBScript / SetGSUBLanguage 選擇狀態下遍歷所請求 feature 的所有 GSUB lookup,列出 LookupType 1(Single — Format 1 delta 對 Coverage 內每個字形 + Format 2 substituteGlyphIDs 數組)/ LookupType 2(Multiple — Sequence.substituteGlyphIDs[])/ LookupType 3 (Alternate — AlternateSet.alternateGlyphIDs[])/ LookupType 4 (Ligature — Ligature.ligatureGlyph)/ LookupType 5/6 (Contextual / Chained Contextual — 遞歸 SequenceLookupRecord 嵌套 lookup,深度限制 8)/ LookupType 7(Extension — 自動解包到有效 lookup 類型)/ LookupType 8(Reverse Chained — substituteGlyphIDs[])的每個潛在替換字形 GID,OR 合併到 FUnicodeExtraUsedGlyphs 讓 v2.84.0 EndDoc subsetter 拉入嵌入 字體子集。Phase 8f 與 v2.119.50 per-glyph MarkUnicodeGlyphUsed 互補 —— 用於 producer 管線在通用啟用某 feature 時的 feature-level batch opt-in。
  • 枚舉重載將每個 THPDFShapingFeature 值派發到其約定的 4-byte OpenType feature tag 集合:sfArabicGSUB → init / medi / fina / isol / rlig;sfStandardLigatures → liga; sfContextualLigatures → clig + rlig;sfStylisticAlternates → salt;sfIndicShaping → nukt / akhn / rphf / rkrf / pref / half / vatu / cjct / pres / blws / abvs / psts / haln / pstf; sfContextualAlternates → rclt + calt。字串 tag 重載接受 任意 4-byte OpenType feature tag 實現枚舉之外的精確目標。 子集體積警告:啟用寬 feature(如 aalt Access All Alternates,某些字體把整個腳本所有字形掛上來)可能把字體一大 部分字形拉進子集,抵消 v2.84.0 體積優化 —— 知道精確 GID 的 呼叫方應優先用 Phase 9 MarkUnicodeGlyphUsed。預設關閉 / 顯式 opt-in。收口 GSUB Engine Roadmap Phase 8 最後一個子 phase。
  • 防禦契約鏡像 v2.119.50:無字體註冊、無 GSUB 表、非 4-byte tag、feature 不在 (script, language) 路徑、空 lookup 鏈 —— 所有 "nothing to do" 都是靜默 no-op(不拋異常)。重複 呼叫冪等(位圖 OR 合併)。Contextual 子表 Format 1 / 2 的 嵌套 lookup 遞歸留待未來版本;Format 3 在真實字體中佔絕大 多數,已實現。需要 Format 1 / 2 精確覆蓋的呼叫方可 fallback 到 per-glyph MarkUnicodeGlyphUsed。

2026-05-23 Version 2.120.11

  • ToUnicode CMap 呼叫方反向映射註冊(Phase 8d 收口): THotPDF 新增 3 個公開方法讓呼叫方向 EndDoc 發射的 Adobe-Identity-UCS ToUnicode CMap 註冊額外的 (substitute codepoint → 原始 Unicode 源 codepoint 序列) 反向映射條目。v2.119.61 / v2.119.62 / v2.119.65 系列已 hard-code 了 35 個 bfchar 內置條目,覆蓋 HotPDF producer-side shaping pipeline 自動 emit 的 Arabic 合字 (LAM-ALEF / YEH-HAMZA / Allah / Bismillah)和 Latin Alphabetic Presentation Forms(fi / fl / ffi / ffl / ff / ſt / st);v2.120.11 透過讓呼叫方為自行驅動的 v2.119.43-50 GSUB 引擎 API(GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst)輸出的 substitute 字形註冊反向映射來收口 Phase 8d。
  • RegisterToUnicodeReverseMapping(SubstCodepoint, SourceCodepoints) 註冊一個 (substitute → 源序列) 條目。 典型用法:Multiple Substitution(1 GID → N GIDs)emit substitute 序列後,註冊反向映射讓消費 reader 的 copy / paste 回到原始 codepoint;Ligature Substitution (N GIDs → 1 合字 GID)emit 合字後,註冊合字 codepoint 反向到 N 元素源序列(例如任意 CALT 上下文合字反向到元件 codepoints)。ClearToUnicodeReverseMappings 清空所有呼叫方 註冊;ToUnicodeReverseMappingCount 報告當前註冊數。
  • EndDoc emit 在內置 35 條目 block 之後追加呼叫方註冊條目 作為額外 bfchar block,按 Adobe CMap and CIDFont Files Specification(Technical Note #5014)§1.4.2 bfchar 算子 上限自動拆分為 100 條目子塊。BMP codepoints 發射 4 hex 位;SMP codepoints 發射 UTF-16BE surrogate pair(8 hex 位)符合 Adobe CMap spec。註冊順序保留,讓 PDF reader 的 bfchar last-write-wins 語義給呼叫方對內置 35 條目的衝突 提供確定性覆蓋行為(呼叫方註冊 <FB01> "fi" 的自定義 映射會在 reader 端覆蓋 v2.119.65 預設)。未呼叫 RegisterToUnicodeReverseMapping 的工作流程 ToUnicode CMap 字節級與 v2.120.10 baseline 一致。SetFormUnicodeFontDict ('', nil) reset 路徑清空呼叫方註冊表讓下次 Unicode 字體 註冊從乾淨狀態開始。

2026-05-23 Version 2.120.10

  • Myanmar 文字排版器(Phase 8f.10):把 Myanmar(OpenType tag mymr)註冊為 HotPDF 第十個、也是最後一個 Indic 腳本, 同時覆蓋 Myanmar 主塊(U+1000-U+109F:Burmese / Mon / Sgaw Karen / Western Pwo / Shan / Rumai Palaung / Pa'o)與 Extended-A (U+AA60-U+AA7F)。新公開 ApplyMyanmarReorder 重排前置 pass 與 GetMyanmarCategory 碼點查詢,可透過 ApplyIndicReorder dispatcher 統一呼叫。
  • 本批次中最複雜的 syllable 結構:音節起始的 Kinzi 三碼點前綴 (U+1004 + U+103A + U+1039)被 FSM 檢測、由 reorder pre-pass 留住,輸出最前面 emit (R8);pre-base 元音 E (U+1031) 移到 音節起始 (R10);四個 medial 輔音 Y / R / W / H (U+103B-U+103E) 按固定 Y → R → W → H 序輸出,不論源序 (R9)。
  • ASAT (U+103A) 與 VIRAMA (U+1039) 都按 virama 處理 stacked consonant 合併。DOT BELOW (U+1037) 渲染在基底之下;其他聲調 記號渲染在基底之上。ANUSVARA(Bindu)在上方;VISARGA 在尾部。 無 Repha。
  • IndicScripts 註冊表加 **兩個** entry(主塊 + Extended-A),共享同一組 Myanmar reorder 函數,讓 Extended-A 輔音與 Pa'o Karen 聲調記號透過 dispatcher 透明排版。
  • 11-Phase 非 Devanagari Indic shaping 批次完成 (Phases 8f.0-8f.10):基礎設施 + 10 個註冊 Indic 腳本 —— Devanagari / Bengali / Gujarati / Tamil / Telugu / Kannada / Malayalam / Sinhala(Brahmic SIA 家族) / Khmer / Myanmar (東南亞)。
  • 遵循 Unicode 16.0 §16.3(Myanmar)與 OpenType Myanmar shaping 規範。

2026-05-23 Version 2.120.9

  • Khmer 文字排版器(Phase 8f.9):把 Khmer(OpenType tag khmr,Unicode 塊 U+1780-U+17FF)註冊為 HotPDF 第九個 Indic 腳本,也是首個東南亞腳本。新公開 ApplyKhmerReorder 重排前置 pass 與 GetKhmerCategory 碼點查詢,可透過 ApplyIndicReorder dispatcher 統一呼叫。
  • 獨立 syllable 結構(不同於 Phase 8f.1-8f.8 用的 Brahmic R1-R5 規則):pre-base 元音 (E / AE / AI / OE / OO / AU) 移到音節起始; register shifter(MUUSIKATOAN、TRIISAP)與其他上標記號路由到 above-base 緩衝;Bindu(NIKAHIT)放上方;Visarga(REAHMUK、 YUUKALEAPINTU)放尾部。
  • COENG 下標處理:每個 COENG (U+17D2) + 輔音對形成 stacked-consonant cluster,在 base 緩衝中保持原始順序,讓字體的 'pres' / 'blws' GSUB feature 負責 下標定位。FSM 支援嵌套 coeng。
  • 無 Repha:Khmer 文字不形成 Repha 視覺,因此 Ra + COENG + Consonant 保留原始順序,不會被旋轉到 音節末尾。
  • 遵循 Unicode 16.0 §16.4(Khmer)與 OpenType Khmer shaping 規範。

2026-05-23 Version 2.120.8

  • PAdES adbe-revocationInfoArchival CMS signed attribute(PAdES Phase 9):emit Adobe 私有 OID 1.2.840.113583.1.1.8,把 CRL 與 OCSP 撤銷值直接 塞進 CMS 簽章內部。Adobe Acrobat 在做簽章撤銷檢查時優先認這個 attribute,先於 DSS dictionary 查找與網絡 OCSP / CRL 獲取 —— 對離線可驗證 PDF 與 Adobe Acrobat 最佳互操作至關重要。
  • 新增 THPDFCMSSignOptions 欄位:
    • AdobeCRLsDER: array of TBytes —— 每個元素 一個 X.509 CertificateList (RFC 5280) DER, 與 DSS /CRLs 流的格式相同。
    • AdobeOCSPsDER: array of TBytes —— 每個元素 一個 BasicOCSPResponse SEQUENCE (RFC 6960 §4.2.1) DER。注意:不是 外層 OCSPResponse wrapper —— 持有完整 OCSPResponse 的呼叫方需要先剝出 responseBytes.response OCTET STRING 取出 BasicOCSPResponse
  • 啟用條件:兩個數組任一非空即 emit attribute。預設兩個數組 都為空時與 v2.120.7 字節級一致。
  • ASN.1 DER 按 Adobe 規範: RevocationInfoArchival ::= SEQUENCE { crl [0] EXPLICIT SEQUENCE OF CRL OPTIONAL, ocsp [1] EXPLICIT SEQUENCE OF BasicOCSPResponse OPTIONAL, otherRevInfo [2] EXPLICIT SEQUENCE OF OtherRevInfo OPTIONAL }。HotPDF 接通 [0][1][2] (非 X.509 撤銷系統)暫未實現。
  • Wire shape(兩個分支都填): 30 <len> A0 <crllen> 30 <...> <CRL1> <CRL2> A1 <ocsplen> 30 <...> <OCSP1> <OCSP2>
  • 與 DSS dictionary 並存:本 attribute 是 PAdES-B-LT DSS dictionary(Catalog 級 /DSS /Certs /OCSPs /CRLs /VRI,v2.110.0 引入)的 並行 路徑,不是替代。嚴格 PAdES 驗證器(EU DSS、mTOM) 傾向認 DSS;Adobe Acrobat 認 adbe-revocationInfoArchival。最大互操作就同時填兩層 —— 用 AddPAdESDSSCRL / AddPAdESDSSOCSP 喂 DSS,用 AdobeCRLsDER / AdobeOCSPsDER 喂 Adobe attribute。
  • 4-arg HPDFCMSBuildSignedData wrapper 把新欄位 顯式清零,legacy CMS bundle 字節級一致。
  • 對應 Adobe Acrobat PDF Reference + RFC 5280 (CRL) + RFC 6960 (OCSP)。

2026-05-23 Version 2.120.7

  • PAdES content-time-stamp CMS signed attribute(PAdES Phase 8):emit id-aa-ets-contentTimestamp(OID 1.2.840.113549.1.9.16.2.20,ETSI EN 319 122-1 §5.2.8 + RFC 5126 §5.11.4),攜帶簽章 之前 由 TSA 蓋章的 RFC 3161 TimeStampToken,證明文件內容在 TSA 聲明時間點 已存在。區別於 signature-time-stamp(Phase 4 unsigned attribute,簽章 之後)。
  • 新增 THPDFCMSSignOptions 欄位 GetContentTimeStamp: THPDFCMSTimestampCallback。 與 v2.120.3 的 GetSignatureTimeStamp 完全對稱: HotPDF 用 document SHA-256(與 messageDigest signed attribute 一致的 hash)呼叫回調,把返回的 TimeStampToken DER 作為 content-time-stamp attribute 的 value 塞進 SignedAttributes。
  • 預設 nil = 不 emit content-time-stamp。需要的 呼叫方賦值一個閉包透過 HTTP 驅動 RFC 3161 TSA。返回空 TBytes 靜默跳過(TSA 不可達時優雅降級)。
  • 免費 TSA endpoint(無需付費 / 無需註冊) 非合規場景可用: http://timestamp.digicert.comhttp://timestamp.sectigo.comhttp://timestamp.globalsign.com/tsa/r6advanced1https://freetsa.org/tsrhttp://timestamp.apple.com/ts01。eIDAS 合格簽章 場景需要付費 QTSA;普通商業用途用免費 endpoint 即可(有速率 限制但夠日常工作流程)。
  • 回調契約:每次簽章操作呼叫一次,時機在 SignedAttributes 封口 之前。TST 字節成為簽章內容的一部分,所以簽章本身 覆蓋了 content-time-stamp —— 這就是為什麼它是 signed attribute (與 signature-time-stamp 不同,後者是 unsigned,在簽章之後塞進 unsignedAttrs)。
  • 4-arg HPDFCMSBuildSignedData wrapper 把 GetContentTimeStamp:=nil 顯式清零,legacy CMS bundle 與 v2.119.27 字節級一致。
  • 呼叫方責任:PAdES 佔位符需要 ContentsBytes 夠容納 signature 加 content-time-stamp TST(~4-8 KB 典型)。B-T 工作流程同時用 content-time-stamp + signature-time-stamp 時需考慮兩個 TST 的 合計大小 —— AddPAdESSignatureField(Profile='B-T') 預設 16 KB 一般夠用。
  • 對應 ETSI EN 319 122-1 V1.2.1 §5.2.8 + RFC 3161 §6 + RFC 5126 §5.11.4。

2026-05-23 Version 2.120.6

  • PAdES signer-attributes-v2 signedAssertions [2] 分支(PAdES Phase 7):收口 SignerAttributeV2 第三個也是最後一個 OPTIONAL 欄位。讓簽章者在 CMS 簽章內附帶 OID 標識的簽章聲明 (SAML 2.0 Assertion / JWT 緊湊形式 token / OAuth attestation / 組織自定義 attestation token)。
  • 新增 THPDFSignedAssertion record: SignedAssertionID(標識聲明類型的 dotted-notation OID)+ AssertionBody: TBytes(按 OID schema 預編碼 的 ANY 字節 —— 通常是包含 SAML XML 或 JWT compact form 的 OCTET STRING)。AssertionBody 為空時省略 ANY 欄位, 只保留 signedAssertionID(spec 允許,適用於以 OID 註冊的 boolean-style 聲明)。
  • 新增 THPDFCMSSignOptions 欄位 SignedAssertions: array of THPDFSignedAssertion。 支援多個聲明;HotPDF 把 SEQUENCE OF 用 [2] EXPLICIT(tag 0xA2)包起來。
  • SignerAttributeV2 emit 條件改為三個 OPTIONAL 欄位任一非空。 三者都填時按 spec 欄位順序輸出: SignerAttributeV2 SEQUENCE { [0] claimed..., [1] certified..., [2] signedAssertions... }
  • ASN.1(ETSI EN 319 122-1 §5.2.6): SignedAssertion ::= SEQUENCE { signedAssertionID OBJECT IDENTIFIER, signedAssertion ANY DEFINED BY signedAssertionID OPTIONAL }。帶 body 的單個聲明 wire 形式: A2 <len> 30 <len2> 30 <len3> 06 <OIDlen> <OID> <ANYbytes>
  • 複用 v2.120.1 的 CMSEncodeOIDFromString 編碼 assertion OID —— 接受任意 dotted-notation OID。
  • 4-arg HPDFCMSBuildSignedData wrapper 把新欄位 清零,legacy CMS bundle 字節級一致。
  • signer-attributes-v2 收口:三個 OPTIONAL 欄位 ([0] claimedAttributes / [1] certifiedAttributesV2 / [2] signedAssertions)經 Phase 5/6/7 全部接入。ETSI EN 319 122-1 §5.2.6 attribute producer 端完整覆蓋。
  • 對應 ETSI EN 319 122-1 V1.2.1 §5.2.6 + ANNEX A.1。

2026-05-23 Version 2.120.5

  • PAdES signer-attributes-v2 certifiedAttributesV2 [1] 分支(PAdES Phase 6):在 SignerAttributeV2 SEQUENCE 裡 emit X.509 attribute 證書(RFC 5755),與 v2.120.4 的 claimedAttributes [0] 並存或單獨使用。讓簽章者附帶 AA (Attribute Authority)簽發的角色證書,從密碼學上背書籤名者 聲明的身份 / 權限。
  • 新增 THPDFCMSSignOptions 欄位 CertifiedAttributeCertsDER: array of TBytes。每個 元素是呼叫方從簽發 AA 處取得的完整 DER 編碼 AttributeCertificate(RFC 5755)。HotPDF 把它們 原樣塞入 CertifiedAttributesV2 SEQUENCE OF 然後用 [1] EXPLICIT(tag 0xA1)包起來。
  • 現在只要 ClaimedRoles CertifiedAttributeCertsDER 任一非空, signer-attributes-v2 attribute 就會 emit。兩者 都填時 SignerAttributeV2 SEQUENCE 裡 [0][1] 依次出現,符合 spec 欄位 順序。
  • ASN.1 DER wire 形式(僅 CertifiedAttributesV2): A1 <len> 30 <len2> <AC1> <AC2> ...,每個 ACn 是呼叫方提供的 RFC 5755 AttributeCertificate SEQUENCE verbatim。 AttributeCertificateOtherAttributeCertificate 兩個 CHOICE 分支由呼叫方 的 DER 輸入決定(兩者都以 SEQUENCE 0x30 起頭;HotPDF 不解析)。
  • 4-arg HPDFCMSBuildSignedData wrapper 把新欄位 清零,legacy CMS bundle 與 v2.119.27 字節級一致。
  • 範圍:signedAssertions [2](SAML / JWT / 任意 OID token) 留待下一 Phase。
  • 對應 ETSI EN 319 122-1 V1.2.1 §5.2.6 + ANNEX A.1 + RFC 5755。

2026-05-23 Version 2.120.4

  • PAdES signer-attributes-v2 CMS signed attribute(PAdES Phase 5):emit id-aa-ets-signerAttrV2(OID 0.4.0.19122.1.1,ETSI EN 319 122-1 §5.2.6),讓 簽章者在 CMS bundle 內聲明角色(如 "Chief Financial Officer"、 "Authorised Representative")。取代 RFC 5126 §5.10 已 deprecated 的 v1 signerAttr
  • 新增 THPDFClaimedRole record: RoleOID(attribute 類型 OID,dotted notation; 通常用組織內部角色 OID 或 1.3.6.1.5.5.7.20.1 id-id-aa-PERMrole)+ RoleValue(UTF-8 字串,人類可讀的角色標籤)。
  • 新增 THPDFCMSSignOptions 欄位 ClaimedRoles: array of THPDFClaimedRole。支援多個 角色;每個角色成為 claimedAttributes [0] SEQUENCE OF 內的一個 Attribute。空數組(預設)壓制 attribute,未啟用此 功能的 v2.120.3 呼叫方字節級一致。
  • ASN.1 DER 結構(ETSI EN 319 122-1 §5.2.6 + ANNEX A.1,模塊 DEFINITIONS EXPLICIT TAGS): SignerAttributeV2 SEQUENCE { [0] EXPLICIT ClaimedAttributes }ClaimedAttributes ::= SEQUENCE OF Attribute。每個角色序列化為 Attribute { type OID, values SET OF UTF8String }。 EXPLICIT 標籤即 0xA0 把內層 SEQUENCE OF 字節 verbatim 包起來(內層 0x30 tag 保留)。
  • OID body 手編:04 00 81 95 32 01 01(arc 0.4.0.19122.1.1;19122 的 base-128 編碼 → 0x81 0x95 0x32 含 continuation bits)。未來自定義角色 OID 可走 v2.120.1 的 CMSEncodeOIDFromString
  • Scope 邊界:本 Phase 僅實現 claimedAttributes [0]certifiedAttributesV2 [1](RFC 5755 X.509 attribute 證書)與 signedAssertions [2](SAML / JWT 風格 token)需要額外基礎設施,等有具體需求再做。
  • 4-arg HPDFCMSBuildSignedData wrapper 把 ClaimedRoles 長度顯式歸零,legacy CMS bundle 與 v2.119.27 字節級一致。
  • 對應 ETSI EN 319 122-1 V1.2.1 §5.2.6 + EN 319 142-1 V1.2.1 §6.3 Table 1 行 signer-attributes-v2(MAY,0-or-1)。

2026-05-23 Version 2.120.3

  • PAdES signature-time-stamp CMS unsigned attribute(PAdES Phase 4):emit id-aa-signatureTimeStampToken(OID 1.2.840.113549.1.9.16.2.14,RFC 3161 §6 + ETSI EN 319 122-1 §5.3),放在 SignerInfo 的 [1] IMPLICIT unsignedAttrs SET 內。提供 PAdES-B-T trusted-time service 的 signature-time-stamp 路徑 (Table 1:B-T shall be provided,可用 signature-time-stamp document-time-stamp)。
  • 新增 THPDFCMSTimestampCallback anonymous method 類型: reference to function(const SigValueSHA256: TBytes): TBytes。HotPDF 用 SignerInfo.signatureValue 的 SHA-256(RFC 3161 §2.4.2 定義的 messageImprint)呼叫回調,把返回的 TimeStampToken DER 作為 attribute value 嵌入。
  • 新增 THPDFCMSSignOptions 欄位 GetSignatureTimeStamp。預設 nil 表示 不加時間戳;PAdES-B-T 呼叫方賦值一個閉包驅動 TSA HTTP / RFC 3161 通信並返回 TST 字節。返回空 TBytes 靜默跳過(如 TSA 不可達但 簽章仍要交付)。
  • 網絡 / 身份驗證 / TSA 賬戶處理留在呼叫方代碼裡;HotPDF 只把 結果接入 unsignedAttrs。與現有 AddPAdESSignatureField(Profile='B-T', ContentsBytes >= 16384) 佔位符尺寸自然配套。
  • ASN.1 wire:SignerInfo SEQUENCE 現在可選攜帶尾部 [1] IMPLICIT SET OF Attribute(tag 0xA1),內含一個 signature-time-stamp Attribute,其 value 是呼叫方 提供的 TimeStampToken ContentInfo 字節。
  • 4-arg HPDFCMSBuildSignedData wrapper 把 GetSignatureTimeStamp:=nil 顯式清零,legacy CMS bundle 字節級一致。
  • 對應 RFC 3161 §6 + ETSI EN 319 122-1 §5.3 + EN 319 142-1 V1.2.1 §6.3 Table 1 注 q(B-T 可用 signature-time-stamp 或 document-time-stamp 任一提供 trusted time)。

2026-05-23 Version 2.120.2

  • PAdES commitment-type-indication CMS SignedAttribute 支援(PAdES Phase 3):emit id-aa-ets-commitmentType attribute(OID 1.2.840.113549.1.9.16.2.16,ETSI EN 319 122-1 §5.2.3 + RFC 5126 §5.11),聲明簽章者透過本簽章所做的承諾類型(如 proof of origin / receipt / delivery / sender / approval / creation)。
  • 新增 THPDFCommitmentType 枚舉:ctNone (預設,壓制 attribute)、ctProofOfOriginctProofOfReceiptctProofOfDeliveryctProofOfSenderctProofOfApprovalctProofOfCreation(六個標準 id-cti-ets-* OID 來自 RFC 5126 §5.11.1,arc 1.2.840.113549.1.9.16.6.{1..6}),以及 ctCustom(呼叫方透過新增 CommitmentTypeOID 欄位提供任意 OID)。
  • 啟用條件:THPDFCMSSignOptions.CommitmentTypectNone 時 emit。預設空值時 v2.120.1 呼叫方字節級 一致。
  • 呼叫方責任(PAdES Part 1 §6.3 Table 1 注 d): emit commitment-type-indication 時 Signature Dictionary /Reason 入口必須不存在(互斥)。HPDFCMS 看不到 Sig Dict 狀態 —— 呼叫方需要選其一:要麼 AddPAdESSignatureField(Reason='', ...) + CommitmentType,要麼 CommitmentType=ctNone + 填 Reason
  • ASN.1 DER 結構: CommitmentTypeIndication SEQUENCE { commitmentTypeId OBJECT IDENTIFIER }。CommitmentTypeQualifier(RFC 5126 §5.11.2)省略,因為六個標準 id-cti-ets-* OID 沒有 qualifier 定義。需要 qualifier 的自定義 commitment 可以擴展 helper。
  • 4-arg HPDFCMSBuildSignedData wrapper 把新增 CommitmentType 欄位顯式清零,v2.119.27 legacy CMS bundle 保持字節一致。
  • 對應 ETSI EN 319 122-1 §5.2.3 + RFC 5126 §5.11 + ETSI EN 319 142-1 V1.2.1 §6.3 Table 1 注 d。

2026-05-23 Version 2.120.1

  • PAdES signature-policy-identifier CMS SignedAttribute 支援(PAdES Phase 2):emit id-aa-ets-sigPolicyId attribute(OID 1.2.840.113549.1.9.16.2.15,ETSI EN 319 122-1 §5.2.9 + RFC 5126 §5.8),聲明簽章所採用的簽章策略。PAdES-E-EPES (Part 2 V1.2.1 §5.4 Table 2)要求shall be present; 其他 PAdES 級別可選。
  • 新增 THPDFCMSSignOptions record 欄位: SignaturePolicyOID(策略文件的 dotted-notation OID 字串)、SignaturePolicyHash(策略文件摘要)、 SignaturePolicyHashAlgOID(摘要算法 OID,留空時 預設 SHA-256)、SignaturePolicyURI(可選 SPuri qualifier,按 RFC 5126 §5.8.1,OID 1.2.840.113549.1.9.16.5.1,指向策略文件 URL)。
  • 啟用條件:呼叫方同時填了 SignaturePolicyOIDSignaturePolicyHash 時才 emit policy attribute; 預設空值時 attribute 被壓制 —— baseline 簽章呼叫方與 v2.120.0 字節級一致。
  • 新增輔助函數 CMSEncodeOIDFromString 把任意 dotted-notation OID 編碼為 DER(X.690 §8.19:前兩個 arc 合併為 40*arc1 + arc2,後續 arc 按 base-128 + 高位 continuation 編碼)。策略 OID 由呼叫方業務決定,生產端無法 hard-code 為字節字面量。
  • ASN.1 DER 結構: SignaturePolicyId SEQUENCE { sigPolicyId OBJECT IDENTIFIER, sigPolicyHash OtherHashAlgAndValue [, sigPolicyQualifiers SEQUENCE OF SigPolicyQualifierInfo] }。 SPuri qualifier 把 URL 用 IA5String(tag 0x16)包在 SigPolicyQualifierInfo 裡。
  • 相容性:v2.120.0 呼叫方未填新增 policy 欄位時輸出字節級一致。 4-arg HPDFCMSBuildSignedData wrapper 把新欄位 顯式清零,legacy CMS bundle 保持不變。
  • 對應 ETSI EN 319 122-1 §5.2.9 + ETSI EN 319 142-2 V1.2.1 §5.4 Table 2 + RFC 5126 §5.8。

2026-05-23 Version 2.120.0

  • PAdES baseline CMS 屬性合規修復(PAdES Phase 1): SignPDFWithPFX 現在預設 emit ESS signing-certificate-v2 signed attribute(RFC 5035 / OID 1.2.840.113549.1.9.16.2.47),保護簽章證書身份不被替換。 ETSI EN 319 142-1 V1.2.1 §6.3 Table 1 把這條列為 所有 baseline 級別(B-B / B-T / B-LT / B-LTA)都 shall be provided
  • PAdES baseline 預設不再 emit CMS signing-time attribute。Table 1 明確要求 baseline 級別 cardinality 0(聲明的 簽章時間由 Signature Dictionary /M 入口承載,見 Table 1 注 g)。v2.119.27 路徑無論 profile 都 emit signing-time,被嚴格 PAdES 驗證器(EU DSS、Adobe Acrobat PAdES baseline 模式)拒收。
  • 新增公開 API:THPDFPAdESLevel 枚舉(8 個值,覆蓋 baseline B-B / B-T / B-LT / B-LTA、extended E-BES / E-EPES / E-LTV、legacy adbe.pkcs7), THPDFCMSSignOptions record(level + signingTime + signing-cert-v2 開關 + UTC 時間戳), HPDFCMSDefaultOptions(Level) 返回該 level 的規範預設值,HPDFCMSBuildSignedDataEx 接受 options record 的 CMS 構建器。
  • 向下相容:v2.119.27 四參數版 HPDFCMSBuildSignedData 簽章保留為 thin wrapper,emit 字節級一致的輸出(不含 signing-cert-v2,按呼叫方請求開關 signingTime)。鎖定 v2.119.27 CMS 字節的測試 fixture 保持不變。
  • 簽章 PDF 輸出的行為變更:呼叫 THotPDF.SignPDFWithPFX 處理 PAdES 佔位符 (AddPAdESSignatureField,SubFilter ETSI.CAdES.detached)時,輸出現在能透過嚴格 PAdES baseline 驗證。需要 v2.119.27 舊屬性集的呼叫方可以顯式呼叫 HPDFCMSBuildSignedDataEx + HPDFCMSDefaultOptions(palLegacy_adbePkcs7)
  • ASN.1 DER 結構(RFC 5035 §3): SigningCertificateV2 SEQUENCE { certs SEQUENCE OF ESSCertIDv2 },省略 SHA-256 AlgorithmIdentifier(X.690 §11.5 DEFAULT 值不可編碼),含 SHA-256 cert hash 與 IssuerSerial(複用現有 CMSExtractIssuerAndSerial 的 X.509 issuer + serialNumber 抽取)。
  • 對應 ETSI EN 319 142-1 V1.2.1 §6.3 Table 1 + RFC 5035 §3。

2026-05-23 Version 2.119.77

  • 新增 Sinhala shaper(Phase 8f.8)。Sinhala('sinh', U+0D80-U+0DFF)成為第八個註冊的 Indic 腳本。 THotPDF 新增公開方法 ApplySinhalaReorderGetSinhalaCategory
  • Sinhala 特性:有 Repha(Ra=U+0DBB + Halant=U+0DCA AL-LAKUNA); 三個 pre-base matras(E=U+0DD9、EE=U+0DDA、AI=U+0DDB), Phase 8f 中 pre-base matra 數量最多的腳本;3 個 split matras (U+0DDC O / U+0DDD OO / U+0DDE AU)按 Unicode 16.0 canonical 分解; U+0DDD OO 是三部件 split(E + AA + AL-LAKUNA)。
  • ApplyIndicReorder 派發器自動覆蓋 Sinhala(註冊表擴為 array[0..7])。
  • 21 個新 DUnitX 測例。Win32 + Win64 全平臺共 187/187 透過。
  • 對應 Unicode 16.0 §12.11(Sinhala)與 OpenType Sinhala shaping spec。

2026-05-23 Version 2.119.76

  • 新增 Malayalam shaper(Phase 8f.7)。Malayalam('mlym', U+0D00-U+0D7F)成為第七個註冊的 Indic 腳本。 THotPDF 新增公開方法 ApplyMalayalamReorderGetMalayalamCategory
  • Malayalam 特性:有 Repha(Ra=U+0D30 + Halant=U+0D4D CHANDRAKKALA); I-matra(U+0D3F)是 POST-base,與 Tamil 一致, 在 Brahmic 中獨特(不同於 Devanagari/Bengali/Gujarati 的 pre-base); E/EE/AI 是 pre-base;3 個 split matras(U+0D4A O / U+0D4B OO / U+0D4C AU)按 Unicode 16.0 canonical pre+post 分解;chillu 字母 (U+0D54-U+0D56、U+0D7A-U+0D7F)與 DOT REPH(U+0D4E)歸類為輔音。
  • ApplyIndicReorder 派發器自動覆蓋 Malayalam(註冊表擴為 array[0..6])。
  • 21 個新 DUnitX 測例,含 chillu / DOT REPH 類別專項覆蓋。 Win32 + Win64 全平臺共 166/166 透過。
  • 對應 Unicode 16.0 §12.10(Malayalam)與 OpenType Malayalam shaping spec。

2026-05-23 Version 2.119.75

  • 新增 Kannada shaper(GSUB 引擎路線圖 Phase 8f.6)。Kannada ('knda',U+0C80-U+0CFF)成為第六個註冊的 Indic 腳本。 THotPDF 新增公開方法 ApplyKannadaReorderGetKannadaCategory
  • Kannada 與 Devanagari / Bengali / Gujarati / Telugu 一樣有 Repha (Ra=U+0CB0 + Halant=U+0CCD)。與 Telugu 類似,Kannada 無 pre-base matras — 所有 Kannada matra 都是 above-base、below-base、 post-base 或 split。
  • 5 個 split matras 按 Unicode 16.0 canonical decomposition 自動展開: U+0CC0 II → U+0CBF(above)+ U+0CD5(post); U+0CC7 EE → U+0CC6(above)+ U+0CD5(post); U+0CC8 AI → U+0CC6 + U+0CD6(兩個 above); U+0CCA O → U+0CC6(above)+ U+0CC2(post); U+0CCB OO 是三部件 split:U+0CC6(above)+ U+0CC2 (post)+ U+0CD5(post) — Phase 8f 家族首個三部件 split 路由。
  • Above-base matras (R3):I (U+0CBF)、E (U+0CC6)、AU (U+0CCC)、 AI 長度標記 (U+0CD6)。Below-base matras (R4):Vocalic R/RR (U+0CC3-U+0CC4)、Vocalic L/LL matras (U+0CE2-U+0CE3)。Post-base matras (R5):AA (U+0CBE)、U/UU (U+0CC1-U+0CC2)、post-base 長度標記 (U+0CD5)。
  • ApplyIndicReorder 派發器自動覆蓋 Kannada(註冊表擴為 array[0..5])。
  • 測試:21 個新 DUnitX 測例(含全部 5 個 split decomposition 與 三部件 OO 專項驗證)。Win32 + Win64 全平臺共 145/145 透過。
  • 對應 Unicode 16.0 §12.9(Kannada)與 OpenType Kannada shaping spec。

2026-05-23 Version 2.119.74

  • 新增 Telugu shaper(GSUB 引擎路線圖 Phase 8f.5)。Telugu ('telu',U+0C00-U+0C7F)成為第五個註冊的 Indic 腳本。 THotPDF 新增公開方法 ApplyTeluguReorderGetTeluguCategory
  • Telugu 與 Devanagari / Bengali / Gujarati 一樣有 Repha(Ra=U+0C30 + Halant=U+0C4D)。與之前所有 Indic 腳本不同:Telugu 無 pre-base matras — 所有 Telugu matra 都是 above-base、below-base 或 split。
  • Above-base matras (R3):AA/I/II/E/EE/O/OO/AU 與長度標記 U+0C55。 Below-base matras (R4):U/UU/Vocalic R/RR (U+0C41-U+0C44)、 AI-length-mark (U+0C56)、Vocalic L/LL matras (U+0C62-U+0C63)。
  • 1 個 split matra:U+0C48 AI 在 reorder 時分解為 U+0C46(E above-base) + U+0C56(AI 長度標記 below-base)。
  • ApplyIndicReorder 派發器自動覆蓋 Telugu(註冊表擴為 array[0..4])。
  • 測試:17 個新 DUnitX 測例。Win32 + Win64 全平臺共 124/124 透過。
  • 對應 Unicode 16.0 §12.8(Telugu)與 OpenType Telugu shaping spec。

2026-05-23 Version 2.119.73

  • 新增 Tamil shaper(GSUB 引擎路線圖 Phase 8f.4)。Tamil ('taml',U+0B80-U+0BFF)成為第四個註冊的 Indic 腳本。 THotPDF 新增公開方法 ApplyTamilReorderGetTamilCategory
  • Tamil 與其他 Brahmic 腳本的差異:無 Repha(Tamil 傳統不形成 Repha 視覺);I-matra(U+0BBF)是 POST-base,在 Brahmic 腳本中獨特; II(U+0BC0)above-base;E/EE/AI(U+0BC6-U+0BC8)pre-base; 3 個 split matras(U+0BCA O = U+0BC6+U+0BBE,U+0BCB OO = U+0BC7+U+0BBE, U+0BCC AU = U+0BC6+U+0BD7)。
  • Halant 在 Tamil 中稱為 PULLI(U+0BCD)。ApplyIndicReorder 派發器自動覆蓋 Tamil(註冊表擴為 array[0..3])。
  • 測試:20 個新 DUnitX 測例。Win32 + Win64 全平臺共 107/107 透過。
  • 對應 Unicode 16.0 §12.7(Tamil)與 OpenType Tamil shaping spec。

2026-05-23 Version 2.119.72

  • 新增 Gujarati shaper(GSUB 引擎路線圖 Phase 8f.3)。Gujarati ('gujr',U+0A80-U+0AFF)成為 Devanagari 與 Bengali 之後 第三個註冊的 Indic 腳本。THotPDF 新增公開方法 ApplyGujaratiReorderGetGujaratiCategory
  • Reorder 規則:R1 Repha(Ra=U+0AB0 + Halant=U+0ACD),R2 pre-base (U+0ABF I),R3 above-base(U+0AC5 CANDRA E、U+0AC7 E、U+0AC8 AI —— Gujarati 的 E/AI 是 above-base,與 Devanagari 一致,與 Bengali 的 pre-base 不同),R4 below-base(U+0AC1-U+0AC4、U+0AE2-U+0AE3), R5 post-base(U+0ABE AA、U+0AC0 II、U+0AC9 CANDRA O、U+0ACB-U+0ACC O/AU)。無 split matras。
  • ApplyIndicReorder 派發器自動將 Gujarati 碼點路由到 Gujarati entry(IndicScripts 數組擴為 array[0..2])。 BuildUnicode*FieldContent helper 在 sfIndicShaping 啟用時自動覆蓋 Gujarati,集成點無需改動。
  • 測試:18 個新 DUnitX 測例,包含 R3 above-base 覆蓋以區分 Gujarati 與 Bengali 的 E/AI 處理。Win32 + Win64 全平臺共 87/87 透過。
  • 對應 Unicode 16.0 §12.6(Gujarati)與 OpenType Gujarati shaping spec。

2026-05-23 Version 2.119.71

  • 新增 Bengali shaper(GSUB 引擎路線圖 Phase 8f.2)。Bengali ('beng',U+0980-U+09FF)成為 Devanagari 之後第二個註冊的 Indic 腳本。THotPDF 新增公開方法 ApplyBengaliReorderGetBengaliCategory,與 Phase 8e Devanagari API 對稱。
  • Bengali reorder 規則:R1 Repha(Ra=U+09B0 + Halant=U+09CD), R2 pre-base matras(I=U+09BF,E=U+09C7,AI=U+09C8 —— Bengali 的 E/AI 是 pre-base,與 Devanagari 的 above-base 不同),R4 below-base (U+09C1-U+09C4,U+09E2-U+09E3),R5 post-base(U+09BE,U+09C0,U+09D7)。 Bengali 主塊無 above-base matra。
  • Split-matra 分解:U+09CB Oo 與 U+09CC AU 在 reorder 時分解為其可視元件(U+09C7 + U+09BE / U+09C7 + U+09D7), 使 GSUB 流水線按 canonical pre+post 位置處理。
  • ApplyIndicReorder 派發器自動將 Bengali 碼點路由到 Bengali entry;BuildUnicode*FieldContent helper 在 sfIndicShaping 啟用時自動覆蓋 Bengali 與 Devanagari,集成點無需任何修改。
  • 測試:18 個新 DUnitX 測例覆蓋 Bengali R1/R2/R4/R5、split 分解、conjunct 保留、混排穿過、idempotency、dispatcher 等價性。Win32 + Win64 全平臺共 69/69 透過。
  • 對應 Unicode 16.0 §12.2(Bengali)與 OpenType Bengali shaping spec。

2026-05-23 Version 2.119.70

  • Devanagari complete-shaper 升級(GSUB 引擎路線圖 Phase 8f.1): ApplyDevanagariReorder 現在應用完整 5 條 reorder 規則 (R1 Repha + R2 pre-base + R3 above-base + R4 below-base + R5 post-base), 取代 v2.119.55 僅有 R1 + R2 的子集。每個 syllable 的輸出簇順序: [pre-matras] + [base + halant + nukta + bindu/visarga/modifier] + [above-matras] + [below-matras] + [post-matras] + [Repha]
  • Conjunct 保留:consonant-halant-consonant 簇在 base 塊中保持分組; reorder 只移動 matra 與 Repha。單 pass 完成、idempotent。
  • 對比 v2.119.69 的行為變更:syllable 包含 above/below/post-base matra (或多 matra 混合簇)時,PDF 字節流現在反映 canonical 重排版面。GSUB/ GPOS 之後的視覺渲染保持不變。僅含 R1 Repha 或 R2 pre-base I-matra (v2.119.55 子集)的輸入仍字節一致。
  • 測試:8 個新 DUnitX 測例覆蓋 R3 / R4 / R5 單獨、多 matra 順序、 matra 下 conjunct 保留、Repha + above + post 混合,以及多 matra idempotency。Win32 + Win64 全平臺共 51/51 透過。
  • 對應 Unicode 16.0 §12.1(Devanagari)與 OpenType Devanagari shaping spec。

2026-05-23 Version 2.119.69

  • Indic shaping 基礎設施(GSUB 引擎路線圖 Phase 8f.0):將 v2.119.55 / v2.119.67 的 Devanagari reorder 前置預處理重構成 script-agnostic 的派發框架。新增類型 TIndicScriptInfo / TIndicCategoryFunc / TIndicFindSyllableFunc / TIndicReorderFunc,以及新的 IndicScripts 註冊表,後續 Indic 腳本透過函數指針掛載即可接入。
  • 新公開方法 ApplyIndicReorder(Wide)Wide 的每個碼點派發到對應已註冊的 script,並呼叫該 script 的 syllable + reorder 回調。非 Indic 內容按字節穿過不變。
  • 三處 BuildUnicode*FieldContent helper 在 sfIndicShaping 包含在 FShapingFeatures 時改為呼叫 ApplyIndicReorder(取代僅覆蓋 Devanagari 的舊 wrapper)。Phase 8f.0 僅註冊 Devanagari,後續 Phase 8f.2 至 8f.10 將逐步添加 Bengali、Gujarati、Tamil、Telugu、Kannada、Malayalam、Sinhala、Khmer、Myanmar,集成點本身無需再改。
  • ApplyDevanagariReorder 保留為僅覆蓋 Devanagari 的薄包裝,向 v2.119.55 呼叫者提供向後相容;輸出與 v2.119.67 字節一致。
  • 對應 Unicode 16.0 §12(南亞腳本)與 ISO 32000-1 §9.10。

2026-05-22 Version 2.119.68

  • Phase 8c.6 — 透過 PUA 合成 codepoint 映射實現 producer 端 GID 級 emit:THotPDF 新增兩個公開方法,讓呼叫方為無自然 Unicode codepoint 的替換 GID 按需分配合成 PUA (U+E000-U+F8FF) codepoint。AssignSyntheticCodepointForGID (GID; out SyntheticCP): Boolean 分配下一個可用 PUA slot,把分配鏡像到 FUnicodeCpToGid + FAcroFormUnicodeAdvances + 新的 FUnicodeSyntheticCpForGID 逐 GID 查詢表,讓現有 producer 端十六進制編碼 pipeline 把合成 codepoint emit 為 4 hex-digit token,消費端 reader 透過 /CIDToGIDMap 解析到替換字形。GetSyntheticCodepointForGID (GID): Word 查詢已有分配(未分配返回 0)。兩個方法都冪等 —— 同一 GID 重複呼叫返回同一合成 codepoint。
  • 解鎖無 Unicode Presentation Form codepoint 的字體特定 GSUB 替換的 producer 端 emit:Devanagari cluster 形態 (Indic 'akhn' / 'rphf' / 'pres' / 'blws' / 'psts' / 'haln' 輸出通常落到字體內部 GID)、stylistic alternates ('salt' / 'ss01-20' 無 codepoint 替換)、discretionary ligatures ('dlig' / 'hlig' 字體特定字形)、CJK 表意文字變體序列替換。配合 v2.119.43-50 GSUB 引擎 API 和 v2.119.50 MarkUnicodeGlyphUsed 子集化閉包,呼叫方現在可構建完整的 producer 端 shaping pipeline,透過現有 codepoint 基礎的 hex pipeline emit 任意替換 GID。
  • 狀態生命期:合成映射在再次 RegisterUnicodeTTF 呼叫或 BeginDoc 觸發前持續(兩者都重置所有 per-font 狀態含合成表)。PUA 範圍 U+E000-U+F8FF 提供 6400 slot,足夠任何實用字體的 GSUB 替換集合。ToUnicode CMap 反向映射是呼叫方責任 —— 合成 PUA codepoint 無源 codepoint 可反向映射;關心文本提取的呼叫方應在 PDF marked content 中包裹文本 emit 配 /ActualText 屬性指定原源 codepoint。未呼叫 AssignSyntheticCodepointForGID 的呼叫方 PDF 輸出與 v2.119.67 字節級一致(新方法是無狀態查詢 / 顯式分配 helper;無自動副作用)。本 commit 完成 GSUB 引擎 roadmap Phase 8 capability 矩陣。

2026-05-22 Version 2.119.67

  • Devanagari reorder pre-pass 自動應用 (GSUB 引擎 roadmap Phase 8e):三個 BuildUnicode*FieldContent helper 現在在 sfIndicShaping 包含於 FShapingFeatures 時自動呼叫 v2.119.55 ApplyDevanagariReorder。pre-pass 走遍輸入 Wide,應用兩個 Devanagari 專屬重排(音節起始 Ra-Halant 的 Repha 重定位 + 前置 I-matra U+093F 移到音節聚類起始),讓 emit 的 codepoint 流匹配視覺讀序。消費 reader 的 GSUB 引擎再對重排後的 codepoint 應用 Indic shaping 鏈('nukt' / 'akhn' / 'rphf' / 'rkrf' / 'pref' / 'half' / 'vatu' / 'cjct' / 'pres' / 'blws' / 'abvs' / 'psts' / 'haln')生成最終 cluster 字形。
  • Scope:Phase 8e 僅交付 producer 端 reorder。Producer 端 GSUB 鏈應用(producer 在 PDF emit 時提交 cluster shaping 而非依賴 reader)留待 Phase 8c.6,因為多數 Devanagari GSUB 替換落在字體特定 GID 無 Unicode Presentation Form codepoint —— 與 Arabic / Latin 的 Forms-A / Forms-B 塊提供 codepoint 可達替換不同,Devanagari 在 Unicode 中沒有對應的 Presentation Form 範圍。Phase 8c.6 PUA synthetic codepoint mapping 會解鎖 Devanagari 和其他替換 GID 字體特定的 Indic / 南亞腳本的 producer 端 GSUB emit。
  • 非 Devanagari 內容經 ApplyDevanagariReorder 字節級穿透(方法僅走 Devanagari 音節,其他 codepoint 範圍原樣 emit)。未設 sfIndicShaping (預設) 的呼叫方 PDF 輸出與 v2.119.66 字節級一致。結合 v2.119.55 capability 層 (GetDevanagariCategory + ApplyDevanagariReorder 公開 method),本 commit 完成 Devanagari producer 端 reorder 集成:啟用 sfIndicShaping 的呼叫方不再需要在 BuildUnicode*FieldContent 之前手動調 ApplyDevanagariReorder —— HotPDF 自動完成。

2026-05-22 Version 2.119.66

  • GSUB 'rclt' (Required Contextual Alternates) 自動集成:新方法 THotPDF.ApplyArabicGSUBContextualRefinement (Wide) 與 v2.119.63 ApplyArabicGSUBRefinement 平行,但走 contextual substitution (GSUB Type 5 / 6) 透過 v2.119.47 ApplyContextualSubst API,而非 ligature substitution (Type 4)。'rclt' 編碼上下文相關的必需替換 —— 典型用法是 Arabic 字體的 v2.85.0 靜態 walker Forms-B 映射之外的額外位置變體,以及南亞 / Indic 字體的 cluster 級依賴鄰居上下文的重排形態。
  • 變長輸出處理:與 ApplyLigatureSubstitution (N 輸入 GID → 1 替換 GID) 不同,ApplyContextualSubst 可從 N 輸入 GID 產生 M 替換 GID。上下文規則 fire 時,**所有** 替換 GID 必須可經 Unicode Presentation Form codepoint 反向 cmap 到達 (FB00-FDFF + FE70-FEFF 約 770 codepoint 掃描) 才提交替換;任一替換無反向映射時輸入窗口原樣穿透(部分 emit 會破壞序列)。Reverse cmap 範圍擴到含 Latin / Armenian / Hebrew Presentation Forms (FB00-FB4F) 加完整 Arabic 範圍,任意腳本的 'rclt' 替換都可 emit。
  • 新 THPDFShapingFeature 枚舉成員 sfContextualAlternates(追加在末尾保後向相容 —— 既有呼叫方走 v2.119.59 5 成員枚舉的 FShapingFeatures 集合算術編譯不變)。接入 3 個 BuildUnicode*FieldContent helper,gated on sfContextualAlternates in FShapingFeatures(opt-in,預設 off)。獨立於 FAutoShapeArabic —— 'rclt' 可應用於非 Arabic 腳本 (Latin / Hebrew / Indic)。替換 GID 走 MarkUnicodeGlyphUsed 閉包入 v2.84.0 subsetter。字體無 'rclt' 規則或替換 GID 無 Presentation Form codepoint 時防禦 no-op。未設 sfContextualAlternates 的呼叫方 PDF 輸出與 v2.119.65 字節級一致。

2026-05-22 Version 2.119.65

  • Latin 'liga' Standard Ligatures emit (GSUB 引擎 roadmap Phase 8b):新方法 THotPDF.ApplyLatinLigatureRefinement (Wide) 與 v2.119.63 ApplyArabicGSUBRefinement 平行,但目標是 Latin / Armenian / Hebrew Alphabetic Presentation Forms U+FB00-U+FB4F。走遍輸入 Wide,透過 FUnicodeCpToGid 構建並行 GID 數組,每位置調 v2.119.43-50 ApplyLigatureSubstitution API 查詢字體 GSUB 'liga' feature。如果替換 fire AND 替換 GID 可經 Unicode Alphabetic Presentation Form codepoint 到達,源 codepoint 窗口替換為替換 codepoint。接入三個 BuildUnicode*FieldContent helper (單行、多行、comb AcroForm /AP),gated on sfStandardLigatures in FShapingFeatures (opt-in, 未置位時字節級穩定)。
  • 可選第二 pass 'clig' (Contextual Ligatures):當 sfContextualLigatures 也在 FShapingFeatures 中時,方法對 'liga' 結果再走一遍 'clig' pass 捕獲字體特定的上下文 ligation(fi / fl / ffi / ffl 標準集之外)。每個 emit 替換 GID 都過 MarkUnicodeGlyphUsed 走 v2.84.0 TTF subsetter 閉包。Reverse cmap 是 ~80 codepoint (FB00-FB4F) 的線性掃描;替換稀疏,開銷可忽略。
  • ToUnicode CMap bfchar 塊從 28 條擴到 35 條:7 個新條目覆蓋 Latin Alphabetic Presentation Forms FB00 (ff -> f + f)、FB01 (fi -> f + i)、FB02 (fl -> f + l)、FB03 (ffi -> f + f + i)、FB04 (ffl -> f + f + l)、FB05 (ſt -> long s + t)、FB06 (st -> s + t)。PDF 文本流出現 Latin ligature codepoint 時,消費端文本提取(複製 / 粘貼 / 無障礙)還原源 ASCII 字母序列。未設 sfStandardLigatures (預設) 的呼叫方 PDF 輸出與 v2.119.64 字節級一致。Scope:僅 emit 經 Alphabetic Presentation Form codepoint 可達的替換 —— 無 Unicode codepoint 的裝飾 / discretionary Latin ligature (字體特定 GID) 不能透過此路徑 emit,留 Phase 8c.6 GID-level emit。

2026-05-22 Version 2.119.64

  • 公開 codepoint advance 查詢 API (GSUB 引擎 roadmap Phase 8c.5):新方法 THotPDF.GetCodepointAdvance (CP: Cardinal): Single 暴露 v2.76.0 /W cache,讓在 BuildUnicodeMultilineFieldContent helper 之外自建 word-wrap 計算的呼叫方能查詢任意 codepoint 的真實 scaled em advance,源自字體 hmtx 表經緩存 cmap。v2.119.32 / v2.119.58 / v2.119.60 / v2.119.62 靜態 ligature post-pass 鏈 + v2.119.63 GID-level GSUB refinement emit ligature codepoint (LAM-ALEF FEF5-FEFC、YEH-HAMZA FBEA-FBFB、Allah FDF2、Bismillah FDFD、GSUB 替換的 Presentation Forms in FB50-FDFF / FE70-FEFF) 之後,本方法返回真實 ligature 字形的 hmtx advance —— 通常比源 codepoint advance 之和窄 —— 讓呼叫方的 wrap 預算與消費端渲染對齊。
  • BuildUnicodeMultilineFieldContent heuristic fallback 優化:v2.65 fallback 路徑(/W cache 不可用時使用,例如走 RegisterUnicodeFontDict 而非 RegisterUnicodeTTF 時)此前把 codepoint >= U+2E80 全部當 wide (1.0 em) 處理。Arabic Presentation Forms (FB50-FBFF Forms-A 字母、FC00-FDFF Forms-A 合字 + Quranic FDF0-FDFD、FE70-FEFF Forms-B 基本形態 + LAM-ALEF) 實際上是 narrow (主流 Arabic 字體平均約 0.55 em),不是 wide。v2.119.64 把這三個 Arabic Presentation Form 範圍在 heuristic fallback 中路由到 narrow 路徑 (0.5 em),修復 v2.119.32 / v2.119.58 / v2.119.60 / v2.119.62 / v2.119.63 post-pass emit 的 Arabic 合字在 cache 未填充時獲得錯誤 1.0 em advance 的邊角情形。
  • 典型無資訊路徑(未註冊字體、cache 未填充、codepoint 超 BMP、codepoint 無字體 cmap 字形)返回 0。純函數無副作用,RegisterUnicodeTTF 成功後任何上下文都可安全呼叫。/W cache 已填充且未使用新查詢方法的 PDF 輸出與 v2.119.63 字節級一致。Phase 8c.5 在 capability 層收口 GSUB 引擎 roadmap §8c producer 端自動 Arabic GSUB shaping pipeline —— Phase 8c.1-8c.5 共同交付靜態表 post-pass (4 合字家族) + ToUnicode 反向映射 + GID-level GSUB refinement + 公開 advance 查詢,協同讓 producer 端 Arabic 合字渲染與消費端顯示字節級對齊。

2026-05-22 Version 2.119.63

  • GID-level GSUB 'rlig' refinement post-pass (GSUB 引擎 roadmap Phase 8c.2):新方法 THotPDF.ApplyArabicGSUBRefinement (Wide) 從左到右走遍輸入 Wide,透過緩存 cmap (FUnicodeCpToGid) 構建並行 GID 數組,每個非零 GID 位置呼叫 v2.119.43-50 ApplyLigatureSubstitution API 查詢字體的 GSUB 'rlig' (Required Ligatures) feature。如果替換 fire AND 替換 GID 可經過 Unicode Arabic Presentation Form codepoint 到達(reverse cmap 掃描 U+FB50-U+FDFF + U+FE70-U+FEFF 約 690 codepoint),源 codepoint 窗口被替換 codepoint 取代。替換字形透過 MarkUnicodeGlyphUsed 走 v2.84.0 TTF subsetter 閉包。
  • 接入三個 BuildUnicode*FieldContent helper,緊跟 v2.85.0 / v2.119.32 / v2.119.58 / v2.119.60 / v2.119.62 靜態 codepoint 級 post-pass 鏈(LAM-ALEF / YEH-HAMZA / Allah / Bismillah)。補充靜態表,捕獲 4 個硬編碼家族之外的字體特定 'rlig' 規則 —— 典型例子包括 Persian / Urdu / Sindhi / Kurdish 字體(Vazirmatn、Markazi Text、Lateef、Scheherazade、Amiri)中映射到 LAM-ALEF / YEH-HAMZA / Allah / Bismillah 集合之外 Unicode Presentation Forms 的上下文變體。僅在 FAutoShapeArabic = True AND sfArabicGSUB NOT in FShapingFeatures(mutex 保 v2.119.59 "呼叫方驅動" 路徑)AND 載入字體有 GSUB 表時執行。
  • Scope 邊界:僅 emit GID 可經 Presentation Form codepoint 到達的替換。替換 GID 落到任意字形 ID(無 codepoint 反向映射)的字體特定 GSUB 替換不能透過此路徑 emit —— 需要 Phase 8c.5+ 範圍的 producer pipeline 完整 GID 級 emit。Reverse cmap 是每次替換嘗試約 690 codepoint 的線性掃描;實際替換稀疏,開銷可忽略。載入字體無 GSUB 'rlig' 內容或替換 GID 無 Presentation Form codepoint 的 PDF 輸出與 v2.119.62 字節級一致(方法在這些情況下是防禦性 no-op)。本切片落地後,GSUB 引擎的 producer 端自動 Arabic shaping pipeline 獲得超出硬編碼靜態錶鏈的字體感知 ligature folding 能力。

2026-05-22 Version 2.119.62

  • Bismillah 短語級合字 post-pass (GSUB 引擎 roadmap Phase 8c.4):v2.85.0 producer 端 Arabic shaper 現在把 22 codepoint 的標準 Bismillah 短語 "بسم الله الرحمن الرحيم"("以最仁慈、至慈的真主之名")摺疊為單一 U+FDFD ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM codepoint。在 post-pass 鏈的**最先**執行(在 LAM-ALEF / YEH-HAMZA / Allah 摺疊之前),保證在 v2.119.60 Allah post-pass 折掉 الله 子短語前能檢測完整短語。每個字母位置匹配原始 codepoint 或任一 v2.85.0 Forms-B shaped 變體(R-joining 字母每個 3 變體,D-joining 5 變體);3 個空格位置必須正好是 U+0020。標準未帶 harakat 拼寫的短語級檢測。
  • ToUnicode CMap 加入第 28 個 bfchar 條目,把 U+FDFD 反向映射到完整 22-codepoint 源序列(BEH + SEEN + MEEM + SPACE + ALEF + LAM + LAM + HEH + SPACE + ALEF + LAM + REH + HAH + MEEM + NOON + SPACE + ALEF + LAM + REH + HAH + YEH + MEEM)。消費端文本提取(複製 / 粘貼 / 無障礙)現在還原原 22-codepoint 短語而非單一合字字形,完成 4 個靜態表合字家族(LAM-ALEF / YEH-HAMZA / Allah / Bismillah)的 round-trip 行為收口。
  • 已知限制(故意的 scope 縮減):tatweel (U+0640) 在字母間不匹配;harakat / 變音符號在字母間不匹配(標準摺疊針對未注音 Bismillah);非斷行空格 U+00A0 或多空格不匹配(僅匹配單個 ASCII U+0020);不同拼寫(الرحمٰن 含上標 ALEF)不匹配;短語必須正好出現無後接修飾。假陽率本質為零,因為標準 22-codepoint 序列在意圖上唯一對應 Bismillah。其他 Quranic 敬辭(FDFA SALLALLAHOU ALAYHE WASALLAM、FDFB JALLAJALALOUHOU)和單詞級合字(FDF3 AKBAR / FDF4 MOHAMMAD / FDF5 SALAM 等)不在範圍內,因為這些源詞在非宗教文本中也作為普通 Arabic 詞出現,會產生假陽。

2026-05-22 Version 2.119.61

  • Arabic 合字 ToUnicode CMap 反向映射 (GSUB 引擎 roadmap Phase 8c.3):v2.83.0 RegisterUnicodeTTF 發射的 Adobe-Identity-UCS CMap 現在擴展 27 個 bfchar 條目,覆蓋 v2.85.0 producer 端 Arabic shaper post-pass 鏈發射的每個 ligature codepoint,把 bfrange identity 映射 override 為正確的源 codepoint 序列。在消費端文本提取(複製 / 粘貼 / 無障礙)時還原源 Arabic 詞,修復之前合字 codepoint 單字符提取的限制(例如 Allah 之前複製得到單字符 "ﷲ" 而非源詞 "الله")。bfchar 按 Adobe CMap and CIDFont Files Specification 規定優先於 bfrange。
  • 覆蓋範圍:8 個 LAM-ALEF 條目 U+FEF5-U+FEFC(v2.119.32 強制合字,4 個 ALEF 變體 × 2 形態)→ LAM + ALEF / ALEF MADDA / ALEF HAMZA ABOVE / ALEF HAMZA BELOW 源對;18 個 YEH-HAMZA 家族條目 U+FBEA-U+FBFB(v2.119.58,含 auto post-pass 不產生但呼叫方可手動使用的起始形態 FBF8 和 FBFB)→ YEH-HAMZA + ALEF / AE / WAW / U / OE / YU / E / ALEF MAKSURA 源對;1 個 Allah 條目 U+FDF2(v2.119.60)→ ALEF + LAM + LAM + HEH 四 codepoint 源序列。本切片落地後,三個靜態表合字家族的複製 / 粘貼 / 無障礙 round-trip 完整。
  • 非 Arabic 內容字節級穩定:bfchar 塊在 CMap 流中加約 700 字節未壓縮 PostScript 文本,FlateDecode 壓縮後通常約 150-200 字節。不含 Arabic 內容的 PDF 仍發射相同的 /ToUnicode 流佈局 —— 擴展在同一間接 FlateDecode 流物件內可加。主流消費 reader(Adobe Reader、Foxit、PDF.js、Apple Preview 等)都遵循 bfchar 優先於 bfrange 並正確應用反向映射。27 條目塊在 CMap 文本中硬編碼(無需逐 PDF 定製);後續 Phase 8c.4 將追加 U+FDFD Bismillah 合字的 bfchar 條目。

2026-05-22 Version 2.119.60

  • Allah 合字靜態 post-pass:v2.85.0 producer 端 Arabic shaper 現在在 v2.119.32 LAM-ALEF 和 v2.119.58 YEH-HAMZA post-pass 完成之後再走一遍 post-pass,把 ALEF + LAM + LAM + HEH 四 codepoint 序列(الله 標準 Arabic 寫法)摺疊為單一 codepoint U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM。模式與前兩個 ligature post-pass 一致:掃描 raw 與各 shaped form 任意組合的源序列、輸出單一 codepoint、依賴字體在 Unicode 定義的 cmap 項有該合字字形。這是 GSUB 引擎 roadmap Phase 8c (producer 端自動 Arabic GSUB shaping pipeline) 的第一刀 —— codepoint 級 ligature folding,覆蓋最常用的 Arabic 宗教合字。
  • 源字母 form 匹配覆蓋 v2.85.0 walker 成形之後的所有合法組合:ALEF 匹配 raw U+0627 或孤立形 FE8D 或末位形 FE8E(R-joining,無 init / medi);LAM 匹配 raw U+0644 或四種 shaped form FEDD-FEE0 之一(D-joining,4 個位置形態全集);HEH 匹配 raw U+0647 或四種 shaped form FEE9-FEEC 之一(D-joining)。一個典型獨立 "الله" 單詞在 walker 之後變成 FE8D + FEDF + FEE0 + FEEA(ALEF 孤立 + LAM 起 + LAM 中 + HEH 末),摺疊為 FDF2。不含 Allah codepoint 序列的 PDF 輸出與 v2.119.59 字節級一致。
  • codepoint 級 ligature folding 的已知限制:(1) 輸出僅 isolated form FDF2 —— Unicode 沒有為 Allah 合字定義 final / initial / medial form,但實際 Allah 幾乎總是獨立渲染,單 FDF2 codepoint 在視覺渲染上夠用。(2) 消費端文本提取(複製 / 粘貼 / 無障礙)得到單字符 "ﷲ" 而非四字符詞 "الله",因為 ToUnicode CMap 還沒擴展為把 FDF2 反向映射到其 4 codepoint 源。後續 Phase 8c.3 安裝件會透過 bfchar 反向映射解決。(3) 字體依賴:載入的 TTF / OTF 必須有 U+FDF2 → Allah 字形的 cmap 條目;主流 Arabic 字體(Noto Sans Arabic、Amiri、Scheherazade、Lateef、Markazi Text、Tahoma / Times New Roman Arabic)都含此字形。其他 Quranic 合字(FDF0 / FDF1 / FDF3-FDFB Allah 家族 honorifics、FDFD Bismillah)和 GID-level GSUB 集成(處理無 Unicode Presentation Forms 的字體特定替換)留待後續 Phase 8c.2-8c.4 安裝件。

2026-05-22 Version 2.119.59

  • Producer 端 shaping pipeline opt-in 框架 (GSUB 引擎 roadmap Phase 8a):新枚舉 THPDFShapingFeature + 集合類型 THPDFShapingFeatures 模型化 Phase 8a-8e producer 端文本成形集成的規劃 feature flag。5 個枚舉成員:sfArabicGSUB(本版本實現)、sfStandardLigatures(Phase 8b 留待)、sfContextualLigatures(Phase 8b 留待)、sfStylisticAlternates(Phase 8d 留待)、sfIndicShaping(Phase 8e 留待)。THotPDF 新增 ShapingFeatures 屬性 (THPDFShapingFeatures 類型),預設值 [] (全部關閉);v2.119.32-58 呼叫方只要保持預設值,輸出字節級一致。
  • sfArabicGSUB 是與 v2.85.0 靜態表 Arabic shaper 互斥的開關。當 ShapingFeatures 含 sfArabicGSUB 時,三個 BuildUnicode*FieldContent helper(單行、多行、comb AcroForm /AP 外觀流構造器)完全跳過 _ApplyArabicShaping —— 不做 v2.85.0 四位置 codepoint 改寫、不做 v2.119.32 LAM-ALEF post-pass、不做 v2.119.58 YEH-HAMZA + 元音 post-pass。呼叫方負責透過 v2.119.43-50 GSUB 引擎 API 驅動 Arabic 成形 (SetGSUBScript ('arab') + GetSingleSubstituteGlyph 配 'init' / 'medi' / 'fina' / 'isol' feature tag + MarkUnicodeGlyphUsed 走 v2.84.0 子集化器閉包)。配合 sfArabicGSUB,使用 Noto Sans Arabic / Amiri / Scheherazade / Markazi Text 等 Arabic 字體的呼叫方現在可以在 producer 時驅動完整的字體側 GSUB Arabic 成形,不依賴靜態表 fallback。
  • 配套 Arabic capability API:兩個新公開方法 GetArabicJoiningClass (CP) 和 GetArabicPosition (Wide, Index) 鏡像 v2.119.53 GetSyriacJoiningClass / v2.119.54 GetMongolianJoiningClass 模式,暴露靜態 shaper 內部使用的 joining-class 表和 4 位置上下文 walker。手動驅動 Arabic GSUB 成形的呼叫方不再需要逐 codepoint 重新推導 joining-class 資料 —— 可直接複用 v2.85.0 / v2.119.35 / v2.119.52 / v2.119.57 累積表(覆蓋基本 Arabic U+0600-U+06FF + Arabic Supplement U+0750-U+077F + Arabic Extended-A U+08A0-U+08FF)。本切片落地後,使用者的兩點需求"Forms-A FBEA-FBFB 裝飾類合字 (v2.119.58) + Producer 端自動 Arabic GSUB shaping pipeline (本版本)"在能力層 + opt-in 框架層完成。完整的 producer 端自動 GSUB 應用 (TextOut / BuildUnicode*FieldContent 內自動 cmap-to-GID + 逐位置 GSUB substitute + substitute GID emit, 呼叫方零代碼) 留待更深的 Phase 8c 集成 commit。

2026-05-22 Version 2.119.58

  • YEH-HAMZA + 元音字母合字 post-pass:v2.85.0 producer 端 Arabic shaper 現在在 4 位置 walker 和 v2.119.32 LAM-ALEF post-pass 之後,再走一遍 post-pass 把 Arabic Presentation Forms-A 塊 U+FBEA-U+FBFB 區域內 8 對 ligature pair 摺疊為單一合字碼點。模式與 LAM-ALEF 一致(靜態表強制替換、每個 ligature 輸出 2 形態)。覆蓋的 pair:YEH-HAMZA + ALEF -> FBEA/FBEB(標準 Arabic / Persian / Urdu)、YEH-HAMZA + AE U+06D5 -> FBEC/FBED(Kashmiri / Uyghur)、YEH-HAMZA + WAW -> FBEE/FBEF(標準 Arabic)、YEH-HAMZA + U U+06C7 -> FBF0/FBF1(Uyghur / Kazakh / Kyrgyz)、YEH-HAMZA + OE U+06C6 -> FBF2/FBF3、YEH-HAMZA + YU U+06C8 -> FBF4/FBF5、YEH-HAMZA + E U+06D0 -> FBF6/FBF7、YEH-HAMZA + ALEF MAKSURA -> FBF9/FBFA(標準 Arabic)。
  • YEH-HAMZA 匹配原始碼點 U+0626 或任一 v2.85.0 成形後形態(FE89 isol / FE8A final / FE8B init / FE8C medial);後跟元音字母匹配原始碼點或任一 v2.119.57 Forms-A 成形變體(U 的 FBD7-FBD8、OE 的 FBD9-FBDA、YU 的 FBDB-FBDC、E 的 FBE4-FBE7)或 v2.85.0 Forms-B 成形變體(ALEF 的 FE8D-FE8E、WAW 的 FEED-FEEE、ALEF MAKSURA 的 FEEF-FEF0)。末位形態選擇(base + 1)遵循 LAM-ALEF 規則:YEH-HAMZA 已被 walker 改寫為 FE8A final 或 FE8C medial 形態時(即前面有 dual-joining 字母),合字 emit 末位形態;否則 emit 孤立形態。
  • Scope 邊界:post-pass 只 emit 孤立和末位形態(2 形態輸出)。Unicode 定義的起始形態 FBF8(YEH-HAMZA + E)和 FBFB(UIGHUR YEH-HAMZA + ALEF MAKSURA)不被產生 —— 需要 3 形態變體的呼叫方用 ApplyContextualSubst 驅動字體的 'rlig' / 'clig' 鏈式上下文 GSUB lookup。其他 Arabic 合字區(Allah U+FDFA / FDFB、裝飾類合字 FC00-FDC7)需 GSUB 'rlig' / 'dlig' 驅動,靜態表 shaper 不在 scope 內。不含上述 YEH-HAMZA + 8 元音字母 pair 的 PDF 輸出與 v2.119.57 字節級一致 —— 新 post-pass 只在那 2 碼點序列上觸發。

2026-05-22 Version 2.119.57

  • Persian / Urdu / Sindhi / Kashmiri / Uyghur / Kazakh / Kyrgyz Arabic 擴展字母全覆蓋:v2.85.0 producer 端 Arabic shaper 的 joining-class 表現在按 Unicode 16.0 ArabicShaping.txt 完整覆蓋 U+0672-U+06D5 範圍,關閉 v2.119.35(Persian/Urdu 核心 9 字符)+ v2.119.52(ALEF WASLA / NOON GHUNNA / HEH 變體)落地時留下的"Persian/Urdu Form-B 擴展"工作面。新增約 80 個字母的 joining-class 條目,覆蓋 REH / DAL / SEEN / SAD / TAH / AIN / FEH / QAF / KAF / GAF / LAM / NOON / HEH / WAW / YEH 各種變體 —— 相鄰字母現在不論緊挨哪個 Arabic Extended-A 字母都能正確選擇位置形態。
  • 新分類字母中 26 個還有 U+FB52-U+FBFC 範圍的靜態 Presentation Forms-A 編碼,現在被靜態表 shaper 直接映射、無需字體 GSUB shaper 介入:15 個 D-joining 4 形態字母(TTEHEH U+067A → FB5E-FB61、BEEH U+067B → FB52-FB55、TEHEH U+067F → FB62-FB65、BEHEH U+0680 → FB5A-FB5D、NYEH U+0683 → FB76-FB79、DYEH U+0684 → FB72-FB75、TCHEHEH U+0687 → FB7E-FB81、VEH U+06A4 → FB6A-FB6D、PEHEH U+06A6 → FB6E-FB71、NG U+06AD → FBD3-FBD6、NGOEH U+06B1 → FB9A-FB9D、GUEH U+06B3 → FB96-FB99、RNOON U+06BB → FBA0-FBA3、HEH DOACHASHMEE U+06BE → FBAA-FBAD(Urdu 標準 'h' 字母)、E U+06D0 → FBE4-FBE7(Kazakh/Kyrgyz Arabic 用))和 11 個 R-joining 2 形態字母(DAHAL U+068C → FB84-FB85、DDAHAL U+068D → FB82-FB83、DUL U+068E → FB86-FB87、KIRGHIZ OE U+06C5 → FBE0-FBE1、OE U+06C6 → FBD9-FBDA、U U+06C7 → FBD7-FBD8、YU U+06C8 → FBDB-FBDC、KIRGHIZ YU U+06C9 → FBE2-FBE3、VE U+06CB → FBDE-FBDF、YEH BARREE U+06D2 → FBAE-FBAF(Urdu 詞尾 yeh)、YEH BARREE WITH HAMZA ABOVE U+06D3 → FBB0-FBB1)。
  • 其中 HEH DOACHASHMEE 和 YEH BARREE 兩個字母值得專門說明:它們的 Forms-A 槽位(FBAA-FBAD 和 FBAE-FBAF)正是 v2.119.52 錯誤地分配給 U+06C2 HEH GOAL WITH HAMZA ABOVE 和 U+06C3 TEH MARBUTA GOAL 的兩組碼點。v2.119.56 撤銷錯誤映射 + v2.119.57 把槽位綁定到正確源字符之後,審計鏈路清晰,混淆徹底解決。U+0672-U+06D5 範圍內 Unicode 16 沒有 Forms-A 編碼的字母(約 50 個,主要是 REH/DAL/SEEN/SAD/TAH/AIN/FEH/QAF/KAF 變體無預編碼成形)仍參與 joining-class 分析讓鄰居正確成形;字母本身按原 codepoint 穿透,自身成形依賴字體 GSUB lookup(呼叫方用 v2.119.43-50 GSUB 引擎驅動)。編譯 78018 行;不含這些新增字符的 PDF 輸出與 v2.119.56 字節級一致。

2026-05-22 Version 2.119.56

  • Arabic shaping bug 修復:v2.119.52 引入了兩個 Urdu / Sindhi 區域字符的錯誤 Presentation Forms-A 映射。U+06C2 HEH GOAL WITH HAMZA ABOVE 被錯誤映射到 FBAA-FBAD,而該碼點範圍實際屬於 U+06BE HEH DOACHASHMEE;消費 PDF reader 會把 Urdu 的 Goal-Heh-with-Hamza 字形渲染成標準的 Urdu Heh-Doachashmee 字形。U+06C3 TEH MARBUTA GOAL 被錯誤映射到 FBAE-FBAF,而該碼點範圍實際屬於 U+06D2 YEH BARREE;reader 會把 Teh-Marbuta-Goal 渲染成 Urdu 詞尾 Yeh-Barree。按 Unicode 16.0,U+06C2 和 U+06C3 都沒有預編碼的 Presentation Forms-A 條目,必須保持原始 codepoint 不變穿透(消費 reader 透過字體 cmap 和字體 GSUB 驅動的 shaping 正確顯示這兩個字符)。
  • 修復:v2.85.0 producer 端 Arabic shaper 的 _ArabicShape Forms-A 查找表刪除了兩個錯誤 case 項;U+06C2 和 U+06C3 現在走 passthrough 路徑,原 codepoint 不變 emit。v2.119.52 的 joining-class 條目(U+06C2 歸 D / U+06C3 歸 R)保留不變,讓這兩個字符在詞中時鄰居仍能正確選擇位置形態。本修復僅影響在 AutoShapeArabic 開啟時含 U+06C2 或 U+06C3 的 PDF;不含這兩個碼點的 PDF 與 v2.119.55 輸出字節級一致。配套發佈的 v2.119.57 把 Forms-A 覆蓋擴到更多 Persian / Urdu / Sindhi / Kashmiri / Uyghur / Kazakh / Kyrgyz 字母,包含本次錯誤所混淆的真正具備 Forms-A 編碼的 HEH DOACHASHMEE 和 YEH BARREE。

2026-05-22 Version 2.119.55

  • Devanagari Indic shaping capability:THotPDF 新增兩個公開方法覆蓋與 Arabic / Syriac / Mongolian 4 位置 joining 模型不同的 Indic 成形範式。GetDevanagariCategory (CP) 按 Unicode 16.0 §12.1 + IndicSyllabicCategory.txt 返回簡化 Indic 音節類別 (0 = Other / 1 = Consonant / 2 = Independent Vowel / 3 = Matra / 4 = Virama / 5 = Nukta / 6 = Bindu / 7 = Visarga / 8 = Danda / 9 = Digit / 10 = ZWJ / 11 = ZWNJ / 12 = Modifier);表覆蓋 Devanagari 塊全部 U+0900-U+097F,含 Marwari / Sindhi / Vedic 擴展 U+0978-U+097F。
  • ApplyDevanagariReorder (Wide) 從左到右走遍輸入串,對每個 Devanagari 音節應用 Indic reorder pre-pass,返回適合 cmap + GSUB 消費的重排 UnicodeString。非 Devanagari 內容(Latin、數字、標點、其他腳本)字節級穿透。實現兩個主導 Devanagari 重排規則:(1) Repha —— 當音節以 Ra (U+0930) + Halant (U+094D) + 輔音開頭時,把 (Ra, Halant) 對移到音節末尾,讓字體的 'rphf' GSUB feature 替換為視覺上貼在音節基字符右上方的 Repha 字形;(2) 前置 I-matra —— U+093F 移到音節最前(如有 Repha 刪除之後),讓從左到右的 GSUB 處理在輔音聚合前看到 i-matra,與視覺渲染順序對齊。
  • 呼叫方流水線:ApplyDevanagariReorder 對邏輯順序文本預重排 → SetGSUBScript ('deva') → 用 GetSingleSubstituteGlyph + ApplyLigatureSubstitution + ApplyContextualSubst 應用 GSUB feature ('nukt' / 'akhn' / 'rphf' / 'rkrf' / 'half' / 'vatu' / 'cjct' / 'pres' / 'blws' / 'abvs' / 'psts' / 'haln') → emit 輸出 GID 到 PDF 文本流,並對每個 emit GID 呼叫 MarkUnicodeGlyphUsed 走 v2.84.0 子集化器閉包。Phase A (v2.119.52 Arabic Extended-A 收尾) + Phase B (v2.119.53 Syriac capability) + Phase C (v2.119.54 Mongolian capability) + Phase D (v2.119.55 Devanagari Indic capability) 全部落地後,矩陣 gap "Mongolian / Syriac / Devanagari shaping" 完全關閉。Scope 邊界:非 Devanagari Indic 腳本(Bengali / Tamil / Telugu / Gujarati 等各有自己的類別資料和重排規則)、Repha + 前置 I-matra 之外的重排規則,以及 TextOut / BuildUnicode*FieldContent 內自動 Devanagari 成形(留待 GSUB 引擎 roadmap Phase 8)均不在本版本範圍。

2026-05-22 Version 2.119.54

  • Mongolian shaping capability:THotPDF 新增兩個公開方法暴露 Mongolian (U+1800-U+18AF) joining-class 查詢與 4 位置上下文分析,讓呼叫方能在 producer 端驅動 Mongolian 文本成形。GetMongolianJoiningClass (CP) 按 Unicode 16.0 §13.5 返回 Mongolian joining 類 (0 = U 非連接、2 = D 雙連接、4 = T 透明 / 變體選擇器);表覆蓋基本 Mongolian + Todo + Sibe + Manchu + Ali Gali 字母擴展 (U+1820-U+1878 + U+1887-U+18A8 + ALI GALI DAGALGA U+18A9 + MANCHU ALI GALI LHA U+18AA),並把 NIRUGU (U+180A)、三個 Free Variation Selectors FVS1-FVS3 (U+180B-U+180D) 和 Ali Gali BALUDA / THREE BALUDA 元音標記 (U+1885-U+1886) 歸為透明類。GetMongolianPosition (Wide, Index) 在 0-based Index 處的字母上跳過透明標記走前後向,返回 0 = 孤立、1 = 末位、2 = 起位、3 = 中位。
  • 與 Syriac (v2.119.53) 一樣,Mongolian 在 Unicode 中**沒有**預編碼的 Presentation Forms —— 每個支援 Mongolian 的字體(Mongolian Baiti、Noto Sans Mongolian、Noto Serif Mongolian 等)都透過其 'mong' script 標籤下的 'init' / 'medi' / 'fina' / 'isol' OpenType GSUB feature 完成位置成形。所以 v2.119.54 繼續走 v2.119.53 的能力層路徑;呼叫方將位置輸出與 v2.119.43-50 GSUB 引擎 API 組合(SetGSUBScript ('mong') → GetSingleSubstituteGlyph 配合對應位置 feature tag → MarkUnicodeGlyphUsed 讓 v2.84.0 子集化器閉包)生成可直接 emit 到 PDF 文本流的成形 GID。
  • Mongolian 在原生書寫方向上是豎排自上而下;walker 在**邏輯** codepoint 順序上工作(codepoint 流中的前驅 / 後繼),與視覺方向無關。實際的自上而下渲染在 PDF emit 時透過 /WMode 1 (豎排書寫模式) 或字體矩陣旋轉處理,而非 shaper 介入。Free Variation Selectors 歸為透明類讓 walker 在 FVS 跟在字母之後時仍能正確解算位置形態;字體的 GSUB 在 'fina' / 'medi' / 'init' / 'isol' feature 內的 lookup 在輸入流含 FVS 時自動選取 FVS 限定變體。Devanagari (Indic) 成形留待後續版本,因為它需要按 UAX #38 做 Indic reorder pre-pass (virama / 輔音聚合 / pre-base 重排),與 Arabic / Syriac / Mongolian 的 4 位置 walker 模型不相容。TextOut / BuildUnicode*FieldContent 內自動 Mongolian 成形留待 GSUB 引擎 roadmap Phase 8。

2026-05-22 Version 2.119.53

  • Syriac shaping capability:THotPDF 新增兩個公開方法暴露 Syriac (U+0700-U+074F) joining-class 查詢與 4 位置上下文分析,讓呼叫方能在 producer 端驅動 Syriac 文本成形。GetSyriacJoiningClass (CP) 按 Unicode 16.0 SyriacShaping.txt 返回 joining 類 (0 = U 非連接、1 = R 右連接、2 = D 雙連接、4 = T 透明 / NSM);表覆蓋 Syriac 塊全部 35 個字母(含 PERSIAN BHETH / GHAMAL / DHALATH 在 U+072D-U+072F、SOGDIAN ZHAIN / KHAPH / FE 在 U+074D-U+074F 等 Suriyani / Sogdian 擴展)並把 SUPERSCRIPT ALAPH (U+0711) 與 Syriac 組合標記 (U+0730-U+074A) 歸為透明類。GetSyriacPosition (Wide, Index) 在 0-based Index 處的字母上跳過透明標記走前後向,返回 0 = 孤立、1 = 末位、2 = 起位、3 = 中位。
  • 與 Arabic 不同(Arabic 有預編碼的 Presentation Forms-B U+FE70-U+FEFF 和 Forms-A U+FB50-U+FBFF 塊,HotPDF 可直接把 codepoint 改寫為成形變體),Syriac 塊在 Unicode 中**沒有**預編碼的位置形態 —— 每個支援 Syriac 的字體(Estrangelo Edessa、Serto Jerusalem、East Syriac Adiabene、Noto Sans Syriac 等)都透過其 'init' / 'medi' / 'fina' / 'isol' OpenType GSUB feature 完成位置成形。所以 v2.119.53 僅提供能力層;呼叫方將位置輸出與 v2.119.43-50 GSUB 引擎 API 組合(SetGSUBScript ('syrc') → GetSingleSubstituteGlyph 配合對應位置 feature tag → MarkUnicodeGlyphUsed 讓 v2.84.0 子集化器閉包)生成可直接 emit 到 PDF 文本流的成形 GID。
  • Alaph 終態範圍:Unicode §9.3 記載了兩個上下文終態 feature ('fin2' 在 DALATH / RISH 之後應用,'fin3' 在 FINAL LAMADH 之後應用),Syriac 字體用它們切換 Alaph 末位字形。v2.119.53 把 Alaph (U+0710) 歸為基本右連接,僅返回 0 (孤立) 或 1 (末位);需要 'fin2' / 'fin3' 區分的呼叫方用 ApplyContextualSubst 配以對應 feature tag 驅動字體的鏈式上下文 lookup 即可。Mongolian 和 Devanagari (Indic) 成形留待後續版本:Mongolian 用 Free Variation Selectors + vowel harmony,Devanagari 需 Indic reorder pre-pass per UAX #38,二者均不適用 Syriac 風格的 4 位置 walker。TextOut / BuildUnicode*FieldContent 內自動 Syriac 成形留待 GSUB 引擎 roadmap Phase 8。

2026-05-22 Version 2.119.52

  • Arabic 家族 shaping 擴展:v2.85.0 producer 端靜態 Arabic shaper 現在覆蓋 Arabic Extended-A 剩餘字符 (ALEF WASLA U+0671、NOON GHUNNA U+06BA、HEH 變體 U+06C0-U+06C3)、Arabic Supplement 塊 U+0750-U+077F (用於豪薩語、Wolofal 等非洲語言的非洲 Arabic 字母) 以及 Arabic Extended-A 新分配區 U+08A0-U+08FF (古蘭經 Arabic + Wolofal/Hausa 擴展字母 + 古蘭經組合標記)。Joining 類資料源 Unicode 16.0 ArabicShaping.txt,在 v2.85.0 四位置分析中應用,讓相鄰字母不論緊挨哪個 Arabic 變體都能正確選擇 init / medi / fina / isol 位置形態。
  • 在 Arabic Presentation Forms-A 塊 (U+FB50-U+FBFF) 有預編碼靜態 presentation form 的字母現在直接映射到對應形態,無需 OpenType GSUB shaper 介入:ALEF WASLA → FB50/FB51 (右連接,兩形態)、NOON GHUNNA → FB9E/FB9F (按 Unicode 是雙連接但只有兩個預編碼形態,init/medi 優雅降級為 isol)、HEH WITH YEH ABOVE → FBA4/FBA5 (右連接,兩形態)、HEH GOAL → FBA6/FBA7/FBA8/FBA9 (雙連接,完整四形態)、HEH GOAL WITH HAMZA ABOVE → FBAA/FBAB/FBAC/FBAD (雙連接,完整四形態)、TEH MARBUTA GOAL → FBAE/FBAF (右連接,兩形態)。合併 v2.119.32 LAM-ALEF 強制合字後處理與 v2.119.35 Persian/Urdu 核心 9 字母子集,靜態 shaper 現在幾乎覆蓋全部現代 Arabic、Persian、Urdu、Sindhi、Pashto、Kurdish、Uyghur、古蘭經及非洲 Arabic (Hausa、Wolofal 等) 文本,不依賴字體的 GSUB 表。
  • Arabic Supplement (U+0750-U+077F) 和較新的 Arabic Extended-A 字母段 (U+08A0-U+08C7) 沒有預編碼靜態 presentation form;它們的 joining 類條目讓相鄰字母正確成形,但字母本身保持原始 codepoint,自身的位置成形依賴支援 GSUB 的字體 (或呼叫方驅動 v2.119.43-50 GSUB 引擎 API)。Arabic Extended-A 古蘭經組合標記區 (U+08CA-U+08E1、U+08E3-U+08FF) 被歸類為透明 (T 連接),讓相鄰位置分析自動跳過它們,與既有的 U+064B-U+065F harakat 處理一致。不含這些擴展字符的文本與 v2.119.51 輸出字節級一致。Mongolian / Syriac / Devanagari shaping (與 Arabic 不同的 shaping 模型) 留待後續版本。

2026-05-22 Version 2.119.51

  • XFA (XML Forms Architecture) producer 端容器層支援:PDF 1.7 §12.7.6 + §12.7.8 允許 AcroForm 在靜態 /Fields 數組之外(或替代)攜帶 /XFA 入口。新方法 THotPDF.AddXFAPacket(PacketName, XMLBytes) 註冊一個命名 XFA packet —— 常用名稱包括 'template'(表單佈局 + 腳本)、'datasets'(資料綁定)、'config'(viewer 配置)、'connectionSet'、'localeSet'、'stylesheet'、'xfdf'、'xmpmeta'、'signature'、'sourceSet'。每個註冊的 packet 在 EndDoc 時變成一個 FlateDecode 壓縮的間接流,/XFA 數組按註冊順序交替排列 packet 名稱 PDF 字串和流引用,確保字節級可重現。THotPDF.ClearXFAPackets 和 THotPDF.XFAPacketCount 補齊 API 表面。
  • 僅容器層支援 —— HotPDF **不**解析 XFA XML、**不**實現 XFA 動態佈局引擎、**不**執行 XFA template 內的 FormCalc / JavaScript、**不**驗證 template 結構。呼叫方自行編寫 XFA XML(通常用 Adobe LiveCycle Designer 或參照 XFA 3.3 規範手寫),HotPDF 按字節原樣發射。含 XFA 引擎的消費 reader(舊版 Acrobat / Reader、FormsCentral、某些 kiosk 產品)渲染表單;不含 XFA 引擎的 reader(Adobe Reader DC 2017 起、多數開源 reader)若文件是 AcroForm + XFA 混合工作流程則顯示 AcroForm 後備欄位。
  • PDF/A 與 PDF/X 合規閘門:ISO 19005-1 §6.4.2 / ISO 19005-2 §6.4.2 / ISO 19005-3 §6.4.2 都明確禁止 XFA 表單(動態佈局引擎無法確定性歸檔)。ISO 15930 印刷工作流程完全拒絕交互式表單。AddXFAPacket 在任意非空 PDFACompliance 或 PDFXCompliance 下立即拋帶 spec 引用的異常。重複 packet 名拋異常。空 PacketName 或空 XMLBytes 拋異常。RequirePDFVersion(pdf15) 自動 bump 文件版本。AcroForm 字典現在在 /Fields 至少一個條目或至少一個 XFA packet 已註冊時發射;未註冊 packet 的 pre-v2.119.51 呼叫方 /AcroForm 輸出字節級一致。

2026-05-22 Version 2.119.50

  • TTF 子集化器對 GSUB substitute 字形的閉包:新方法 THotPDF.MarkUnicodeGlyphUsed(GID: Word) 不管 cmap 是否有 codepoint 能到達,都把該字形 opt-in 到 v2.84.0 EndDoc 子集化器。v2.84.0 closure 透過 cmap 從 FUnicodeUsedCps 派生 used-glyph 集合,所以所有 GSUB 引入的替換字形 —— stylistic alternates、合字、contextual 變體,Phase 1-6 查詢 API 的全部輸出 —— 之前都對子集化器不可見,消費 PDF reader 在它們位置渲染 .notdef。在 emit GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst 返回的任何 GID 到 PDF 文本流後,呼叫方現在為每個 emit 的 GID 呼叫一次 MarkUnicodeGlyphUsed(GID) 把它拉入嵌入子集。
  • helper 冪等(重複呼叫同一 GID 是 no-op)、防禦(GID >= FUnicodeNumGlyphs 靜默丟棄;任何 RegisterUnicodeTTF 成功之前的呼叫是 no-op)、並與 v2.84.0 _BuildSubsetTTF 內的複合字形閉包 pass 集成:呼叫方只需 mark 頂層 substitute GID —— 元件由現有 _TTFWalkCompositeClosure walk 自動拉入。集合在首次呼叫時懶分配,並在每個 RegisterUnicodeTTF('', nil) 時與其餘子集狀態一併重置為空。Phase 9 落地後,Phase 1-7 的每個 GSUB 查詢 API 都能與子集 emission 安全配對,不會出現 substitute 字形從嵌入字體中掉隊的問題。

2026-05-22 Version 2.119.49

  • OpenType GSUB Script / LangSys 選擇 API:THotPDF 新增 5 個公開方法,讓呼叫方把 GSUB 查詢固定到特定 script 和 language,而非歷史的 DFLT-script / 預設 LangSys fallback。SetGSUBScript ('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' 等) 選擇 OpenType script 標籤;預設空字串維持 v2.119.43-48 baseline(優先 'DFLT',否則首個 script)。SetGSUBLanguage ('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' 等,呼叫方需空格填充到 4 字節) 選擇 OpenType 語言標籤;空字串走 script 的預設 LangSys。兩個設置跨 GSUB 查詢持久存在,在 RegisterUnicodeTTF('', nil) 時復位為空。
  • 3 個新枚舉 helper 暴露字體公佈的內容:GetGSUBScripts: TGSUBStringArray 按 ScriptList 順序返回每個 script 標籤;GetGSUBLanguages(ScriptTag) 返回該 script 下的所有 language 標籤(當 script 有預設 LangSys 時 index 0 是 '' 佔位符);GetGSUBFeatures(ScriptTag, LangTag) 按 LangSys featureIndices 順序返回 (script, language) 路徑下的所有 feature 標籤(如 'liga' / 'salt' / 'aalt' / 'ss01' 到 'ss20')。空 ScriptTag / LangTag 走與替換 API 相同的 DFLT-first / 預設 LangSys fallback,呼叫方可直接 GetGSUBFeatures('', '') 枚舉預設路徑下的 feature,不需要先看 script 列表。
  • 嚴格匹配 vs 回退語義:SetGSUBScript 設置為字體不公佈的標籤時,後續 GSUB 查詢返回空 / no-op —— 引擎**不會**靜默 fallback 到 DFLT,讓呼叫方清楚知道選定 script 不可用。SetGSUBLanguage 設置為不認識的標籤時**會**按 OpenType spec 建議 fallback 到 script 預設 LangSys。已有 7 個 GSUB 替換方法 (GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyphCount / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst) 公開簽章字節級穩定,僅內部 `_GSUBFindFeatureLookups` helper 增加 2 個尾部參數,所有 7 個呼叫點同步路由。Script / LangSys API + LookupType 1-8 矩陣全部就位後,GSUB 引擎對 capability-only 使用已經 feature-complete;剩餘 roadmap phase(自動 shaping pipeline + TTF subsetter 閉包)面向 producer-side 集成,不增加新查詢面。

2026-05-22 Version 2.119.48

  • OpenType GSUB Reverse Chained Contextual Single Substitution (LookupType 8):新方法 THotPDF.ApplyReverseChainedContextualSubst(const InputGIDs; StartIndex; FeatureTag; out OutGID): Boolean —— GSUB 最後一個 LookupType 落地。Type 8 做上下文相關的 1:1 單字替換,替換字形由輸入字形的 Coverage 索引選定,特點是呼叫方必須以"反向"順序(從末尾向起始)掃描多字形序列 —— 因為每個替換字形可能依賴未來 lookahead 上下文,這些位置必須尚未被替換。helper 是單點 applier,呼叫方負責驅動反向 scan loop。Coverage Format 1 + 2、LookupFlag honor(input + backtrack + lookahead 全部 skip-aware)、Extension 包裝(LookupType 7)都支援。
  • 典型使用者:某些 Arabic / Syriac / N'Ko / Indic 上下文替代形態,其終態依賴後續字形的具體形狀。一些字體也用於 Latin 序列消歧。與 LookupType 5/6 不同,Type 8 沒有 nested-lookup 機制 —— 替換本質就是 1:1。未命中返回 False、OutGID = InputGIDs[StartIndex](best-effort 透傳,與 v2.119.43 GetSingleSubstituteGlyph 契約一致)。
  • LookupType 矩陣收口:v2.119.48 起,OpenType GSUB 全部 8 個 LookupType (1-8) 都在 THotPDF 上有專用公開 capability。Script / LangSys 選擇 API、自動 shaping pipeline 接入、TTF 子集化器自動拉 substitute 字形 留待 Phase 7-9;呼叫方仍需手動把選中的替換字形 mark 進字體子集,且自行驅動反向 scan loop。

2026-05-22 Version 2.119.47

  • OpenType GSUB Contextual + Chained Contextual Substitution (LookupType 5 + 6):新方法 THotPDF.ApplyContextualSubst(const InputGIDs; StartIndex; FeatureTag; var OutGIDs; out ConsumedLen): Boolean 是統一入口,覆蓋 LookupType 5(僅 input 上下文)和 LookupType 6(backtrack / input / lookahead 三段上下文),並支援全部 3 個子表 Format —— Format 1(字面 glyph ID 序列)、Format 2(ClassDef 類序列)、Format 3(Coverage 表序列,現代字體最常用)。典型使用者:'rclt' (Required Contextual Alternates — 字體透過 GSUB 驅動的 Arabic init/medi/fina/isol 位置形態)、'clig' (Contextual Ligatures)、'calt' (Contextual Alternates)、Indic 系列 ('pres' / 'blws' / 'psts' / 'half' / 'pstf' / 'cjct')。
  • SequenceLookupRecord nested lookup 派發:contextual rule 命中後,SequenceLookupRecord 條目分別在匹配的 input 子序列特定位置觸發 nested lookup。新 helper `_GSUBApplyNestedLookup` 重新進入 GSUB LookupList,透明解 Extension 包裝,派發到 Single (Type 1) / Multiple (Type 2) / Alternate (Type 3,取 index 0) / Ligature (Type 4) applier。dispatcher 跟蹤 live MatchPositions[],讓後續 SequenceLookupRecord 在 Multiple Substitution 1→N 擴張或 Ligature Substitution N→1 摺疊後仍能正確尋址 working position。Nested LookupType 5 / 6 / 8(遞歸 contextual)刻意延後;多數實際字體把 nested lookup 接 Type 1 / 4。
  • 命中時返回 True + 應替換 InputGIDs[StartIndex..StartIndex+ConsumedLen-1] 的輸出字形序列。OutGIDs 長度可能與 ConsumedLen 不同(nested 1→N 或 N→1 lookup 觸發時)。ConsumedLen 始終是 contextual rule 吸收的總 input 跨度(含 significant glyphs 之間被 LookupFlag 跳過的 marks);典型呼叫方按 ConsumedLen 推進 scan loop 並 emit OutGIDs。未命中返回 False、空 OutGIDs、ConsumedLen = 1 —— 與 v2.119.43-46 helper 一致的安全 no-op。LookupFlag honor (Phase 4) 貫穿 contextual match:backtrack / input / lookahead walk 全部跳過被 flag 標記應忽略的字形。本版本 Script / LangSys 仍固定為 DFLT default;選擇 API 是 Phase 7 範圍。

2026-05-22 Version 2.119.46

  • OpenType GSUB Extension Lookups (LookupType 7):GSUB 引擎現在透明解包 Extension Substitution 子表 —— OpenType spec 為體積過大、LookupList Offset16 不夠觸達實際子表的字體定義的純轉向層。v2.119.43-45 的所有公開 API (GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyphCount / GetAlternateGlyph / ApplyLigatureSubstitution) 自動跟隨 32-bit Offset32 轉向找到真正的 LookupType 1/2/3/4 子表。這是解鎖 GSUB 表超過 64 KB 的重型 CJK / Indic OpenType 字體(Noto Sans CJK / Noto Sans Devanagari 等)的關鍵 binary-layout 改造 —— 這類字體長期把 lookup 包在 LookupType 7 後面,之前在 HotPDF 看起來 feature 表是空的。
  • OpenType GDEF (Glyph Definition) 表解析:RegisterUnicodeTTF 現在在字體含 GDEF 表時也緩存。三個 GDEF 子表驅動 LookupFlag honor 邏輯 —— GlyphClassDef 把每個 GID 分類為 base(1) / ligature(2) / mark(3) / component(4);MarkAttachClassDef 給每個 mark 字形標註 attachment 類;MarkGlyphSetsDef (v1.2+) 聲明命名的 mark 集合。ClassDef Format 1 (startGlyphID + classValueArray) 和 Format 2 (排序的 classRangeRecords) 都實現;GDEF v1.0 / v1.1 / v1.2 header 都接受(v1.3 itemVariationStore 忽略)。無 GDEF 表的字體退回 v2.119.43-45 baseline 行為("不忽略任何字形"),保持字節級穩定。
  • OpenType GSUB LookupFlag honor:5 個 GSUB 公開 API 現在都讀取每個 Lookup 表的 LookupFlag(以及 LookupFlag.useMarkFilteringSet 時尾部跟隨的可選 markFilteringSet uint16),跳過被標記應忽略的 input 字形。spec 定義的 flag bits 都尊重:0x0002 ignoreBaseGlyphs (跳過 GDEF.GlyphClassDef class 1)、0x0004 ignoreLigatures (跳過 class 2)、0x0008 ignoreMarks (跳過 class 3)、0x0010 useMarkFilteringSet (只有命名 MarkGlyphSet 內的 mark 參與),以及高字節 markAttachmentType (只有指定 MarkAttachClassDef 類的 mark 參與)。對 Ligature Substitution (LookupType 4) 影響最大:含 mark 字形分隔的 Arabic 'rlig' / Indic 'akhn' 合字(如 LAM + Fatha + ALEF)現在在 LookupFlag.ignoreMarks 設置時能正確匹配,返回的 ConsumedCount 包含被跳過的 mark 字形,呼叫方掃描循環正確跨過所有被吸收的 input 字形。0x0001 (rightToLeft) 是 GPOS 專用,GSUB lookup 仍忽略。
  • 沿用同樣的防禦性契約:無 GSUB 表的字體、非 4 字節 tag、字體 DFLT script 未公佈的 feature、無子表覆蓋的 GID、以及現在新增的 LookupFlag-ignored 輸入字形 都返回 v2.119.43-45 的安全 no-op 結果。5 個公開 API 簽章字節級穩定,僅內部 lookup walk 接入 Extension dispatch + LookupFlag honor + GDEF classification。Script / LangSys 選擇 API、自動 shaping pipeline 接入、TTF 子集化器自動拉 substitute 字形 仍留待後續版本。

2026-05-22 Version 2.119.45

  • OpenType GSUB Ligature Substitution (LookupType 4):新方法 THotPDF.ApplyLigatureSubstitution(const InputGIDs: array of Word; StartIndex; FeatureTag; out OutGID; out ConsumedCount): Boolean 把多字形分量序列摺疊成單個合字字形。典型使用者:'liga' (Standard Ligatures — fi / fl / ffi / ffl)、'clig' (Contextual Ligatures)、'dlig' (Discretionary Ligatures)、'hlig' (Historical Ligatures)、'rlig' (Required Ligatures — 字體透過 GSUB 驅動 shaping 時的 Arabic LAM-ALEF 及類似情形)、Indic 系列合字 feature ('akhn' / 'pres' / 'blws' / 'psts')。呼叫方傳入 post-cmap 字形 ID 序列和 0-based 起始位置;完整命中時返回 True、OutGID = 替換合字字形、ConsumedCount = 消耗的分量總數(實際通常 ≥ 2)。未命中返回 False、OutGID = 0、ConsumedCount = 1,讓呼叫方步進一格繼續掃描。實現遵循 OpenType 慣例 —— LigatureSet 通常按"長度優先"排列,讓 prefix 重疊的字體(例如三分量 'ffi' 合字與二分量 'ff' 合字共存)拿到更長的匹配。沿用 v2.119.43/.44 helper 的防禦性契約:空 / 非 4 字節 tag、無 GSUB、feature 未公佈、StartIndex 越界、該位置無 LookupType 4 子表命中 全部返回安全 no-op (False / OutGID = 0 / ConsumedCount = 1)。LookupFlag mark-skipping、GDEF GlyphClassDef 集成、自動在 text emit 路徑應用合字、TTF 子集化器自動拉合字字形 都留待後續版本。

2026-05-22 Version 2.119.44

  • OpenType GSUB Multiple Substitution (LookupType 2):新方法 THotPDF.GetMultipleSubstituteGlyphs(InputGID, FeatureTag, var OutGIDs) 把單個輸入字形拆分為一串替換字形。典型使用者是 'ccmp' (Glyph Composition / Decomposition) feature,用於把預組合的帶音標拉丁字母拆成基礎字形 + 組合符號,配合下游的 mark positioning 使用。helper 走與 v2.119.43 GetSingleSubstituteGlyph 相同的 DFLT script / 預設 LangSys / FeatureList / LookupList 路徑,對 FeatureTag 關聯的每個 LookupType 2 子表應用 InputGID,第一個命中為準。OutGIDs 在入口被清空,呼叫方不需要預清。spec 允許 Sequence 長度為 0(Unicode-canonical 字形刪除),此情況返回 Result = True 且 Length(OutGIDs) = 0,呼叫方據此從文本流裡刪除該輸入字形。
  • OpenType GSUB Alternate Substitution (LookupType 3):兩個新方法讓風格特性的完整替代字形循環可被顯式訪問。THotPDF.GetAlternateGlyphCount(InputGID, FeatureTag) 返回字體為 InputGID 在 FeatureTag 下提供的替代字形數量;THotPDF.GetAlternateGlyph(InputGID, FeatureTag, AlternateIndex) 返回該 0-base 索引處的替代字形。典型使用者是 'aalt' (Access All Alternates)、'salt' (Stylistic Alternates)、'titl' (Titling Alternates) 和 'ss01' 到 'ss20' (Stylistic Sets 1-20),這些 feature 用 LookupType 3 而非 LookupType 1 實現時,v2.119.43 的 GetSingleSubstituteGlyph 會靜默跳過相應子表 —— 'aalt' 呼叫方之前只能看到 LookupType 1 的傳遞替換。這對方法讓呼叫方顯式遍歷裝飾字形循環(不同形態的 'a' / 'g' / '7')、Titling 大寫變體、Stylistic Set 替代。AlternateIndex 越界 / 負值返回 InputGID 原值讓呼叫方安全探測。
  • 兩個 helper 沿用 v2.119.43 的防禦性契約:無 GSUB 表的字體、非 4 字節 tag、字體 DFLT script 未公佈的 feature、無 LookupType 2 / 3 子表覆蓋的 GID 都返回安全 no-op(Multiple 返回 False + 空 OutGIDs;Alternate 返回 0 / InputGID)。feature 鏈路上遇到的 LookupType 1 / 4-8 子表靜默跳過。LookupFlag mark-filtering、GDEF GlyphClassDef 集成、Script / LangSys 選擇 API、自動 shaping pipeline 接入、TTF 子集化器自動拉所選 substitute 字形仍留待後續版本;呼叫方仍需要手動 mark 所選字形進字體子集。

2026-05-22 Version 2.119.43

  • OpenType GSUB stylistic-alternates 查詢:新方法 THotPDF.GetSingleSubstituteGlyph(InputGID, FeatureTag) 走字體的 GSUB ScriptList / FeatureList / LookupList 鏈路(DFLT script 預設 LangSys),應用 FeatureTag 關聯的每個 LookupType 1 (Single Substitution) 子表,返回替換後的字形 ID。最常用的 stylistic-alternates feature tag 包括 'salt' (Stylistic Alternates)、'ss01' 到 'ss20' (Stylistic Sets 1-20)、'aalt' (Access All Alternates)、'titl' (Titling Alternates)、'subs' / 'sups' (上標/下標)、'frac' (分數)、'ordn' (序數);任意 4 字節 OpenType feature tag 只要其 feature 鏈路含 LookupType 1 子表即可支援。Coverage Format 1(已排序字形數組,二分查找)和 Format 2(range records)均支援。Single Substitution Format 1(delta 增量)和 Format 2(替換字形數組)均實現。RegisterUnicodeTTF 現在與 cmap 一起緩存 GSUB 表偏移/長度,查詢時不需重新掃表目錄。無 GSUB 表的字體、傳入字體 DFLT script 不公佈的 4 字節 tag、GID 不在 lookup Coverage 內的情況都返回 InputGID 原值,讓 API 作為"盡力替換或透傳"安全呼叫。LookupType 2-8 子表在 feature 鏈路上遇到時靜默跳過 —— Multiple / Alternate / Ligature Substitution、Contextual 鏈路、自動 shaping pipeline 集成留待後續版本。

2026-05-22 Version 2.119.42

  • AcroForm /DR Resources 現在支援多個 Unicode 字體。v2.56.0 SetFormUnicodeFontDict 僅追蹤單個呼叫方提供的字體(作為 AcroForm /DA 預設字體),需要按欄位切換腳本(阿拉伯 + CJK + 拉丁混合表單)的場景之前只能手工拼 /DR /Font 字典。新方法 THotPDF.RegisterAcroFormFont(LogicalName, FontDict) 按任意邏輯名註冊附加 Unicode 字體,使其可在 per-field /DA 字串中透過 '/<name> 12 Tf' 引用,並在 AcroForm /DR /Font 字典中與 v2.56.0 預設字體一起發射。註冊順序保留確保 /DR 字節級可重現。與 SetFormUnicodeFontDict 預設字體或先前註冊的字體同名拋帶衝突名稱的異常。空 LogicalName / nil FontDict 也拋異常。SetFormUnicodeFontDict('', nil) 重置路徑同時清空附加字體註冊表,讓全新 Unicode 工作流程從已知乾淨狀態開始。PDF/A / PDF/X 全級別允許 —— 組合 Unicode 字體屬於結構性表單中繼資料,非交互腳本。

2026-05-22 Version 2.119.41

  • PDF 1.7 §14.8.4 Table 333 標準 structure type 枚舉:新增 THPDFStandardStructureType 枚舉覆蓋 ~40 個 spec 規定的結構 role,按 PDF role 分類分組(Grouping: Document / Part / Art / Sect / Div / BlockQuote / Caption / TOC / TOCI / Index / NonStruct / Private;Block-level: H / H1-H6 / P / L / LI / Lbl / LBody / Table / TR / TH / TD / THead / TBody / TFoot;Inline-level: Span / Quote / Note / Reference / BibEntry / Code / Link / Annot;Ruby + Warichu: Ruby / RB / RT / RP / Warichu / WT / WP;Illustration: Figure / Formula / Form)。兩個 unit-level helper 將枚舉轉換為 spec-精確的 PDF 名稱——StandardStructureTypeToName(T) 返回作為結構元素 /S 鍵的大小寫敏感名稱,IsStandardStructureType(Name) 測試任意 AnsiString 是否在標準集合內,便於呼叫方預檢自定義 role 名並按需透過 AddStructRoleMap 路由。新增 AddStructureElement 枚舉重載直接接受 THPDFStandardStructureType,消除字串重載的拼寫 / 大小寫敏感隱患(如 'Para' vs 'P'、'Lbody' vs 'LBody'),轉發到相同的底層實現路徑。既有 AnsiString 重載對使用自定義或 RoleMap 路由名稱的呼叫方保持字節級一致。

2026-05-22 Version 2.119.40

  • 結構元素屬性 setter 三件套:新增 3 個 helper 與 v2.88.0 /Alt + /ActualText、v2.95.0 /ID 一起補齊 structure element 級 PDF 文本字串屬性。THotPDF.SetStructureElementLanguage(Elem, Lang) 寫 PDF 1.7 §14.9.2 /Lang BCP-47 自然語言代碼,覆蓋該元素及其子孫的文件預設語言直到下一次 /Lang override —— 典型用法是引用其他語言的段落或多腳本混排區段。THotPDF.SetStructureElementExpansionText(Elem, ExpansionText) 寫 §14.9.5 /E 縮寫展開文本,屏幕閱讀器在朗讀時用展開內容代替原始縮寫(如 "NASA" 朗讀為 "National Aeronautics and Space Administration"),同時給內容提取工具使用。THotPDF.SetStructureElementTitle(Elem, Title) 寫 §14.7.5.2 /T 標題,區分同一 role 下多個 sibling 元素(Acrobat Tags 面板會在 role 名旁顯示 /T)。三個 setter 均簡單實現:空值 no-op、nil Elem 拋異常;屬性屬於 structural metadata,PDF/A 與 PDF/X 全部級別允許。

2026-05-22 Version 2.119.39

  • AcroForm form-field trigger 系列收口:新增 3 個 helper 與 v2.119.37 AttachFieldKeyStrokeAction 一起覆蓋 PDF 1.7 §12.7.5.3 Table 246 完整四個 trigger。THotPDF.AttachFieldFormatAction 裝 /AA /F(format 事件,欄位提交後顯示前格式化 — 典型用法是 AFNumber_Format / AFDate_FormatEx 貨幣 / 日期 / 千分位掩碼);THotPDF.AttachFieldValidateAction 裝 /AA /V(validate 事件,使用者提交新值後觸發 — 典型用法是 event.rc := false 範圍 / 正則校驗拒絕非法輸入);THotPDF.AttachFieldCalculateAction 裝 /AA /C(calculate 事件,依賴欄位變更時觸發,依賴集由 Catalog /AcroForm /CO 計算順序數組定義 — 典型用法是合計求和、稅額計算)。四個 wrapper 共享同一 FFormFields /T 查找、同一冪等 last-call-wins 替換、同一 PDF/A + PDF/X JavaScript 守衛。同一 /AA 字典上其他 trigger 鍵 (/E /X /D /U /Fo /Bl 註釋觸發器 + 三個 sibling form-field trigger) 保持不動。內部重構:AttachFieldKeyStrokeAction 現在委託給共享 _InstallFieldTriggerJSAction helper;v2.119.37 既有呼叫方看到的異常消息字節級一致。

2026-05-22 Version 2.119.38

  • RegisterUnicodeTTF 現在會從字體 cmap format 12 子表中捕獲 Supplementary Multilingual Plane(SMP,U+10000-U+10FFFF)的 codepoint→glyph 映射。之前版本因為 codepoint→glyph 查找表是 BMP-sized 數組而靜默丟棄 SMP 條目;v2.119.38 新增並行稀疏列表(FUnicodeCpToGidSMP)與 BMP 數組同步填充。新公開方法 GetUnicodeGlyphForCodepoint(Cp) 返回任意 U+10FFFF 以內 Unicode codepoint 的字形 ID(SMP 範圍走二分查找),無映射時返回 0(.notdef)。這是 capability 第一刀:producer 端 hex 編碼管線、/CIDToGIDMap 流、ToUnicode CMap 仍然 BMP-anchored,寫入 SMP 字符到 PDF 文本流仍需呼叫方自行發射 UTF-16BE surrogate pair。完整 surrogate-aware 文本流 emit 留待後續版本。僅 format 4 子表的字體會得到空 SMP 列表。

2026-05-22 Version 2.119.37

  • 新增 AcroForm 鍵盤 trigger helper:THotPDF.AttachFieldKeyStrokeAction(FieldName, JavaScriptBody) 按 /T 查找命名錶單欄位,掛 /AA /K JavaScript action,PDF 閱讀器在文本輸入時每次按鍵觸發執行;典型用途包括實時輸入校驗(數字 / 日期 / 正則)、輸入掩碼、其他欄位編輯觸發的計算欄位連動。冪等設計:重複呼叫替換 /K 入口,同一 /AA 字典上其他 trigger 鍵(/F format / /V validate / /C recalc / /Bl blur / /Fo focus 等)保持不動。PDF/A 全級別(ISO 19005-1 §6.6.1、-2/-3 §6.5.1)+ PDF/X 全級別(ISO 15930 prepress)禁 JavaScript action,guard 啟用時立即拋帶 spec 引用的異常。底層對應 PDF 1.7 §12.6.3 trigger event 字典 + §12.7.5.3 Table 246 form-field /K 鍵。

2026-05-22 Version 2.119.36

  • BeginTaggedContent 新增 4 個可選參數,對接 PDF 1.7 §14.8.4 Table 322 marked-content sequence properties:Lang(BCP-47 自然語言代碼)/ Alt(替代描述,非文本或裝飾性內容用,屏幕閱讀器消費)/ ActualText(實際文本,提供給文本提取 / 複製粘貼 / 屏幕閱讀器替換視覺字形序列 —— 合字、裝飾大寫、風格化字形等場景必備)/ ExpansionText(/E 鍵,縮寫展開文本)。4 個值與現有 MCID 一起發射到同一個 BDC inline properties dict;空值跳過對應 key,未傳任何 attribute 的舊 2 參數呼叫方與 v2.119.35 字節級一致。PDF literal string 轉義(圓括號 / 反斜槓)自動處理;含非 ASCII 內容(CJK ActualText、Indic Alt 等)呼叫方負責 pre-encode 為 UTF-16BE + U+FEFF BOM 字節並以 AnsiString 形式傳入。配套低層 page-stream API BeginMarkedContentMCIDProps 同時暴露,便於不走高層 StructElem 通路、直接控制 BDC 的呼叫方使用。

2026-05-22 Version 2.119.35

  • Arabic Extended-A 塊 Persian / Urdu 核心 9 字符子集接入 v2.85.0 producer-side 4-position shaper。AutoShapeArabic 啟用時,以下字符按與基礎 Arabic 塊相同的 joining-context 算法映射到 U+FB50-U+FBFF Arabic Presentation Forms-A 塊字形:PEH U+067E、TCHEH U+0686、JEH U+0698、KEHEH U+06A9、GAF U+06AF、FARSI YEH U+06CC(Persian 核心)+ TTEH U+0679、DDAL U+0688、RREH U+0691(Urdu retroflex 核心)。Dual-joining 字符提供完整 isolated / final / initial / medial 4 形態;right-joining 字符(JEH / DDAL / RREH)按 Arabic shaping 模型僅提供 isolated / final。Arabic Extended-A 其他字符(ALEF WASLA U+0671、NOON GHUNNA U+06BA、HEH 變體 U+06C0-U+06C3、完整 Arabic Supplement U+0750-U+077F)保持 pass-through,留待後續版本擴展。非 Persian / Urdu 阿拉伯文輸出與 v2.119.34 字節級一致。

2026-05-22 Version 2.119.34

  • PDF name 處理現在會在導入或複製 PDF 物件時解碼 ISO 32000-1 的 #XX 轉義序列。資源名、專色名、結構 role 名,以及 /PANTONE#20216#20CVC 這類 name object 會以預期字節值在 HotPDF 內部往返,不再因為複製時把 # 再次轉義而輸出成雙重轉義名稱。

2026-05-22 Version 2.119.33

  • PDF 日期處理更貼近 ISO 32000-1 date string 規則。文件資訊、XMP 派生日期和簽章時間戳現在使用呼叫方傳入的 TDateTime,不再靜默替換為當前系統時間;解析器也能接受標準的可選日期欄位和時區後綴,同時保持本地日期/時間欄位不被破壞。
  • PDF 導入過濾器處理新增顯式 ASCIIHexDecode、ASCII85Decode 與 RunLengthDecode 輔助函數,LZWDecode 預設 EarlyChange 也調整為 PDF 預設值 1。導入或複製使用舊式 PDF stream filter 的頁面時相容性更好。

2026-05-21 Version 2.119.32

  • 阿拉伯文 LAM-ALEF 強制合字摺疊落到 v2.85.0 producer-side shaper 內部。當 AutoShapeArabic 啟用時,任何 U+0644 LAM(raw 或四種 shaped 形態 FEDD-FEE0 之一)跟隨四種 ALEF 變體之一(MADDA U+0622、HAMZA-above U+0623、HAMZA-below U+0625、plain U+0627;raw 或 post-shape 形態)的序列,會被摺疊為 U+FEF5-U+FEFC 塊的單個合字字形。合字 connected 與 isolated 形態依據 LAM 是否已被 4-position walker shape 到 final (FEDE) 或 medial (FEE0) 形態來選擇。其他阿拉伯文強制合字(Allah U+FDFB、各裝飾性敬語合字)仍需完整 GSUB 引擎,不在 static-table shaping 模型範圍內。不含 LAM-ALEF 的文本和未啟用 AutoShapeArabic 的呼叫方與 v2.119.31 字節級一致。三個 AcroForm Unicode /AP 輔助函數(單行 / 多行 / comb 分格)透過共享 _ApplyArabicShaping 入口自動繼承本變更。

2026-05-21 Version 2.119.31

  • 新增 DevExpress ExpressPrinting System 導出適配器:dxHotPDFExportReportLinkToFile / dxHotPDFExportReportLinkToStream 接收任何 TBasedxReportLink(橋接 cxGrid / cxRichEdit / cxScheduler / cxPivotGrid 等可列印元件到 TdxComponentPrinter 的抽象鏈路家族),把每頁渲染輸送進 HotPDF 而非 DevExpress 自帶的 dxPSExportToPDF emitter。適配器鏡像 DevExpress 內部導出循環:RebuildReport → for 每頁 → PaintPage 到 TMetafileCanvas → ShowEnhancedMetafile 進 HotPDF。Options record 暴露 Title / Author / Subject / Keywords / PDFVersion / Compression / RenderDPI。與 FastReport / QuickReport / ReportBuilder 適配器相同的 metafile 橋限制:無 AcroForm 欄位、無大綱、無 PDF/A / PDF/X 一致性閘門。適配器位於 Lib/Addons/DevExpress/,不進入主 HotPDF*.dpk。

2026-05-20 Version 2.119.30

  • 新增 ReportBuilder 設備類:TppHotPDFDevice 派生自 TppGraphicsDevice,掛載到 ReportBuilder 標準 publisher → device 鏈路(賦值給 TppReport.PrinterDevice 或 TppPublisher.Device)。每個頁面渲染到一個臨時 TMetafileCanvas(在 BeforeRenderPage 建立、AfterRenderPage finalize),捕獲為 TMetafile 後透過 HotPDF EMF 導入(HPDFEmf.ShowEnhancedMetafile)輸出。屬性暴露 Title / Author / Subject / Keywords / PDFVersion / CompressionLevel / Compressed;SetOutputStream 把 PDF 字節路由到呼叫方提供的 TStream。與 FastReport / QuickReport 適配器相同的 metafile 橋限制:無 AcroForm 欄位、無大綱、無 PDF/A / PDF/X 一致性閘門。適配器位於 Lib/Addons/ReportBuilder/,不進入主 HotPDF*.dpk。

2026-05-20 Version 2.119.29

  • 新增 QuickReport 導出過濾器:TQRHotPDFExportFilter 派生自 TQRExportFilter,無需修改 QuickReport 核心即可插入常規 MyReport.ExportToFilter(MyFilterInstance) 工作流程。適配器收割 QuickReport 已經緩存在 QRPrinter.PageList 中的每頁 TMetafile,逐個透過 HotPDF 的 EMF 導入(HPDFEmf.ShowEnhancedMetafile)寫出。屬性暴露 Title / Author / Subject / Keywords / PDFVersion / CompressionLevel / Compressed;SetOutputStream 把 PDF 字節路由到呼叫方提供的 TStream 而非磁盤。與 FastReport 適配器相同的 metafile 橋限制:無 AcroForm 欄位、無大綱、無 PDF/A / PDF/X 一致性閘門。適配器位於 Lib/Addons/QuickReport/,不進入主 HotPDF*.dpk。

2026-05-20 Version 2.119.28

  • 新增 FastReport 4 / FastReport VCL 導出適配器:TfrxHotPDFExport 派生自 TfrxCustomExportFilter,無需修改 FastReport 核心即可插入常規 MyReport.Export(MyExportInstance) 工作流程。適配器把每個 prepared page 透過 HotPDF 的 EMF 導入路徑(FastReport TfrxPreviewPages.DrawPage → TMetafileCanvas → HotPDF.ShowEnhancedMetafile)渲染,因此 FastReport 標準佈局引擎產生的矢量 + 位圖頁面內容無需逐物件 emit 代碼即可保留。屬性暴露 Title / Author / Subject / Keywords / PDFVersion / CompressionLevel / RenderDPI 控制最終 PDF。限制:無 AcroForm 欄位、無大綱、無 PDF/A / PDF/X 一致性閘門(這些需要逐物件 emit 管道,未來版本規劃)。適配器位於 Lib/Addons/FastReport4/,不進入主 HotPDF*.dpk;使用者在自己工程中與 FastReport 對應包一起引用。

2026-05-20 Version 2.119.27

  • 新增端到端 PFX-based PDF 簽章:THotPDF.SignPDFWithPFX(InputPDFPath, OutputPDFPath, PFXFilePath, Password) 載入一個已包含 AddSignedSignatureField 佔位符的未簽章 PDF,解析 PFX / PKCS#12 文件,對 /ByteRange 覆蓋範圍構造完整的 CMS SignedData (RFC 5652),並一次性寫出已簽章 PDF。同時提供 TStream-based 重載用於內存工作流程。PDF /Contents 預留長度必須足夠容納 CMS DER 的 hex;預設 8192 字節即可覆蓋 1024 / 2048-bit RSA。僅支援 PBES2 + AES-256-CBC 的 PFX 文件(與 v2.119.26 PKCS#12 解析器的限制一致)。
  • 新增 HPDFCMS 單元:CMS SignedData 構造器。HPDFCMSBuildSignedData 組裝 ContentInfo → SignedData → SignerInfo,使用 id-data detached 內容、contentType + messageDigest + signingTime 簽章屬性(按 RFC 5652 §5.4 要求 DER 升序排序)、從 X.509 證書提取的 IssuerAndSerialNumber 簽章者標識、RSA + SHA-256 簽章算法,X.509 證書包裝在 [0] IMPLICIT certificates 內。同時暴露 HPDFCMSSHA256ByteRanges 用於流式兩段摘要、HPDFCMSBytesToHex 用於 /Contents 佔位符注入。封閉了從 HPDFASN1(v2.119.23)+ HPDFRSA(v2.119.24)+ HPDFCrypt 擴展(v2.119.25)+ HPDFPFX(v2.119.26)起步的庫內簽章棧。

2026-05-20 Version 2.119.26

  • 新增 HPDFPFX 單元:PKCS#12 / PFX 容器解析器。讀取 OpenSSL ≥ 3.0、Windows 11+ certutil 與 macOS Keychain Access 產生的 .pfx / .p12 文件,解密 PBES2(PBKDF2-HMAC-SHA-256 + AES-256-CBC)SafeBag 內容,提取 X.509 證書 DER 與 RSA 私鑰參數。返回一個 THPDFPFXKeyMaterial 記錄含 CertDER、Modulus、PublicExponent、PrivateExponent,下游 CMS / 簽章代碼可以直接消費。密碼錯誤時透過錯 AES key 之後的 PKCS#7 反填充失敗被識別。Legacy PBE-SHA1-3DES 文件會拋帶遷移提示的清晰錯誤(用 `-keypbe AES-256-CBC -certpbe AES-256-CBC` 重新導出)。

2026-05-20 Version 2.119.25

  • 新增密碼學原語:AES-256 反向密碼(AES256DecryptBlock + AES256CBCDecryptPKCS7 + AES256CBCDecryptNoPad,遵循 FIPS-197 §5.3,與既有的加密助手成對)、HMAC-SHA-256(RFC 2104)、PBKDF2-HMAC-SHA-256(RFC 8018 §5.2)。已透過 RFC 4231 HMAC 測試向量和標準 PBKDF2-SHA-256 參考輸出驗證。配合 v2.119.23 的 ASN.1 解碼器和 v2.119.24 的 RSA 原語,完成了現代(OpenSSL ≥ 3.0 / Windows 11+)PKCS#12 / PFX 文件的 PBES2-AES-256 SafeBag 解密路徑所需的全部密碼學基礎。

2026-05-20 Version 2.119.24

  • 新增 HPDFRSA 單元:多精度整數運算 + RSA 模冪 + PKCS#1 v1.5 EMSA 編碼。大小足以簽出真實世界使用的 2048 / 4096-bit RSA 密鑰。配合 v2.119.23 的 ASN.1 解碼器,完成了即將到來的庫內 PFX 簽章管道所需的密碼學原語。還沒有面向使用者的 API 呼叫它 —— 這是內部基礎設施,等待 PKCS#12 與 CMS 層。

2026-05-20 Version 2.119.23

  • 新增 HPDFASN1 單元:一個緊湊的 BER/DER 解碼器,覆蓋 HotPDF 讀取 PKCS#12 密鑰庫、X.509 證書、CMS/PKCS#7 SignedData 容器所需的 ASN.1 子集。暴露 THPDFASN1Node(解析後的 Tag-Length-Value 描述符)、THPDFASN1ParseNode / ParseAt、Content / ToInteger / ToBigInt / ToOID / ToString 訪問器,以及 FirstChild / NextSibling / Children 迭代器。顯式拒絕 BER 的不定長形式和高 tag-number(≥ 31)編碼,與 DER 嚴格子集保持一致。這是為後續版本中庫內 PFX 簽章管道準備的內部基礎設施——還沒有任何面向使用者的 API 依賴它。

2026-05-20 Version 2.119.22

  • 新增 PolyLine + Polygon 註釋擴展中繼資料重載:THPDFPage.AddPolylineAnnotation 與 AddPolygonAnnotation 增加兩個新重載,接收一組 THPDFCurrPoint 頂點 + 可選的 THPDFPolyExtras 記錄。Extras 暴露 ISO 32000-1 §12.5.6.9 全部可選條目——/IC 內部填色、/BE 雲形邊框(besSolid / besCloudy + /I 強度)、/IT 意圖(PolyLineDimension / PolyLineFlight / PolygonCloud / PolygonDimension)、PolyLine 的 /LE 線端樣式。用 HPDFDefaultPolyExtras() 拿零初始化的起點記錄。新重載校驗頂點數 ≥ 2,並按 /IT 取值動態 bump 文件版本(PDF 1.5 / 1.6 / 1.7)。原有的 interleaved-Single 數組重載繼續編譯保持不變。

2026-05-20 Version 2.119.21

  • 新增 Line 註釋擴展中繼資料:AddLineAnnotation 增加第三個重載,接收 THPDFLineExtras 記錄控制 PDF 1.6/1.7 §12.5.6.7 Table 175 全部可選條目——/IC 內部填色(實心箭頭/菱形/方塊)、/LL 引導線長度、/LLE 引導線延伸、/LLO 引導線偏移(PDF 1.7)、/Cap 標題標誌 + /CP 標題位置(/Inline 或 /Top,PDF 1.7)+ /CO 標題偏移、/IT 意圖(LineArrow / LineDimension)。用 HPDFDefaultLineExtras() 拿零初始化的記錄基礎上按需賦值。新重載按所需條目自動 bump 文件版本到 PDF 1.6(或 1.7 當 /LLO / /CP / /CO 被請求時)。原有兩個重載繼續發射字節級一致的輸出,新重載只會寫入呼叫方明確請求的條目。

2026-05-20 Version 2.119.20

  • 新增 baShow / baImportData 按鈕動作:THPDFButtonAction 增加 baShow(baHide 的鏡像,發射 /H false 重新顯示已隱藏的控制項)與 baImportData(/S /ImportData /F filespec,點擊後載入 FDF 表單資料,ISO 32000-1 §12.7.5.4)。baShow 在 PDF/A 與 PDF/X 下都允許;baImportData 在 PDF/A(ISO 19005-1 §6.6.1)和 PDF/X(ISO 15930 印刷預檢)下都拒絕。
  • 新增多欄位 Hide/Show 重載:THPDFPage.AddPushButtonWithHideAction(FieldName, Caption, Targets, Hide, Rectangle, Flags) 接收一組目標欄位名 + 一個顯式 Hide 布爾,單個按鈕可一次切換多個控制項的可見性。空 Targets 數組會拋異常。PDF/A 與 PDF/X 都允許該重載(僅涉及控制項可見性)。

2026-05-20 Version 2.119.19

  • 新增 SubmitForm /Flags 使用者可控:THPDFPage.AddPushButtonWithSubmitAction(FieldName, Caption, URL, Rectangle, SubmitFlags) 透過新的 THPDFSubmitFormFlags 集合類型暴露 ISO 32000-1 §12.7.5.2 Table 237 全部位標誌。呼叫方可以自由組合 sffExportFormatHTML / sffXFDF / sffSubmitPDF(提交格式)、sffGetMethod(HTTP GET 而非 POST)、sffIncludeAnnotations、sffSubmitCoordinates、sffCanonicalFormat、sffIncludeNoValueFields、sffIncludeAppendSaves、sffExclNonUserAnnots、sffEmbedForm 等位,替代舊 baSubmitURL 硬編碼的 /Flags 0(FDF + POST)。已有的 AddPushButtonWithAction(.., baSubmitURL, ..) 仍發射 /Flags 0 保字節級相容。PDF/A / PDF/X 守衛與 baSubmitURL 相同:PDF/A 允許,PDF/X 禁止。

2026-05-20 Version 2.119.18

  • 擴展按鈕動作類型:THPDFButtonAction 增加 baNamed 與 baHide。baNamed 發射 /S /Named /N <name> 動作(ISO 32000-1 §12.6.4.11),適用於四個標準導航命令 NextPage / PrevPage / FirstPage / LastPage(PDF/A 按 ISO 19005-1 §6.6.1 全部允許)以及 Acrobat 擴展命令 Print、SaveAs。baHide 發射 /S /Hide /T <field> /H true 動作(§12.6.4.10),點擊按鈕時隱藏指定的表單欄位。兩種動作類型在 PDF/A 與 PDF/X 下都允許;只有 baJavaScript / baResetForm / baSubmitURL 保留之前的合規守衛。

2026-05-20 Version 2.119.17

  • 新增命名目的地註冊表:THotPDF.RegisterNamedDestination(Name, PageIndex, FitMode, ...) 把一個符號化目的地寫入 Catalog /Names /Dests 名字樹(ISO 32000-1 §12.3.2.3)。GoTo / GoToR 動作和大綱 /Dest 條目此後可以按名字引用目的地,不用再寫死頁號,跨頁插入/刪除/調序時所有引用保持有效。新枚舉 THPDFDestinationFitMode 覆蓋 spec 全部 8 種 fit 模式(XYZ / Fit / FitH / FitV / FitR / FitB / FitBH / FitBV)。空 Name、越界 PageIndex、重複 Name 三類呼叫會拋異常;按需自動 bump 到 PDF 1.2。PDF/A / PDF/X 不 gate——導航輔助在所有 profile 都允許。

2026-05-20 Version 2.119.16

  • 新增 Line 註釋 /LE 線端樣式:THPDFPage.AddLineAnnotation 增加一個接受起點/終點線端樣式的重載。新枚舉 THPDFLineEndingStyle 暴露 ISO 32000-1 §12.5.6.7 Table 176 全集十個值:None / Square / Circle / Diamond / OpenArrow / ClosedArrow / Butt / ROpenArrow / RClosedArrow / Slash。Line 註釋現在可以在 Adobe Acrobat / Foxit 裡直接以箭頭、尺寸標記或指向性提示符的形式渲染,呼叫方不再需要在頁面上手畫箭頭。原四參數重載行為字節級保持不變。

2026-05-20 Version 2.119.15

  • 新增大綱(書籤)樣式支援:THPDFDocOutlineObject 增加 Color、Bold、Italic 三個屬性(ISO 32000-1 §12.3.3 Table 153 /C 與 /F)。大綱面板現在可以用彩色和粗體/斜體強調書籤,便於按章節分組、標註未完成或需注意的段落、以及匹配品牌樣式。Color 預設 clNone(不發射 /C 條目,字節級相容舊輸出);Bold、Italic 預設 false。在 AddChild 後再設置任一屬性會實時改寫大綱字典;把 Color 改回 clNone 或者把 Bold/Italic 都改回 false 會移除已經寫入的 /C / /F 條目。

2026-05-20 Version 2.119.14

  • 新增文件級命名 JavaScript 註冊表:THotPDF 增加 RegisterDocumentJavaScript(Name, Body) 方法。每個註冊項會被序列化到 Catalog /Names /JavaScript 名字樹(ISO 32000-1 §7.7.4.4 + §12.6.4.16)作為一個獨立的 /S /JavaScript /JS 字典。AcroForm 控制項動作和文件開啟動作可以透過閱讀器(Acrobat、Foxit)的 JavaScript 引擎按名字呼叫註冊好的函數。適用於讓多個表單控制項共享一組驗證、格式化或計算函數,不必在每個 /A 動作裡重複 JS 原始碼。該方法在任意 PDFACompliance 級別(ISO 19005-1 §6.6.1)和任意 PDFXCompliance 級別(ISO 15930 印刷預檢)下拋異常,同時拒絕空 Name / Body 以及重複 Name 註冊。

2026-05-20 Version 2.119.13

  • 新增頁面縮略圖支援:THPDFPage 增加 SetPageThumbnail(ImageIndex) / ClearPageThumbnail 兩個方法。PDF 閱讀器(Acrobat、Foxit、瀏覽器內 PDF 閱讀器)會用頁面字典的 /Thumb 條目(ISO 32000-1 §12.3.4)在導航面板裡顯示預先準備好的頁面縮略圖,省去閱讀器自身光柵化整頁內容的開銷——對圖文密集的歸檔文件尤其有用。該方法可直接複用透過 AddImage / AddImageFromFile 添加的任意圖像,呼叫方準備好降採樣的預覽位圖後一行就能掛上去;傳 -1 或呼叫 ClearPageThumbnail 可移除已掛載的縮略圖,越界的圖像索引會拋出含明確資訊的異常。

2026-05-20 Version 2.119.12

  • PDF/A 合規修復:當 PDFACompliance 在任意級別(PDF/A-1/2/3)啟用時,AddPushButtonWithAction 現在會對 baJavaScript 和 baResetForm 動作類型拋出異常。ISO 19005-1 §6.6.1 / ISO 19005-2 §6.5.1 / ISO 19005-3 §6.5.1 在所有 PDF/A 級別下禁用 JavaScript、ResetForm 和 ImportData 動作。baSubmitURL(SubmitForm)、baURI 和 baNone 在 PDF/A 下仍然允許——SubmitForm 在 §6.6.1 允許的動作列表中。之前 v2.119.5 守衛只覆蓋 Catalog /AA 和文件級 OpenAction 路徑,按鈕控制項可以攜帶被禁動作而未被攔截。
  • PDF/X 合規修復:當 PDFXCompliance 在任意級別啟用時,AddPushButtonWithAction 現在對 baJavaScript、baResetForm 和 baSubmitURL 動作類型拋出異常。ISO 15930 印刷預檢工作流程不允許交互式腳本、表單變更和向外部端點提交表單。

2026-05-20 Version 2.119.11

  • PDF/A 合規修復:PDF/A 註釋類型守衛補全。AddScreenAnnotation、Add3DAnnotation、AddRichMediaAnnotation 現在在任意 PDF/A 級別(PDF/A-1/2/3)啟用時拋出異常。ISO 19005-1 §6.5.2 / ISO 19005-2 §6.6.1 / ISO 19005-3 §6.6.1 在所有 PDF/A 級別下禁用 Screen、3D、RichMedia(多媒體 / Adobe Extension Level 3)註釋子類型。同時鏡像加 PDFXCompliance 守衛——ISO 15930 印刷預檢工作流程不支援多媒體子類型。
  • PDF/A-1 合規修復:當 PDFACompliance 設為 PDF/A-1 時,AddWatermarkAnnotation 和 AddRedactAnnotation 現在會拋出異常。Watermark(PDF 1.6)和 Redact(PDF 1.7)都是 PDF 1.4 之後引入的註釋子類型,不相容 PDF/A-1 的 PDF 1.4 基線(ISO 19005-1 §6.5.2)。PDF/A-2 和 PDF/A-3(PDF 1.7 基線)繼續允許這兩種註釋類型。

2026-05-20 Version 2.119.10

  • PDF/A 合規修復:當 PDFACompliance 設為 PDF/A-1 時,AddImageWithSMask 和 AddImageWithSMask32 現在會拋出異常。ISO 19005-1:2005 §6.4 禁止所有透明效果;圖像 /SMask 流激活軟掩膜透明度合成,違反此規定。使用者應將圖像預先合成到背景色再傳入 AddImage(),或改用 PDF/A-2 / PDF/A-3。PDF/A-2 和 PDF/A-3 繼續支援圖像軟掩膜透明度。

2026-05-20 Version 2.119.9

  • PDF/A 合規修復:當 PDFACompliance 設為 PDF/A-1 時,SetTransparencyGroup 和 SetTransparencyGroupICC 現在會拋出異常。ISO 19005-1:2005 §6.4 禁止所有透明效果;頁面級 /Group /S /Transparency 字典激活透明度合成模型,違反此規定。這兩個方法在 v2.32.0 引入時沒有加 PDF/A-1 守衛。PDF/A-2 和 PDF/A-3 支援透明度(ISO 19005-2/3 §6.3.8),繼續允許。

2026-05-20 Version 2.119.8

  • PDF/A 合規修復:當 PDFACompliance 激活且提供了自定義半調字典時(即 HTDefaultName = false),RegisterHalftoneState 現在會拋出異常。ISO 19005-1:2005 §6.2.9 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.3.7 規定 ExtGState /HT 只允許使用 /Default 名字字面量;自定義半調字典(Type 1、5、6、10、16)在所有 PDF/A 級別下均被禁止。傳入 HTDefaultName=True 以復位為預設半調在所有 PDF/A 級別下仍然允許。
  • PDF/A 合規修復:當 PDFACompliance 設為 PDF/A-1 且提供了自定義軟掩膜字典時(SMaskDict 參數非 nil),RegisterSoftMaskState 現在會拋出異常。ISO 19005-1:2005 §6.4 禁止所有透明效果;非 None 的 /SMask 值會激活軟掩膜透明度。傳入 SMaskNone=True 以復位軟掩膜仍然允許。PDF/A-2 和 PDF/A-3 繼續支援軟掩膜透明度。

2026-05-20 Version 2.119.7

  • PDF/A 合規修復:AddDocumentAttachment(透過 Catalog /Names /EmbeddedFiles 實現的文件級文件嵌入)在 PDF/A-1 或 PDF/A-3 模式下現在會拋出異常。ISO 19005-1:2005 §6.1.11 明確禁止 PDF/A-1 下在文件 Names 字典中出現 /EmbeddedFiles 鍵。對於 PDF/A-3,文件附件必須透過 AddPDFA3AssociatedFile() 註冊,以包含 ISO 19005-3:2012 Annex E 要求的 Catalog /AF 數組和 /AFRelationship 鍵。PDF/A-2 繼續允許文件級附件,但附件文件本身必須符合 PDF/A 規範。

2026-05-20 Version 2.119.6

  • PDF/A 合規修復:在 PDFACompliance 激活時使用 PDF 標準字體(Arial、Helvetica、Times New Roman、Courier New、Symbol、ZapfDingbats)且 StandardFontEmulation 開啟時,現在會拋出描述性異常。ISO 19005-1:2005 §6.3 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.3 要求所有字體必須嵌入;標準字體模擬路徑僅寫出不嵌入的字體名引用,違反 §6.3。使用者應將 StandardFontEmulation 設為 false,或使用 RegisterUnicodeTTF() 配合真實字體文件生成 PDF/A 文件。
  • PDF/A 合規修復:在 PDFACompliance 激活時,非標準字體現在總是強制嵌入,不受 FontEmbedding 屬性設置影響。FontEmbedding = false 的性能優化在 PDF/A 模式下被靜默覆蓋,以滿足 §6.3 的全量字體嵌入要求。

2026-05-20 Version 2.119.5

  • PDF/A 合規修復:當 PDFACompliance 激活時,JavaScript 動作及 Catalog 級 /AA(附加動作)字典現已被禁止。ISO 19005-1:2005 §6.6.1/§6.6.2 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.5.1/§6.6.2 禁止所有 JavaScript 動作類型,並禁止 Catalog 字典中出現 /AA 鍵。在 PDFACompliance 激活的情況下呼叫 SetActionScript 現在會拋出描述性異常。作為縱深防禦,EndDoc 中的 OpenAction JavaScript 與 Catalog /AA 輸出路徑也加入了守衛,在 PDFACompliance 激活時靜默跳過,確保即使透過內部路徑也不會寫入不合規的鍵。

2026-05-20 Version 2.119.4

  • PDF/A 合規修復:當 PDFACompliance 激活時,AcroForm /NeedAppearances 現在被強制為 false,不受 AutoFormAppearances 設置影響。ISO 19005-1:2005 §6.9 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.4 要求該鍵必須缺失或為 false。此前如果在 PDFACompliance 激活的同時禁用 AutoFormAppearances,/NeedAppearances 會被設為 true,導致生成的文件不合規。

2026-05-20 Version 2.119.3

  • PDF/A 合規修復:當 PDFACompliance 激活時,嵌入的 CIDFont 子集現在在其 FontDescriptor 上包含 /CIDSet 流。ISO 19005-1:2005 §6.3.5 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.2.11 要求 CIDFont 子集攜帶 /CIDSet 位流,指示嵌入字體程序中存在哪些 CID 值。HotPDF 使用 Identity-H 編碼(CID 等於 Unicode 碼點),因此 CIDSet 直接由文件中使用的碼點集合構建。位流經 FlateDecode 壓縮後作為 indirect 流物件掛到現有的 FontDescriptor 上。本次修復了所有 PDF/A 級別中此前未檢測到的缺口(早期合規審計錯誤地標註此項已就位)。

2026-05-20 Version 2.119.2

  • PDF/A-2 與 PDF/A-3 合規修復:當 PDFACompliance 設為 PDF/A-2 或 PDF/A-3 級別時,非 Link / 非 Popup 註釋類型(TextNotes、FreeText、Line、Square、Circle、Stamp、FileAttachment)現在自動發射 /AP /N 外觀字典。ISO 19005-2:2011 §6.3.3 及 ISO 19005-3:2012 §6.3.3 要求每個此類註釋必須至少有一個外觀字典(/AP /N Form XObject)。當前發射一個最小空 Form XObject 滿足結構要求;大多數 PDF 檢視器對標準註釋類型無論如何都使用內置渲染,不依賴 /AP 流內容。Link 和 Popup 註釋按標準明確豁免,不受影響。此要求不適用於 PDF/A-1(ISO 19005-1 §6.5.3 僅在 /AP 存在時約束其格式,不強制要求存在)。

2026-05-20 Version 2.119.1

  • PDF/A 合規修復:所有非 Widget 註釋類型(文本註釋、印章、線條、矩形/橢圓、超鏈接、GoTo 跳轉鏈接、GoToR 跨文件鏈接、URI 鏈接)在 PDFACompliance 激活時現在自動設置 /F Print 標誌位(bit 3 = 1,值 4)。ISO 19005-1:2005 §6.5.3 及 ISO 19005-2:2011 / ISO 19005-3:2012 §6.3.2 要求每個註釋字典必須包含 /F 鍵且 Print 位為 1。此前只有 Widget 註釋(表單欄位)設置了該標誌,其餘所有註釋類型均未設置,導致生成文件不合規。
  • PDF/A-1 合規修復:可選內容組(圖層)在 PDFACompliance 設為 PDF/A-1 級別('A' 或 'B')時現在被阻止。ISO 19005-1:2005 §6.1.13 禁止在 Catalog 字典中出現 /OCProperties 鍵;在 PDF/A-1 模式下呼叫 RegisterOptionalContentGroup 現在會拋出說明性異常,提示呼叫方在需要可選內容時改用 PDF/A-2 或更高版本。EndDoc 的 /OCProperties 寫出也加了相應 gate 作為防禦性保障。

2026-05-20 Version 2.119.0

  • XAdES-in-PDF 容器支援按 ETSI EN 319 142-2 V1.2.0 §6.2(B/C/D 系列收口 3 之 3)。把呼叫方提供的 XAdES 簽章 XML 字節嵌入 PDF EmbeddedFile,把 Filespec 註冊到 Catalog /AF 數組,按呼叫方指定的 PDF 2.0 枚舉設 /AFRelationship。producer 端只做 wrapper——實際 XAdES 簽章構造(XML-DSig + ETSI EN 319 132-1 QualifyingProperties + RFC 3161 時間戳嵌入 xades:UnsignedSignatureProperties)是呼叫方 XML 密碼學庫職責(Apache Santuario、.NET SignedXml、libxmlsec、帶 XAdES 擴展的 Saxon 等)。
  • 新方法 `THotPDF.AddXAdESAssociatedFile(FileName, XMLBytes, Description, MimeType, Relationship)`。預設值:MimeType `'application/xml'`(常用 ASiC-E archive 用 `'application/vnd.etsi.asic-e+zip'`)、Relationship `'Source'`(XAdES 簽章 XML 是文件主內容)。返回 indirect Filespec dict 供呼叫方掛額外中繼資料或自定義 Catalog 條目交叉引用。
  • 獨立於 PDF/A:不像 v2.108 `AddPDFA3AssociatedFile`(需 PDFACompliance='3*'),本 helper 無 PDF/A gate——XAdES-in-PDF 按 PAdES Part 2 V1.2.0 §6 是獨立 profile 族。
  • `_EscapePDFNameBytes` 關鍵 bug 修復(PDF 1.7 ISO 32000-1 §7.3.5 + Table 2)。之前 escape 只轉換 [0x21..0x7E] 之外的字節 + `#`;PDF delimiter(`/ ( ) < > [ ] { } %`)spec 要求在 name 裡 `#XX` 轉義但被原樣輸出。`/Subtype /application/xml` 類名因此被嚴格閱讀器解析為兩個獨立 name token(/application 後跟 /xml),破壞 EmbeddedFile /Subtype 識別。v2.119 按 spec 轉義 10 個 delimiter;不含 delimiter 的 name(HotPDF 絕大多數 emit)保持字節相同。PDF/A-3 Annex E(v2.108)MIME 類型現在正確 emit(`/application#2Fxml` 替代損壞的 `/application/xml`)。
  • PAdES B/C/D 系列 3 commit 收口:v2.117(Extended profiles E-BES / E-EPES / E-LTV 按 Part 2 §5)+ v2.118(Seed Values 按 ISO 32000-1 §12.7.5.5 + Part 2 §4.2.6)+ v2.119(XAdES-in-PDF + delimiter escape 修復按 Part 2 §6.2)。加 v2.109 - v2.116,HotPDF 現在覆蓋完整 PAdES producer 範圍含 baseline profiles、extended profiles、document timestamp、DSS 驗證資訊、ESIC extensions、Seed Value 簽章約束、XAdES-in-PDF 容器。
  • Win32 + Win64 clean compile;v2.108 - v2.118 baseline 全部重 compile 透過。新 smoke smoke_pades_xades 走 2 個正向路徑(XAdES 簽章 XML 作 /AFRelationship /Source + ASiC-E archive 作 /Data)加 4 個拒絕路徑(空 FileName / 空 XMLBytes / 空 MimeType / 無效 Relationship)。Python verifier 走兩 Filespec 端到端含 `/Subtype /application#2Fxml` 和 `/Subtype /application#2Fvnd.etsi.asic-e+zip` 轉義形式。v2.108 PDF/A-3 / PAdES / PDF/X smokes 全部重跑透過。

2026-05-20 Version 2.118.0

  • PAdES Seed Values 按 ISO 32000-1 §12.7.5.5 + ETSI EN 319 142-1 V1.2.1 §5.5 + ETSI EN 319 142-2 V1.2.0 §4.2.6(B/C/D 系列第 2 刀,共 3 刀)。掛在簽章欄位上的 Seed Value (SV) 字典約束消費閱讀器的簽章工具在該特定欄位可選什麼——哪個 handler、哪個 SubFilter、哪個摘要算法、是否強制撤銷資訊、最低 PDF 版本。
  • 新 `THotPDF.AttachPAdESSeedValue(FieldName, SubFilters, DigestMethods, ForceSubFilter, ForceDigestMethod, AddRevInfo, MinPDFVersion, ForceMinPDFVersion)` 方法。在 AcroForm 欄位列表查命名簽章欄位(必須已由 AddPAdESSignatureField 或 AddDocumentTimestampSignature 建立)並掛帶呼叫方約束的 /SV 子字典。
  • Seed Value emit 條目(按 Table 234):
    • `/Type /SV`
    • `/SubFilter` Name 數組 — 例如 [/ETSI.CAdES.detached]
    • `/DigestMethod` Name 數組 — 例如 [/SHA256 /SHA384 /SHA512]
    • `/AddRevInfo` boolean — 簽章工具必須在 CMS 裡含 OCSP/CRL
    • `/V` 數字 — 最低 PDF 版本(例如 1.7)
    • `/Ff` 整數 bit 標誌(Table 235)— 每個 Force* 參數置對應 bit 讓簽章工具**必須**遵守約束(bit 2 = force SubFilter, bit 3 = force V, bit 6 = force AddRevInfo, bit 7 = force DigestMethod)
  • 規範合規護欄:PAdES Part 2 V1.2.0 §4.2.6 禁止迫使簽章工具違反 PAdES profile 的 seed value(例如指定 PKCS#1 SubFilter)。HotPDF producer 端不強制——呼叫方負責只傳 spec 允許的值(SubFilter 用 `'adbe.pkcs7.detached'` 或 `'ETSI.CAdES.detached'`,DigestMethod 用 SHA-256+)。helper 文件註釋明確該約束。
  • Win32 + Win64 clean compile;v2.108 - v2.117 baseline 全部重 compile 透過。新 smoke smoke_pades_seedvalue 建立 PAdES-B-T 欄位然後掛完整 Seed Value 約束集(SubFilter 限定 ETSI.CAdES.detached、DigestMethod 限定 SHA256/384/512、AddRevInfo true、MinPDFVersion 1.7、全部 force bit 置位)。Python verifier 走 /SV 子字典斷言每個條目形狀;還走"未知 FieldName"拒絕路徑。
  • 系列第 3 刀(v2.119):XAdES-in-PDF 容器按 Part 2 V1.2.0 §6 收口 B/C/D 系列。producer 端是個薄 wrapper 複用 HotPDF 既有 EmbeddedFile / Catalog /AF 管道(v2.108 PDF/A-3 helper)加上 PAdES Part 2 V1.2.0 §6.2.2 對 XAdES 簽章 XML payload 期望的 /AFRelationship 語義。

2026-05-20 Version 2.117.0

  • PAdES 擴展 profile 按 ETSI EN 319 142-2 V1.2.0 §5(B/C/D 系列第 1 刀,共 3 刀)。Part 1 baseline (V1.2.1 §6 B-B / B-T / B-LT / B-LTA) 定義固定 CMS 屬性組合;Part 2 §5 定義並行的"extended" profile 族(E-BES / E-EPES / E-LTV)含更高 CMS-屬性可選性,供 baseline 之外需要靈活性的呼叫方(如多策略企業部署、PAdES 信封內的自定義 CAdES profile)。
  • `AddPAdESSignatureField` Profile 參數現在接受三個額外值,與四個 baseline 名並列:
    • `'E-BES'` — 基礎 + 透過 signing-certificate ESS 屬性的明確簽章證書綁定(PAdES 信封內的 CAdES-BES 等價)。預設 16 KB /Contents 預算。
    • `'E-EPES'` — E-BES + 顯式 signature-policy-identifier signed attribute。預設 16 KB;呼叫方通常傳 18-20 KB 以容納 policy OID + qualifier 字節。
    • `'E-LTV'` — 長期驗證含 CMS-屬性靈活的證書鏈 + 撤銷資訊嵌入。自動 upsize 到 20 KB 最低(鏡像 B-LT)。
  • baseline 和 extended profile 的 producer 端 wire format 完全相同——七個全用 SubFilter `ETSI.CAdES.detached`、相同 /ByteRange + /Contents 哨兵模式、相同 DSS + ESIC 管道(v2.110 / v2.116)。級別差異完全在呼叫方密碼學庫產生的 CMS signed-attribute 組合裡。Profile 字串隻影響校驗診斷和預設 /Contents 預算;HotPDF 不在 PDF 字典本身裡編碼 CAdES-BES / CAdES-EPES / CAdES-T 之分。
  • PAdES helper 文件註釋更新表面 Part 2 V1.2.0 §4.2 暴露的呼叫方責任:SHA-256+ 哈希選擇(SHA-1 phase-out)、每個 Sig 欄位一個 SignerInfo、不用 RFC 5755 attribute certificate、以及 E-EPES 要求包含 signature-policy-identifier signed attribute。caller-domain 項仍在 producer 範圍外,但合約現在在 API 表面明確。
  • Win32 + Win64 clean compile;v2.108 - v2.116 baseline 全部重 compile 透過。smoke_pades_signature 擴展加 3 個新欄位(SigEBES / SigEEPES / SigELTV)走每個新 Profile 值的 auto-upsize / 顯式預算 / 預設預算路徑。Python verifier 擴展走全部 7 個欄位並斷言 Catalog ESIC extension(v2.116 carry-forward)。
  • B/C/D 系列後續:v2.118 加 Seed Values (PDF 1.7 §12.7.5.5 + ETSI EN 319 142-1 V1.2.1 §5.5 + Part 2 V1.2.0 §4.2.6) 讓 PAdES 簽章欄位聲明 handler / SubFilter / digest-method 約束,消費閱讀器簽章時必須遵守。第 3 刀:v2.119 加 XAdES-in-PDF 容器支援按 Part 2 V1.2.0 §6(XAdES 簽章 XML 作 EmbeddedFile 嵌入 + Catalog /AF 關聯)。

2026-05-20 Version 2.116.0

  • PAdES 按最新 ETSI 規範 + eIDAS 實施決定刷新:ETSI EN 319 142-1 V1.2.1 (2024-01, 已發佈) + ETSI EN 319 142-2 V1.2.0 (2025-03, draft 附加 profile + 擴展 profile 族 + XAdES-in-PDF) + ETSI TS 119 142-3 V1.1.1 (2016-12, PAdES-DTS 文件時間戳) + EU 2015/1506 (公共部門承認)。HotPDF v2.109 - v2.111 baseline(B-B / B-T / B-LT / B-LTA + standalone timestamp)繼續滿足同樣的 wire format;本刀關閉新 spec 暴露的兩個 producer 端缺口。
  • DSS 字典 `/Type "DSS"` 項 (EN 319 142-1 V1.2.1 §5.4.2.2)。/Type 項 optional 但存在時必須為 /DSS name。HotPDF 現在主動 emit 讓先看 /Type 再走字典其餘項的嚴格驗證器立即識別。
  • ESIC extensions 字典 (TS 119 142-3 §5.1, recommended)。新 `EnsurePAdESESICExtensions` 方法在任意 PAdES helper 呼叫時冪等寫入 Catalog:`<< /Extensions << /ESIC << /BaseVersion /1.7 /ExtensionLevel 1 >> >> >>`。驗證器(Adobe Acrobat pre-flight / EU DSS / callas pdfaPilot)憑此項識別文件為 PAdES 容器並聲明 PDF 1.7 + ESIC level 1 extensions。
  • `EnsurePAdESDSS` round-trip 路徑關鍵 bug 修復。v2.116 之前 helper 每次呼叫透過 `Catalog.GetIndexedItem(FindValue('DSS'))` 重解析 DSS 字典,返回 Catalog 存儲的 indirect-link THPDFLink 而不是真實 DSS dict。THPDFDictionaryObject 強轉把指針類型搞錯,導致第一次之後每個 `AddPAdESDSSCertificate` / `AddPAdESDSSOCSP` / `AddPAdESDSSCRL` / `AddPAdESDSSVRI` 呼叫都靜默跳過數組 push(數組引用變 nil,FindValue 返回 -1,if-Idx 小於 0 early-exit 觸發)。v2.116 修復用 `FPAdESDSSDict` 欄位緩存真實 Dict 引用讓後續呼叫直接命中緩存。smoke_pades_dss 現在正確 emit 2 證書 + 1 OCSP + 1 CRL + 1 VRI 條目(之前只有第一個證書進 /DSS,/OCSPs 和 /CRLs 都是空數組)。
  • PAdES helper 文件註釋更新覆蓋 Part 2 V1.2.0 §4.2 暴露的呼叫方責任:SHA-1 phase-out(呼叫方 CMS 應選 SHA-256+)、每個 PDF 簽章只能一個 SignerInfo(Part 2 §4.2.1 h / Part 1 §4.1 a)、RFC 5755 attribute certificate 應避用(Part 2 §4.2 g)、PAdES-DTS 文件不應帶 VRI 字典(TS 119 142-3 §6.3 h — DSS 足夠)。HotPDF producer 端 wire format 透過結構本身已經滿足這四條約束;註釋表面告訴呼叫方他們的 CMS 構造庫要做什麼。
  • Win32 + Win64 clean compile;smoke_pades_signature / smoke_pades_dss / smoke_pades_doctimestamp 加 verifier 全部透過。Verifier 擴展:smoke_pades_dss 現在斷言 `/Type /DSS` + Catalog `/Extensions /ESIC /BaseVersion /1.7 /ExtensionLevel 1`;smoke_pades_doctimestamp 斷言同 ESIC extension 並接受 page-Y-flipped 零面積 /Rect(`[0 H 0 H]` H = 頁高)。Audit doc + TechnicalNotes 刷新引用 EN 319 142-1 V1.2.1 / Part 2 V1.2.0 / TS 119 142-3 / EU 2015/1506。

2026-05-20 Version 2.115.0

  • PDF/X (ISO 15930) producer 系列收口 (4/4):禁用 annot + action 類型按 ISO 15930-1:2001 / ISO 15930-3:2002 / ISO 15930-7:2010 + ISO 32000-1 §12.5.6 / §12.6.4。PDF/X 印刷工作流程只消費可見印刷內容——多媒體 annot、嵌入文件、交互 action 都不參與印刷,故消費 pre-flight 工具(Adobe Acrobat / Enfocus PitStop / callas pdfaPilot)會拒絕含這些功能的文件。
  • 禁用 annot 類型(任意 PDFXCompliance ∈ {X-1a, X-3, X-4} 下拒絕):
    • FileAttachment — 印刷壓機不消費嵌入文件
    • Sound — 多媒體無印刷場景
    • Movie — 同上多媒體理由
    每個入口(AddFileAttachmentAnnotation / AddSoundAnnotation / AddMovieAnnotation)在任意 PDF/X profile 呼叫時拋帶 spec 章節診斷 + PDFXCompliance 值。
  • 禁用 action 類型(任意 PDFXCompliance 下拒絕):Launch / JavaScript / SubmitForm / ImportData / Movie / Sound / ResetForm。印刷工作流程不能觸發任何外部程序——PDF 只被壓機 / RIP 消費,從不執行。AddLaunchLink 在任意 PDF/X profile 下拋(其餘 action HotPDF 無公開 API emit 路徑自然滿足)。
  • PDF/X 系列功能完整:v2.112(opt-in + XMP 身份 + Trapped /Name)+ v2.113(OutputIntent + ICC GTS_PDFX)+ v2.114(透明度 gate + PageBox 強制)+ v2.115(禁 annot/action)。三個業界主流 profile(X-1a:2001 / X-3:2002 / X-4:2010)全覆蓋。呼叫方仍需自行編排頁級印前內容(正確 CMYK 目標、v2.84 TTF subsetter 字體嵌入、TrimBox 與設計匹配、有出血時配 BleedBox)但結構性合規 gate 全部到位。
  • Win32 + Win64 clean compile;v2.108 - v2.114 baseline 全部重 compile 透過。smoke_pdfx_optin 擴展 4 個新拒絕測試(TestRejectFileAttachmentAnnot / TestRejectSoundAnnot / TestRejectMovieAnnot / TestRejectLaunchAction)——每個在 PDF/X 三 profile 之一下 emit 被禁類型確認乾淨拒絕。smoke 現共 11 個場景:3 個正向 emit + 8 個拒絕路徑。
  • 本組完成兩個並行多版本系列:PAdES(ETSI EN 319 142, v2.109 - v2.111, 3 commit, B-B / B-T / B-LT / B-LTA + standalone timestamp 全支援)和 PDF/X(ISO 15930, v2.112 - v2.115, 4 commit, X-1a / X-3 / X-4 producer 端結構合規 gate 全部到位)。

2026-05-20 Version 2.114.0

  • PDF/X (ISO 15930) producer 系列第三刀 (3/4):透明度 gate + PageBox 強制按 ISO 15930-1:2001 / ISO 15930-3:2002 / ISO 15930-7:2010 + ISO 32000-1 §14.11.2。本刀覆蓋兩個獨立的頁級限制;gate 拆分鏡像 v2.103 PDF/A-1 透明 + 頁特性模式。
  • 透明度 gate (§7.5):RegisterExtGState 在 PDFXCompliance 為 'X-1a' 或 'X-3' 時拒絕 fill alpha < 1 (/ca)、stroke alpha < 1 (/CA)、BlendMode 非 {Normal, Compatible}。PDF/X-1a (ISO 15930-1:2001) 和 PDF/X-3 (ISO 15930-3:2002) 強制 PDF 1.3 base,先於 PDF 1.4 透明度。PDF/X-4 (ISO 15930-7:2010, PDF 1.6 base) 明確允許透明度,故 X-4 下 gate 不開火。診斷解釋成因 + 建議透明度需求時切到 X-4。
  • PageBox 強制 (§14.11.2):新方法 `EnsurePDFXPageBoxes` 走每頁要求至少 /TrimBox 或 /ArtBox 其一。MediaBox 單獨不夠——它代表設計畫布,而非印刷廠裁切所需的成品尺寸。缺 PageBox 拋帶 1-base 頁號、spec 章節號、推薦 SetTrimBox 呼叫簽章的診斷。EndDoc PDFXCompliance gate 在 OutputIntent 檢查之後自動呼叫 EnsurePDFXPageBoxes。
  • 典型呼叫方模式:設置 PDFXCompliance + Trapped + AddPDFXOutputIntent 後,文件每頁必須包含 `CurrentPage.SetTrimBox(Left, Bottom, Right, Top)` 匹配成品尺寸(例如 US Letter 用 0 0 612 792,A4 用 0 0 595 842)。BleedBox 推薦但不強制。
  • Win32 + Win64 clean compile;v2.108 - v2.113 baseline 全部重 compile 透過。smoke_pdfx_optin 擴展:3 個 profile emit 中每個加 SetTrimBox 正向呼叫 + 缺 TrimBox 拒絕路徑 + X-1a 透明度拒絕路徑(RegisterExtGState ca=0.5 拋)+ X-4 透明度允許正向路徑(同呼叫透過 + ExtGState 註冊)。Python verifier 走每個 /Type /Page 字典斷言至少含 /TrimBox 或 /ArtBox 其一。
  • 剩餘 PDF/X slice:v2.115 收口禁用 action 類型(JavaScript / Launch / SubmitForm / ImportData / Movie / Sound)+ 禁用 annot 類型(Movie / Sound / FileAttachment / Screen)+ AcroForm /XFA 拒絕。印刷工作流程不需要這些功能;消費 pre-flight 工具把它們視作硬失敗。

2026-05-19 Version 2.113.0

  • PDF/X (ISO 15930) producer 系列第二刀 (2/4):OutputIntent + ICC profile 強制按 ISO 15930-1:2001 §6.2.2 / ISO 15930-3:2002 §6.2.2 / ISO 15930-7:2010 §6.2 + ISO 32000-1 §14.11.5。每個 PDF/X profile 強制至少一個 /Type /OutputIntent /S /GTS_PDFX 條目命名目標印刷條件 + 提供 /DestOutputProfile ICC profile 流——印刷廠用這個 ICC 把 PDF 與印刷機 / 紙 / 墨水組合做顏色匹配。
  • 新 helper `AddPDFXOutputIntent(OutputConditionIdentifier, Info, ICCProfileStream, NumComponents, AlternateCS)` 鏡像 v2.102 PDF/A wrapper 但 emit GTS_PDFX 子類型而非 GTS_PDFA1。校驗 ICCProfileStream 非 nil + OutputConditionIdentifier 非空;內調 RegisterICCProfile 嵌入 profile(自動按 NumComponents 配 /Alternate 備用色彩空間)+ AddOutputIntent 構建 OutputIntent 字典。
  • EndDoc 強制:PDFXCompliance 啟用時, EnsurePDFXOutputIntent 走 OutputIntents 數組要求至少一個含 /S /GTS_PDFX + /DestOutputProfile 的條目。缺失拋帶註冊標識符建議(FOGRA39 用於單張膠印, CGATS TR 001 SWOP 用於北美捲筒, Japan Color 2001 Coated 用於亞洲市場)。
  • 典型 PDF/X 工作流程:1) `Doc.PDFXCompliance := 'X-4'`,2) `Doc.Trapped := 'False'`,3) 把 CMYK ICC profile 流(FOGRA39 / SWOP 等)裝入 TStream,4) `Doc.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)', '', ICCStream, 4, 'DeviceCMYK')`,5) 設計內容,6) Doc.EndDoc emit OutputIntent 掛在 Catalog /OutputIntents 數組;消費 pre-flight 工具(Adobe Acrobat / Enfocus PitStop / callas pdfaPilot)校驗色彩管理配對。
  • Win32 + Win64 clean compile;v2.108 / v2.109 / v2.110 / v2.111 / v2.112 baseline 全部重 compile 透過。smoke_pdfx_optin(原 v2.112)擴展:在 3 個 profile emit 中各註冊一個假 ICC profile + AddPDFXOutputIntent(X-1a → FOGRA39 CMYK,X-3 → SWOP CMYK,X-4 → sRGB RGB)+ 加缺 OutputIntent 拒絕路徑。Python verifier 擴展走每個字典確認 /Type /OutputIntent /S /GTS_PDFX + /DestOutputProfile 條目 emit 出來。
  • 剩餘 PDF/X slice:v2.114 加透明度 gate(X-1a / X-3 拒絕 ExtGState fill/stroke alpha < 1 + BM 非 Normal;X-4 允許透明)+ PageBox 強制(每頁需 TrimBox 或 ArtBox 按 §14.11.2);v2.115 收口禁用 action / annot / XFA gate(Movie / Sound / FileAttachment / Screen / JavaScript / Launch / SubmitForm / ImportData / XFA 都拒絕因為印刷工作流程不需要)。

2026-05-19 Version 2.112.0

  • 啟動 PDF/X (ISO 15930) 印刷預檢 producer 系列。PDF/X 是把"press-ready"PDF 寄送商業印刷廠的 ISO 標準族;profile X-1a(嚴格 CMYK + 專色)、X-3(ICC 色彩管理)、X-4(PDF 1.6 透明度 + ICCN)三者業界主流。v2.112 是第一刀 (1/4):opt-in 屬性 + 身份中繼資料。完整審計 + 4 版本路線圖歸檔在 .superpowers/specs/2026-05-19-pdfx-compliance-audit.md。
  • 新 `PDFXCompliance: AnsiString` 屬性在 THotPDF 上接受 `''`(禁用,預設)、`'X-1a'`(ISO 15930-1:2001)、`'X-3'`(ISO 15930-3:2002)、`'X-4'`(ISO 15930-7:2010)。設置非空值自動啟用 HotPDF 能為該 profile 結構層滿足的所有 producer 端要求。
  • 新 `Trapped: AnsiString` 屬性(PDFXCompliance 啟用時強制)接受 `'True'` / `'False'` / `'Unknown'`。PDF/X 全族 spec 強制此 DocInfo 項,讓印刷廠知道 PDF 是否已 trap 或需印刷廠在印前處理 trap。按 ISO 32000-1 §14.11.6.1 emit 為 PDF /Name(不是字串);例如 `<< /Trapped /False >>`。
  • XMP 中繼資料識別:packet 現在 advertise `xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/"` + `<pdfx:GTS_PDFXVersion>` 設為 spec 精確字串(`PDF/X-1:2001`、`PDF/X-3:2002`、`PDF/X-4`)+(X-1a + X-4)`<pdfx:GTS_PDFXConformance>` 設為完整 profile 名(`PDF/X-1a:2001` 或 `PDF/X-4:2010`)。Adobe Acrobat pre-flight / Enfocus PitStop / callas pdfaPilot 識別文件為 PDF/X 候選。
  • EndDoc 校驗:拒絕未知 profile 值、拒絕空 / 未識別 Trapped 值、要求 Title、自動 bump PDF 版本到 profile 強制最低(X-1a/X-3 → PDF 1.3,X-4 → PDF 1.6)。加密 + PDFXCompliance 硬衝突——呼叫 EnableEncrypt(或 `ActivateProtection := True`)拋帶清晰診斷的異常說明 PDF/X 工作流程必須能不帶密碼處理地審查每個物件。
  • 呼叫方仍需自行編排 OutputIntent + ICC profile + TrimBox/ArtBox + 有效印前色彩空間 + 正確字體嵌入(X-1a/X-3 避免透明度)才能完整 PDF/X 合規。v2.113 - v2.115 續刀關閉這些缺口:v2.113 加 `AddPDFXOutputIntent`(強制 /GTS_PDFX 意圖),v2.114 加透明度 gate + PageBox 強制,v2.115 收口禁用 action/annot/XFA。
  • Win32 + Win64 clean compile;v2.108 / v2.109 / v2.110 / v2.111 baseline 全部重 compile 透過。新 smoke smoke_pdfx_optin emit 三個 PDF(每 profile 一個)並驗證 XMP 命名空間 + GTS_PDFXVersion + GTS_PDFXConformance + DocInfo /Trapped /Name + 無效 profile / 空 Trapped / 未識別 Trapped / 加密衝突拒絕路徑。
  • PAdES 系列注:v2.109 / v2.110 / v2.111 覆蓋 B-B / B-T / B-LT / B-LTA + standalone timestamp 用例。原本計劃的 v2.112(standalone ETSI.RFC3161 timestamp-only PDF)實際上是隱含的——v2.111 的 `AddDocumentTimestampSignature` 在沒有內層簽章的新文件上呼叫就是 timestamp-only PDF——故 PAdES 系列視為 3 commit 實質收口,v2.112 重新分配給 PDF/X。ETSI EN 319 142-1 baseline profile 都已支援。

2026-05-19 Version 2.111.0

  • PAdES producer 系列第三刀 (3/4):PAdES-B-LTA 文件時間戳簽章支援,按 ISO 32000-1 §12.8.5 + ETSI EN 319 142-1 §5.7。文件時間戳是在長期驗證簽章完成**之後**疊加的第二個簽章;它覆蓋整個 LT 狀態文件(原簽章 + DSS),證明 LT 材料在權威時間存在。這是歐盟監管下超過原 CA 證書生命週期歸檔保存所需的最高級 profile。
  • 新 `THPDFPage.AddDocumentTimestampSignature(FieldName, ContentsBytes)` helper。與普通 PAdES 簽章不同,文件時間戳:
    • SubFilter 是 `/ETSI.RFC3161`(RFC 3161 TimeStampToken,不是 CAdES)。
    • Widget 矩形零面積(時間戳無可見外觀——純加密中繼資料)。
    • 無 /Reason / /Location / /ContactName(這些資訊在 TST signed-attrs 裡,不在 sig dict)。
    • 預設 /Contents 字節預算 16 KB(呼叫方可傳更小,1 KB 地板;含證書鏈的完整 RFC 3161 TST 通常 4-8 KB)。
  • Producer 範圍止於 wire format:helper 建立 /Type /Sig 佔位字典含時間戳專用 SubFilter + /ByteRange + /Contents 哨兵供 PreparePDFForSigning + InsertSignatureHex 後續修補。呼叫方從可信時間戳權威 (TSA, 例如 DigiCert / GlobalSign / FreeTSA HTTP POST) 獲取真實 RFC 3161 TST 字節並注入。典型 PAdES-B-LTA 歸檔工作流程疊加:1) emit PAdES-B-LT 基礎簽章 (v2.109),2) 填充 Catalog /DSS 含證書鏈 + OCSP/CRL (v2.110),3) 增量更新保存,4) 在 LT 狀態字節上加文件時間戳欄位 (v2.111),5) 按字節範圍向 TSA 請求 TST,6) 注入 TST 字節。
  • Win32 + Win64 clean compile;v2.108 / v2.109 / v2.110 baseline 全部重 compile 透過。新 smoke smoke_pades_doctimestamp 透過新 helper emit PAdES-B-LT 'SigInner' 欄位 + 'DocTS' 文件時間戳欄位。Python verifier 斷言內層簽章 /SubFilter /ETSI.CAdES.detached、時間戳 widget /Rect 零面積、時間戳 /V 字典含 /SubFilter /ETSI.RFC3161 且無 /Reason / /Location / /ContactName、/Contents 是 16 KB 佔位(32768 hex 字符)。
  • 剩餘 PAdES slice:v2.112(可選)加獨立 ETSI.RFC3161 timestamp-only PDF(無 CAdES 內層簽章——純時間戳文件容器)。

2026-05-19 Version 2.110.0

  • PAdES producer 系列第二刀 (2/4):Document Security Store (DSS) 字典支援,按 ISO 32000-2 §12.8.4.3 + ETSI EN 319 142-1 §5.6。PAdES-B-LT(和 B-LTA)要求驗證資訊——證書鏈、OCSP 響應、CRL——嵌入 PDF 本身,讓簽章在原簽章時間之後多年仍可驗證,無需再訪問外部 PKI 伺服器。
  • THotPDF 上的新 helper:
    • `EnsurePAdESDSS` — 懶建立 Catalog /DSS indirect dict 含其 /Certs、/OCSPs、/CRLs 數組和空 /VRI 子字典;後續呼叫返回既有字典。
    • `AddPAdESDSSCertificate(CertDERBytes)` — 把 DER 編碼 X.509 證書作為 indirect 流附加到 /DSS /Certs;返回 indirect 流物件供 VRI 引用。
    • `AddPAdESDSSOCSP(OCSPDERBytes)` — 同上, OCSP BasicOCSPResponse 加到 /DSS /OCSPs。
    • `AddPAdESDSSCRL(CRLDERBytes)` — 同上, Certificate Revocation List 加到 /DSS /CRLs。
    • `AddPAdESDSSVRI(SigContentsHexSHA1, Certs, OCSPs, CRLs)` — 建立按簽章的 VRI 條目,鍵是簽章 /Contents 字節的 UPPERCASE hex SHA-1 digest (spec 強制形式);每條目含 /Cert / /OCSP / /CRL 數組引用上面建立的 indirect 流。
  • Producer 範圍止於 wire format。呼叫方仍需計算最終簽章 /Contents 的 SHA-1 並從 PKI 工具鏈提供 DER 編碼證書 / OCSP 響應 / CRL。典型工作流程:先構造 PAdES-B-T 基礎簽章 (v2.109),再向 DSS 加 certs / OCSPs / CRLs 支援長期驗證,再附 VRI 條目將驗證資訊綁到具體簽章。
  • Win32 + Win64 clean compile;v2.108 + v2.109 baseline 重 compile 透過。新 smoke smoke_pades_dss 建立 PAdES-B-LT 簽章欄位,向 DSS 加 2 個證書 + 1 個 OCSP + 1 個 CRL,並加一個帶測試 hex digest 的 VRI 條目。Python verifier 走 DSS 字典結構:Catalog /DSS ref、/Certs / /OCSPs / /CRLs 數組數量、VRI 鍵匹配、VRI 條目的 cert/OCSP/CRL ref 匹配頂層 DSS 數組。
  • 剩餘 PAdES slice:v2.111 實現 PAdES-B-LTA 文件時間戳簽章(第二個 Sig 欄位,SubFilter ETSI.RFC3161,覆蓋整個 LT 文件);v2.112 (可選) 加 timestamp-only PDF。

2026-05-19 Version 2.109.0

  • 啟動 PAdES (ETSI EN 319 142) 數字簽章 producer 工作。v2.109 在既有 ISO 32000-1 §12.8 簽章基礎設施(v2 AddSignedSignatureField helper)之上加高層 wrapper,硬編碼 PAdES 要求的 SubFilter 並校驗合規 profile。完整審計 + 4 版本路線圖歸檔在 .superpowers/specs/2026-05-19-pades-compliance-audit.md。
  • 新 `THPDFPage.AddPAdESSignatureField(FieldName, Rect, Profile, Reason, Location, ContactName, ContentsBytes, Flags)` helper。Profile 選擇 ETSI EN 319 142-1 baseline 級別:'B-B'(基本 CAdES,無時間戳)、'B-T'(帶 RFC 3161 可信時間戳,歐盟法律最低要求)、'B-LT'(帶 DSS 驗證資訊,支援長期驗證)、'B-LTA'(帶文件時間戳簽章,歸檔級)。四者都使用 SubFilter 'ETSI.CAdES.detached';profile 參數影響診斷和預設 /Contents 字節預算。其他 profile 字串拋帶 ETSI 枚舉診斷。
  • 自動 upsize Contents 預算:PAdES-B-B + B-T 預設 16 KB(呼叫方可傳更少,繼承 v2.108 的 64 字節地板)。PAdES-B-LT 自動 upsize 到 20 KB 最小(CAdES + 證書鏈 + OCSP/CRL 資料)。PAdES-B-LTA 自動 upsize 到 24 KB 最小(B-LT + 文件時間戳)。呼叫方提供更大值直接透過;helper 只抬地板。
  • Producer 範圍:wrapper 建立 /Type /Sig 佔位字典含 /SubFilter /ETSI.CAdES.detached、/Reason / /Location / /ContactName / /M(簽章日期),以及 /ByteRange + /Contents 哨兵供 PreparePDFForSigning + InsertSignatureHex 後續修補。實際 CMS / CAdES 字節、RFC 3161 時間戳獲取、OCSP/CRL 收集、DSS 字典構造仍是呼叫方責任——需要 PDF producer 範圍之外的外部加密庫(OpenSSL、Bouncy Castle、Windows CAPI 等)。
  • Win32 + Win64 clean compile。新 smoke smoke_pades_signature emit 四個 PAdES 簽章欄位(B-B / B-T / B-LT / B-LTA)並確認無效 profile 值拋。Python verifier 斷言 AcroForm /SigFlags 3、每個 widget 有 /FT /Sig + /V indirect ref 指向 /Type /Sig 字典含 /SubFilter /ETSI.CAdES.detached、/Contents 佔位 hex 長度匹配預期(自動 upsize 後)字節預算。
  • 剩餘 PAdES 路線圖:v2.110 加 Catalog /DSS(Document Security Store)字典 builder 供 PAdES-B-LT 驗證資訊(證書鏈 + OCSP/CRL);v2.111 加獨立文件時間戳簽章欄位供 PAdES-B-LTA 歸檔;v2.112(可選)加 ETSI.RFC3161 timestamp-only PDF。

2026-05-19 Version 2.108.0

  • PDF/A-2 + PDF/A-3 producer 系列收口 (4/4):ISO 19005-3 Annex E Associated Files。新高層 helper AddPDFA3AssociatedFile(FileName, MimeType, Description, Relationship, FileBytes) 把任意文件(XML 發票、源 spreadsheet、JSON 中繼資料等)附到 PDF/A-3 hybrid 容器並註冊到 Catalog /AF 數組,帶 §E.4 /AFRelationship 語義。
  • Hybrid 容器工作流程:典型用例是 ZUGFeRD 風格的 PDF/A-3 發票——人類可讀的發票渲染存在 PDF 頁流,機器可讀的 XML 源作為 Associated File 一起帶。/AFRelationship 告訴消費者附件如何與可見內容關聯:'Source'(原始源資料)、'Data'(PDF 可視化的原始資料)、'Alternative'(替代表示)、'Supplement'(補充材料)、'Unspecified'(其他)。
  • Spec gating:AddPDFA3AssociatedFile 在非 PDF/A-3 PDFACompliance 值下拋(Annex E 是 part-3 專有),診斷建議 PDF/A-2 用 AddFileAttachmentAnnotation,並提示 PDF/A-1 §6.1.11 完全禁止附件。空 FileName 或 MimeType 拋;無效 Relationship 值拋附 spec §E.4 枚舉。
  • Emission 結構:indirect EmbeddedFile 流帶 /Type /EmbeddedFile + /Subtype <MIME> + /Params <</Size n>> + 文件字節。Indirect Filespec 字典帶 /Type /Filespec + /F + /UF(都 = FileName)+ 可選 /Desc + /EF <</F ref /UF ref>> + /AFRelationship(Annex E key)。Catalog /AF 數組首次附件時 lazy 建立,後續呼叫追加。返回的 Filespec 字典讓呼叫方需要時加額外可選鍵(如 /CI 校驗和資訊)。
  • Win32 + Win64 clean compile。新 smoke smoke_pdfa3_associated 構造 PDF/A-3B hybrid 發票,附真實 XML 發票為 /AFRelationship Source,行使三個拒絕路徑:PDF/A-1 拒絕、PDF/A-2 拒絕、無效 /AFRelationship 拒絕。Python verifier 斷言 Filespec / EmbeddedFile 字典圖(Type / F / UF / Desc / AFRelationship / EF F UF / EmbeddedFile Type / Subtype #2F 轉義 / Params Size)。
  • PDF/A-2 + PDF/A-3 producer 面現已完全審計閉合(v2.105 wrapper opt-in + XMP、v2.106 禁用 annot/action、v2.107 §6.1.13 implementation limits、v2.108 Annex E Associated Files)。配合 PDF/A-1 (v2.101-104) 和 PDF/UA-1 (v2.94-v2.100) 已達 strict conformance,HotPDF 現在端到端覆蓋 PDF/A-1/2/3 + PDF/UA-1 歸檔/無障礙 producer 完整矩陣。

2026-05-19 Version 2.107.0

  • PDF/A-2 + PDF/A-3 producer 系列第三刀 (3/4):ISO 19005-2 §6.1.13 + ISO 19005-3 §6.1.13 implementation limits 強制。PDF/A-1 §6.1.13 顯著寬鬆(無硬字串長度限制),所以新 gate 只在 PDFACompliance 為 PDF/A-2 或更高('2*' / '3*')時觸發。
  • 新公開方法 EnsurePDFAImplementationLimits 校驗文件呼叫方控制的值是否符合 spec 硬限制:Doc.Title / Author / Subject / Keywords / Lang 字串 ≤ 32767 字節;每個 page MediaBox 維度落在 [3..14400] 單位內。EndDoc 在 PDFACompliance 為 PDF/A-2/3 時自動呼叫;呼叫方也可在 build 中段直接調獲取早期診斷。
  • 審計報告記錄自動滿足的限制:integer 範圍(-2³¹..2³¹-1)、real 範圍(±3.403×10³⁸,近零 ≥1.175×10⁻³⁸)、name 長度 ≤127 字節、indirect 物件數 ≤8388607、q/Q 嵌套 ≤28、DeviceN colorant ≤32、CID ≤65535。HotPDF emission 路徑不會超過這些限制因為它們綁定到 HotPDF 控制的 producer 資料結構。校驗器聚焦呼叫方提供的字串 + 頁面邊界,因為只有這些是現實世界呼叫方能突破的限制。
  • XFA 表單(§6.4.2):HotPDF 不 emit AcroForm /XFA 或 Catalog /NeedsRendering。跨 PDF/A-1/2/3 自動滿足——審計報告標記,防止未來 producer 擴展重新引入。
  • .notdef glyph(PDF/A-2 §6.2.11.8):spec 禁止 text-showing 算子引用 .notdef。呼叫方使用註冊的 Unicode TTF 字體(v2.74-v2.86 路徑)時 HotPDF 字體處理自動避免——producer 把每個 codepoint 映射到真實 glyph,或拒絕註冊。原始文本 emit 路徑是呼叫方責任;審計報告記錄。
  • XMP namespace(§6.6.2):spec 禁 XMP packet 頭部的 bytes / encoding 屬性。BuildXMPPacket emit 最小頭部(id="W5M0MpCehiHzreSzNTczkc9d")不帶任一屬性——所有 PDF/A part 自動滿足。
  • Win32 + Win64 clean compile。新 smoke smoke_pdfa2_limits 行使三個路徑:PDF/A-2 限制內透過;PDF/A-1 含 32768 字節 Title 也透過(無 §6.1.13 gate);PDF/A-2 含 32768 字節 Title 被 spec 節診斷拒絕。所有 PDF/A-2/3 baseline 重 compile 透過。
  • 剩餘 PDF/A-2/3 producer slice:v2.108 實現 PDF/A-3 Annex E Associated Files(PDF/A-3 專有 hybrid 容器特性:Catalog /AF 文件 specification 數組 + /AFRelationship key + EmbeddedFile /Params /CheckSum + /ModDate)。

2026-05-19 Version 2.106.0

  • PDF/A-2 + PDF/A-3 producer 系列第二刀 (2/4):覆蓋 PDF/A-2 §6.3.1 + §6.5.1(與 PDF/A-3 §6.3.1 + §6.5.1 一致)。v2.104 PDF/A-1 禁用 annotation + action gate 本來就在任何 PDFACompliance 非空時觸發,所以 PDF/A-2/3 下繼續工作。v2.106 確認此行為、升級診斷消息引用所有 PDF/A part 共享 spec 節、並文件化 PDF/A-2 新增禁用類型中 HotPDF 自然滿足的部分(無公開 emit 路徑)。
  • 禁用 actions 表:PDF/A-1 禁 6 個(Launch / Sound / Movie / ResetForm / ImportData / JavaScript)。PDF/A-2/3 擴展到 13 個,新增 Hide / SetOCGState / Rendition / Trans / GoTo3DView + 已棄用的 set-state / no-op。AddLaunchLink 繼續拋;HotPDF 無公開 emit 其他 12 個的入口,自動滿足。
  • 禁用 annotation 類型表:PDF/A-1 禁 FileAttachment / Sound / Movie。PDF/A-2/3 解除 FileAttachment 禁(v2.105 已放寬)但新增 3D / Screen 禁。AddSoundAnnotation + AddMovieAnnotation 跨所有 PDF/A part 繼續拋;HotPDF 無 3D / Screen emit 路徑,自動滿足。
  • 診斷消息升級:v2.104 三個 gate(AddSoundAnnotation、AddMovieAnnotation、AddLaunchLink)的異常文本現在引用三個相關 spec 節(如 "PDF/A-1 §6.5.2 / PDF/A-2 §6.3.1 / PDF/A-3 §6.3.1"),開發者直接看到統一禁用範圍。AddLaunchLink 消息額外列出 PDF/A-2/3 擴展禁用 action 集。
  • Win32 + Win64 clean compile。新 smoke smoke_pdfa2_annot_action 在所有 6 個 PDF/A-2/3 level(2B、2U、2A、3B、3U、3A)下行使三個 gate;每次呼叫斷言帶 §6.3.1 / §6.5.1 診斷的預期異常。既有 PDF/A-1 baseline(smoke_pdfa1_compliance / smoke_pdfa1_forbidden / smoke_pdfa1_annot_action)和 v2.105 smoke_pdfa2_compliance 重 compile 透過。
  • 剩餘 PDF/A-2/3 producer slice:v2.107 強制 ISO 19005-2 §6.1.13 implementation limits(integer / real / string / name 字節範圍、q/Q 嵌套、DeviceN 顏色數、CID、page 邊界)+ §6.4.2 XFA + §6.2.11 Type 3 / .notdef 嚴格;v2.108 實現 PDF/A-3 Annex E Associated Files(任意類型嵌入的 hybrid 容器 PDF)。

2026-05-19 Version 2.105.0

  • 啟動 PDF/A-2 (ISO 19005-2:2011) + PDF/A-3 (ISO 19005-3:2012) producer 合規 4 版本系列。審計 + 路線圖歸檔在 .superpowers/specs/2026-05-19-pdfa2-pdfa3-compliance-audit.md。v2.105 落地 wrapper 層 opt-in、XMP pdfaid namespace 擴展、PDF 版本自動 bump 至 1.7、以及對 v2.101-104 PDF/A-1 嚴格 gate 中 PDF/A-2/3 spec 明確允許的有選擇性放寬。
  • PDFACompliance 屬性在 PDF/A-1 的 '' / 'A' / 'B' 基礎上新接受六個值:'2A' / '2B' / '2U'(PDF/A-2 A/B/U 級)和 '3A' / '3B' / '3U'(PDF/A-3 A/B/U 級)。Level U 是 PDF/A-2 引入的新等級"僅 Unicode 保留"(視覺 + Unicode 可提取文本,不要求 Tagged PDF)。
  • BuildXMPPacket 擴展:<pdfaid:part> 元素現在反映解析的 part 號(1 / 2 / 3),<pdfaid:conformance> 反映解析的級別字母(A / B / U)。veraPDF 等驗證器按這對值識別文件的 PDF/A part。按 ISO 19005-2 §6.6.4 + ISO 19005-3 §6.6.4 Table 8。
  • 自動 bump:PDFACompliance '2*' / '3*' 自動 bump 文件版本到 PDF 1.7,因為 PDF/A-2/3 都基於 ISO 32000-1 (PDF 1.7)。PDF/A-1 保持錨定 PDF 1.4。
  • v2.103 透明度 gate 放寬:RegisterExtGState 僅在 PDFACompliance 為 PDF/A-1 strict('A' 或 'B')時對透明 alpha / 非 Normal blend mode 拋異常。PDF/A-2/3 §6.4 明確允許透明度(帶 OutputIntent 必填 + 完整 PDF 1.4 命名 blend mode 等獨立要求),'2*' / '3*' 讓呼叫透過。
  • v2.104 FileAttachment gate 放寬:AddFileAttachmentAnnotation 現在僅在 PDF/A-1 strict 下拋。PDF/A-2 §6.3.1 僅禁 3D / Sound / Screen / Movie 註釋類型;FileAttachment 被允許且是 PDF/A-3 Annex E Associated Files hybrid 工作流程的基礎。剩餘 v2.104 gate(Sound、Movie 註釋;Launch 操作)按共享 §6.3.1 + §6.5.1 禁用規則對所有 PDF/A part 仍然觸發。
  • 新 THotPDF 方法 PDFAPart / PDFAConformanceLevel / IsPDFA1Strict / IsPDFA2OrLater 讓分支判斷 ergonomic。既有 v2.101-104 PDF/A gate 現在使用這些 helper,代碼更清晰,錯誤資訊建議合適時切換到 PDF/A-2/3。
  • Win32 + Win64 clean compile;v2.101-104 baseline(smoke_pdfa1_compliance / smoke_pdfa1_forbidden / smoke_pdfa1_annot_action)全部重 compile 透過。新 smoke smoke_pdfa2_compliance emit 四個 PDF(Levels 2B / 2U / 2A / 3U),行使 v2.103 透明度放寬、v2.104 FileAttachment 放寬,加兩個驗證路徑(無效 '4Q' level 拒絕、PDF/A-1 透明度 gate 仍然觸發)。Python verifier 斷言 XMP pdfaid:part + conformance 匹配每個 level,Level 2A 額外有 Tagged-PDF 繼承。
  • 剩餘 PDF/A-2/3 producer slice:v2.106 把禁用 action 集從 6 個擴展到 13 個(新增 Hide / SetOCGState / Rendition / Trans / GoTo3DView + deprecated set-state / no-op),並調整 annot 類型禁用(加 3D / Screen,去 FileAttachment);v2.107 強制 ISO 19005-2 §6.1.13 implementation limits + XFA gate;v2.108 實現 PDF/A-3 Annex E Associated Files(hybrid container PDF)。

2026-05-19 Version 2.104.0

  • PDF/A-1 producer 系列收口(4/4 閉環):閉合 §6.5.2 禁用 annotation 類型(FileAttachment、Sound、Movie)與 §6.6.1 Launch action 子類型。v2.104 落地後,2026-05-19 PDF/A-1 審計報告中所有 17 個 producer-side 缺口全部閉合:四大重頭(§5/§6.7.11 標識、§6.1.3 加密禁、§6.2.2 OutputIntent、§6.4 透明度)+ 其他 forbidden-feature gate。
  • §6.5.2 禁用 annotation 類型:AddFileAttachmentAnnotation、AddSoundAnnotation、AddMovieAnnotation 在 PDFACompliance 啟用時拋帶清晰 spec 節診斷。按 spec "FileAttachment、Sound、Movie 類型不被允許",避免歸檔文件依賴外部內容或包含多媒體。
  • §6.6.1 Launch action:AddLaunchLink 在 PDFACompliance 啟用時拋 §6.6.1 診斷帶 launch 目標。按 spec "Launch、Sound、Movie、ResetForm、ImportData、JavaScript actions 不被允許"。剩餘五個禁用 action 類型(Sound/Movie/ResetForm/ImportData/JavaScript)HotPDF 無 emit 它們的公開入口,自動滿足無需顯式 gate。
  • PDFUACompliance + PDFACompliance 組合現在跨四個 PDF/A slice 完全正確工作。兩個 opt-in 疊加:Level A 繼承 PDFUACompliance 自動開啟 Tagged PDF;兩個 wrapper 各自應用 §-specific guard(PDF/UA 的 Suspects/Tabs/Lang;PDF/A 的 Encrypt/Transparency/Annot/Action)互不干擾。
  • 審計閉環總結:HotPDF 能在 producer 端結構性滿足的所有 PDF/A-1 §6 文件格式要求全部閉合。剩餘的呼叫方責任(§6.1.5 Info-XMP 等價、§6.2.3.3 顏色空間 ↔ OutputIntent 匹配、§6.3 字體細節其中 v2.74-v2.86 PDF/UA 工作已經處理大部分)與 PDF/UA-1 呼叫方責任對齊。
  • Win32 + Win64 clean compile;v2.103 smoke_pdfa1_forbidden 重 compile 透過。新 smoke smoke_pdfa1_annot_action 在 PDFACompliance 下行使四個 gated 路徑(AddFileAttachmentAnnotation、AddSoundAnnotation、AddMovieAnnotation、AddLaunchLink)並斷言每次呼叫都拋 §6.5.2 或 §6.6.1 診斷。
  • PDF/A-1 producer 面現已完全審計閉合。未來 PDF/A-2(ISO 19005-2:2011 基於 PDF 1.7,允許透明度 + layers)與 PDF/A-3(ISO 19005-3:2012,允許 hybrid 工作流程嵌入文件)擴展是後續可能的候選,待呼叫方需求觸發。

2026-05-19 Version 2.103.0

  • PDF/A-1 producer 系列第三刀 (3/4):閉合 §6.4 Transparency (CRITICAL 缺口 #15) + §6.2.8 ExtGState /TR transfer function (#14)。兩個 §6 缺口對應的既有 HotPDF producer 路徑自動滿足無需代碼改動:§6.1.10 LZW filter (HotPDF writer 路徑只 emit FlateDecode) 和 §6.2.4 image /Interpolate (HotPDF 從不 emit /Interpolate)。審計報告裡同步標記為 automatic。
  • §6.4 透明度禁非 1.0 alpha 和非 Normal/Compatible 混合模式。RegisterExtGState 在 PDFACompliance 啟用時 gate:fill alpha < 1 拋 (PDF/A-1 要求 /ca = 1.0);stroke alpha < 1 拋 (/CA = 1.0);BM 非 `Normal` 或 `Compatible` 拋。三種診斷都指明 spec 節和具體違規值。預設 ExtGState(無 alpha keys、無 BM)和顯式合法值(1.0 alphas、Normal / Compatible BM)一律放行。
  • §6.2.8 ExtGState 禁 /TR 傳輸函數鍵(已 deprecated;PDF/A-1 只允許 /TR2 值 = /Default,而且儘量避免使用)。RegisterTransferFunctionState 現在 PDFACompliance 啟用時拋帶清晰診斷。需要 PDF/X 工作流程傳輸函數的呼叫方仍可在非 PDFACompliance 模式下用。
  • §6.1.10 LZW + §6.2.4 Interpolate:已在審計報告裡記為 HotPDF 既有 producer 路徑自動滿足(FlateDecode-only writer、不 emit /Interpolate)。無代碼改動;註釋提示未來呼叫方不要重新引入。
  • Win32 + Win64 clean compile;v2.102 smoke_pdfa1_compliance 重 compile 透過。新 smoke smoke_pdfa1_forbidden 行使所有三個 gated 路徑(ca<1、CA<1、BM=Multiply、/TR 註冊)+ 驗證允許的路徑(ca=1.0、CA=1.0、BM=Normal/Compatible、無 alpha)仍正常透過。無 verifier — smoke 本身用 try/except 斷言每個 gated 呼叫都拋。
  • 剩餘 PDF/A-1 producer slice:v2.104 閉合 §6.5.2 禁用註釋類型(FileAttachment、Sound、Movie)+ §6.5.3 annot /F /AP 規則 + §6.6.1 禁用 action 類型(Launch、Sound、Movie、ResetForm、ImportData、JavaScript)+ §6.9 Form 欄位 /A /AA + /NeedAppearances。v2.104 落地後 PDF/A-1 producer 面完全審計閉合。

2026-05-19 Version 2.102.0

  • PDF/A-1 (ISO 19005-1:2005) producer 系列第二刀 (2/4):閉合 §6.2.2 OutputIntent + ICC profile 缺口。新增高層 helper `AddPDFAOutputIntent(OutputConditionIdentifier, Info, ICCProfileStream, NumComponents, AlternateCS)` 把 v2.51 RegisterICCProfile + AddOutputIntent('GTS_PDFA1', ...) 兩步合併為一次呼叫。PDF/A-1 嚴格要求 `/Type /OutputIntent /S /GTS_PDFA1` 條目帶有效 `/DestOutputProfile` ICC 流——沒它符合標準的文件無法跨平臺準確再現顏色。
  • EndDoc PDFACompliance gate 新增 `EnsurePDFAOutputIntent` 檢查:遍歷已註冊 OutputIntent 列表,找到至少一個 `/S /GTS_PDFA1` 條目帶 `/DestOutputProfile`。缺失則拋清晰診斷指明 spec 節並指向 AddPDFAOutputIntent。按 §6.2.2 + Annex A。
  • 典型歸檔工作流程:傳 sRGB IEC61966-2.1 ICC profile 用於屏幕 PDF/A、FOGRA39 / GRACoL 用於印刷、或對應已註冊的 CMYK profile 用於印前。NumComponents 必須 1 (Gray)、3 (RGB / Lab) 或 4 (CMYK) 按 PDF 1.7 8.6.5.5 Table 66;helper 轉發校驗給 RegisterICCProfile。
  • Helper 校驗:空 OutputConditionIdentifier 拋 (§6.2.2 要求 identifier);nil ICCProfileStream 拋 (DestOutputProfile 強制)。無返回值——OutputIntent 自動註冊到 FOutputIntents 並透過既有 Catalog /OutputIntents 序列化路徑發出。
  • Win32 + Win64 clean compile;v2.101 smoke_pdfa1_compliance 更新呼叫 AddPDFAOutputIntent(帶 192 字節 fake ICC 佔位;真實呼叫方應傳完整 ICC binary)。第 4 個驗證案例斷言 PDFACompliance + 缺 OutputIntent 拋 §6.2.2 診斷。Python verifier 擴展檢查 Catalog /OutputIntents 數組,遍歷條目找 `/S /GTS_PDFA1` + `/DestOutputProfile` indirect ref。
  • 剩餘 PDF/A-1 producer slice:v2.103 閉合 #15 透明度 (CRITICAL) + #5 LZW filter + #10 image /Interpolate + #14 ExtGState /TR;v2.104 閉合 #16 FileAttachment/Sound/Movie annot + #17 annot /F /AP 規則 + #18 Launch/Sound/Movie/ResetForm/ImportData/JavaScript actions + #20 Form 欄位 /A /AA + /NeedAppearances。

2026-05-19 Version 2.101.0

  • 啟動四版本 PDF/A-1 (ISO 19005-1:2005) producer-side 合規系列,首版落地 wrapper 層 opt-in。完整 17 缺口審計報告歸檔在 `.superpowers/specs/2026-05-19-pdfa1-compliance-audit.md`;v2.101 落基礎(PDFACompliance 屬性、XMP pdfaid 標識、Title/Lang 嚴格化、加密衝突 guard)。v2.102 - v2.104 閉合剩餘顏色管理 / 透明度 / 字體 / 註釋 + 操作缺口。
  • 新 `PDFACompliance: AnsiString` 屬性接受 '' (禁用,預設)、'A' (Level A: 視覺 + Tagged PDF + 無障礙) 或 'B' (Level B: 僅視覺保真)。EndDoc 時無效值拋異常。按 ISO 19005-1:2005 §5 conformance levels。
  • 設 PDFACompliance:='A' 自動啟用 PDFUACompliance(Level A 繼承 §6.8 Tagged PDF 要求,與 PDF/UA-1 §7 logical structure 要求一致)。兩個 wrapper 可同時啟用無衝突;v2.94 PDF/UA-1 Lang/Title/Suspects gate 疊在 v2.101 PDF/A guard 之上。
  • 設任一級別自動啟用 FEnableXMPMetadata 讓文件攜帶必需的 /Metadata XMP 流。按 §6.7.2 Catalog Metadata 強制。
  • BuildXMPPacket 擴展:PDFACompliance 非空時 XMP packet 聲明 `xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/"` 加 `<pdfaid:part>1</pdfaid:part>` 和 `<pdfaid:conformance>A</pdfaid:conformance>` (或 `B`)。veraPDF 等驗證器靠這組三元組分類文件為 PDF/A-1A 或 1B 候選。按 §6.7.11 Table 6 PDF/A 標識 schema。
  • Title / Lang 嚴格化:PDFACompliance 啟用 + Doc.Title='' 拋 (PDF/A-1 §6.7.3 要求 dc:title in XMP 與 Info /Title 等價)。Lang 嚴格化鏡像 v2.94 PDFUACompliance 行為(§6.8.4 for Level A),呼叫方必須顯式選有效 BCP-47 標籤而非接受靜默 'en' 回退。
  • 加密衝突 guard:按 §6.1.3 文件 trailer 不能含 /Encrypt。EnableEncrypt(OwnerPassword/UserPassword/Protection 設置觸發的內部入口)現在 PDFACompliance 非空時拋清晰診斷。EndDoc 經同路徑暴露衝突,讓呼叫方在序列化之前看到失敗。
  • 呼叫方仍需自負責:emit 有效 PDF/A-1 OutputIntent + ICC profile(v2.102 跟進)、避免透明度(v2.103)、避免禁用的 annotation/action 類型(v2.104)、Level A 真實語義結構樹(由 v2.96-v2.99 Tagged PDF helper 覆蓋)。
  • Win32 + Win64 clean compile;v2.100 baseline smoke_pdfua_link_contents 重 compile 透過。新 smoke smoke_pdfa1_compliance emit Level A 和 Level B PDF + 行使三個驗證路徑(無效 level Z、空 Title、加密 + PDFACompliance 衝突)。Python verifier 斷言 xmlns:pdfaid + pdfaid:part=1 + 匹配 pdfaid:conformance、dc:title、Level A 另外含 /MarkInfo /Marked true + Catalog /Lang + /StructTreeRoot + xmlns:pdfuaid(自動繼承)。

2026-05-19 Version 2.100.0

  • 閉合 2026-05-19 PDF/UA-1 審計中剩餘的 §7.18.5 link-annotation /Contents 覆蓋缺口。v2.95 給 AddURILink 加 Description;v2.100 把同樣的替代描述支援帶到剩餘三個 link 入口:AddGoToLink(文件內跳轉)、AddGoToRLink(跨文件跳轉)、AddLaunchLink(外部文件啟動)。
  • 每個 helper 增加可選末參 `const Description: AnsiString = ''`。非空時 annotation dict 攜帶 `/Contents (Description)` 條目;`PDFUACompliance` 模式下空 Description 拋異常並給出明確診斷說明出問題的 link 目標,缺失替代描述無法靜默透過。預設空保 PDFUACompliance 模式之外的向後相容。
  • 按 PDF/UA-1 §7.18.5 嚴格:"鏈接必須透過 Contents 鍵提供替代描述(按 ISO 32000-1:2008, 14.9.3)"。spec 適用於所有 link annotation 類型不只 URI link — helper 簽章現在統一覆蓋。
  • 典型用法:`Page.AddGoToLink(R, 1, 700, '跳到第 2 頁:方法論'); Page.AddGoToRLink(R, 'companion.pdf', 0, -1, false, '開啟伴隨文件檢視完整資料表'); Page.AddLaunchLink(R, 'readme.txt', false, '在預設文本編輯器開啟 README');`
  • Win32 + Win64 clean compile;v2.99 baseline smoke_pdfua_figure 重 compile 透過。新 smoke smoke_pdfua_link_contents 構造 2 頁文件在 page 0 加三個 link annotation(GoTo 跳 page 1、GoToR 跳 'companion.pdf'、Launch 啟 'readme.txt')+ 三個 PDFUACompliance 空 Description 異常路徑。Python verifier 斷言每個 link annotation 帶 /Subtype /Link、匹配的 /S /GoTo(或 /GoToR / /Launch)action 類型、與傳入 Description 匹配的 /Contents 值。
  • PDF/UA-1 producer 面覆蓋總結:v2.100 之後,四個 link annotation 入口全部滿足 §7.18.5。配合 v2.94 審計閉環(Suspects、Tabs、Lang)、v2.95(URI Contents、Bit 10、ID)、v2.96-v2.99 Tagged PDF semantic helper 系列(Heading、List、Table、Figure),HotPDF 的 PDF/UA-1 producer-side 面在 spec-strict wrapper 層與 ergonomic API 層雙閉環。

2026-05-19 Version 2.99.0

  • 新增 `BeginTaggedFigure(Parent, AltText, BBox): FigureElem` + `EndTaggedFigure` 作為 Tagged PDF semantic helper 系列第四刀也是最後一刀,對應 PDF/UA-1 §7.3(Graphics)。把呼叫方提供的繪圖操作(圖像 XObject、矢量路徑、描邊矩形)包在 Figure 結構元素裡,帶強制 /Alt 和可選 /BBox 佈局屬性。
  • /Alt 強制(無空字串預設 fallback)。按 PDF/UA-1 §7.3 嚴格:"Figure 標籤必須包含代表 Figure 內容的替代表示或替代文本"。空 AltText 拋異常並給出明確診斷指向 v2.88 6 參 AddStructureElement 重載(如果 /ActualText 而非 /Alt 才是適合的替代文本機制)。
  • 可選 BBox 是 4 元素 [llx, lly, urx, ury] 數組描述 Figure 在預設使用者空間的邊界框,按 ISO 32000-1 14.8.5.4.5 Layout 屬性 owner 附為 /A << /O /Layout /BBox [...] >>。傳空數組完全省略 BBox 屬性。長度錯(1/2/3/5+ 元素)拋異常並給出 spec 矩形佈局指引。
  • 典型用法:`Fig := Doc.BeginTaggedFigure(Root, '公司 logo:指向右側的箭頭', [72, 600, 200, 720]); ... 繪 Figure 內容 ... Doc.EndTaggedFigure;` Figure 參與與其他 v2.90 BeginTaggedContent 路徑相同的 MCID / ParentTree 接線,但 /Alt + /BBox 屬性自動掛上。
  • 這閉合審計報告中 PDF/UA-1 §7.3 呼叫方責任面。Tagged PDF semantic helper 系列現在覆蓋所有四種重型結構類型:§7.4(Heading,v2.96)、§7.6(List,v2.97)、§7.5(Table,v2.98)、§7.3(Figure,v2.99)。配合 v2.94 + v2.95 wrapper 層修復,HotPDF 的 PDF/UA-1 producer 面在 spec 級別既 strict-conformant 又在 API 級別 ergonomic。
  • Win32 + Win64 clean compile;v2.98 baseline smoke_pdfua_table 重 compile 透過。新 smoke smoke_pdfua_figure emit 兩個 Figure 結構元素(一個帶 /Alt + /BBox、一個僅 /Alt)+ 行使空 AltText 與畸形 BBox 異常路徑。Python verifier 斷言兩個 Figure /S 類型、/Alt 文本匹配、BBox 數組值為 [72, 600, 200, 720]。

2026-05-19 Version 2.98.0

  • 新增 4 個 Tagged Table helper 對應 PDF/UA-1 §7.5(Tables)作為 Tagged PDF semantic helper 系列第三刀。`BeginTaggedTable(Parent): TableElem` 構造 Table 結構容器;`AddTaggedTableRow(Table): TRElem` 添加 TR 行;`EmitTaggedTableHeader(TR, X, Y, Text, Scope): THElem` emit 帶強制 /Scope 屬性的 TH 表頭單元格;`EmitTaggedTableCell(TR, X, Y, Text): TDElem` emit TD 資料單元格。5 個標籤類型(Table、TR、TH、TD 加屬性物件)全部 spec 合規。
  • /Scope 屬性(ISO 32000-1 14.8.5.7 Table 350)helper 強制(無預設),合法值 `Row` / `Col` / `Both`。無效 Scope 字串拋異常並給出 spec 集合。PDF/UA-1 §7.5 嚴格:"TH 類型結構元素應有 Scope 屬性。如果表格結構無法透過 Headers + IDs 判定,TH 結構元素必須有 Scope 屬性"。helper 簽章強制 Scope 阻止 missing-Scope 合規失敗模式。
  • Scope 序列化按標準屬性物件形式:`/A << /O /Table /Scope /<Row|Col|Both> >>`(按 ISO 32000-1 14.7.5.3 Class Map)讓消費閱讀器視其為 Table 命名空間屬性。與 v2.97 List 的 `/A << /O /List /ListNumbering ... >>` 屬性同模式。
  • Table 與 TR 是純結構容器(不帶頁內容 marked-content),但 TH 和 TD 攜帶可見文本所以都走 BeginTaggedContent + TextOut + EndTaggedContent。每個 TH/TD 單元格分配自己的 MCID、頁內容流 BDC 算子、ParentTree 入口。helper 返回 cell StructElem 讓呼叫方掛更多屬性(如複雜表的 /Headers list、/RowSpan、/ColSpan)。
  • 典型用法:`T := Doc.BeginTaggedTable(Root); R := Doc.AddTaggedTableRow(T); Doc.EmitTaggedTableHeader(R, 72, 750, WideString('Name'), 'Col'); Doc.EmitTaggedTableHeader(R, 200, 750, WideString('Age'), 'Col'); R2 := Doc.AddTaggedTableRow(T); Doc.EmitTaggedTableCell(R2, 72, 730, WideString('Alice')); ...` 替代 v2.90 每個單元格多步結構 + BDC/EMC 序列。
  • 這閉合審計報告中 PDF/UA-1 §7.5 呼叫方責任面。Tagged PDF semantic helper 系列現在覆蓋 §7.4(Heading,v2.96)、§7.6(List,v2.97)、§7.5(Table,v2.98)。剩餘 slice(v2.99+):Figure helper for §7.3 含 /BBox + /Alt + 呼叫方提供繪圖塊。
  • Win32 + Win64 clean compile;v2.97 baseline smoke_pdfua_list 重 compile 透過。新 smoke smoke_pdfua_table 構造 3 行表(1 表頭 + 2 資料),3 個 TH 單元格(Scope=Col)+ 6 個 TD 單元格 + 行使無效 Scope 異常路徑。Python verifier 斷言完整 Table > TR > TH/TD 結構每個 TH 帶 /Scope /Col。

2026-05-19 Version 2.97.0

  • 新增兩個 PDF/UA-1 §7.6 List helper 作為 Tagged PDF semantic helper 系列第二刀:`BeginTaggedList(Parent, NumberingStyle): ListElem` 構造 L 結構元素並附 /A << /O /List /ListNumbering /<Style> >> 屬性物件(按 ISO 32000-1 14.8.5.5);`EmitTaggedListItem(ListElem, LblX, LblY, LabelText, BodyX, BodyY, BodyText): LIElem` emit 完整 LI > {Lbl, LBody} 子結構,Lbl 與 LBody 都帶 marked-content 包裹可見文本。
  • NumberingStyle 參數接受 8 個 PDF/UA-1 / ISO 32000-1 spec 名:`None`、`Decimal`、`UpperRoman`、`LowerRoman`、`UpperAlpha`、`LowerAlpha`、`Circle`、`Disc`。無效 style 名拋異常並給出完整 spec 集合。空字串完全省略 /ListNumbering 讓呼叫方自行附加自定義屬性物件。
  • 按 PDF/UA-1 §7.6:有序列表必須顯式 /ListNumbering 屬性;無序列表可用 `None` 或 bullet glyph 之一。helper 不強制——呼叫方負責選與可見內容匹配的 style。
  • 典型用法:`Lst := Doc.BeginTaggedList(Root, 'Decimal'); Doc.EmitTaggedListItem(Lst, 72, 750, WideString('1.'), 96, 750, WideString('First item')); ...` 每個列表項一行替代 v2.90 六行 LI + Lbl-BDC-TextOut-EMC + LBody-BDC-TextOut-EMC 鏈。
  • Lbl 與 LBody 子結構都經過 BeginTaggedContent(各自分配 MCID 和 ParentTree 入口),EmitTaggedListItem 返回 LI 結構元素讓呼叫方可附加嵌套 LI 子項、/Alt 或 /Lang。
  • 這閉合審計報告中 PDF/UA-1 §7.6 呼叫方責任面。剩餘 Tagged PDF semantic helper slice(v2.98+):Table helper 覆蓋 §7.5(Table / TR / TH / TD with /Scope)、Figure helper 覆蓋 §7.3(Figure + /Alt + /BBox 屬性)。
  • Win32 + Win64 clean compile;v2.96 baseline smoke_pdfua_heading 重 compile 透過。新 smoke smoke_pdfua_list 構造 3 項 Decimal 有序列表 + 2 項 None 無序列表 + 行使無效 style 異常路徑。Python verifier 斷言兩個 /S /L StructElem 帶不同 /ListNumbering 屬性值、3 vs 2 LI 子項、有序列表第一個 LI 含 Lbl/LBody 子項。

2026-05-19 Version 2.96.0

  • 新增 `EmitTaggedHeading(Level, Parent, X, Y, Text)` 高層 helper 對應 PDF/UA-1 §7.4。一次呼叫 emit 完整 `/H1`..`/H6` 結構元素 + 當前頁可見文本:helper 分配 per-page MCID、發 BDC 算子、跑 TextOut、再 EMC,構造對應 /H<Level> 角色的 StructElem 接進 /ParentTree。替代 v2.90 三行 BeginTaggedContent + TextOut + EndTaggedContent 模板的常見 heading 場景。
  • Level 參數接受 1..6(標準 heading 範圍)。超範圍 Level 拋 Exception 並給出明確診斷。PDF/UA-1 §7.4.3 允許使用者定義 H7+ 標籤但少見;需要的呼叫方仍可手工調 BeginTaggedContent('H7', ...)。
  • 返回 heading StructElem 讓呼叫方能在 helper 返回後鏈式添加屬性(/Lang、裝飾性 heading 的 /Alt 等)。
  • 典型用法:`Doc.EmitTaggedHeading(1, RootElem, 72, 750, WideString('第一章'));` 現在完全代替之前 BDC + TextOut + EMC + AddStructureElement 多行 plumbing。
  • 這是 v2.95 PDF/UA-1 wrapper 閉環後規劃的"Tagged PDF semantic helpers"系列第一刀。後續 slice(v2.97+)覆蓋 List(L / LI / Lbl / LBody)和 Table(Table / TR / TH / TD with /Scope)helper,閉合審計報告中 §7.5 / §7.6 的呼叫方責任面。
  • Win32 + Win64 clean compile;v2.95 baseline 重 compile 透過。新 smoke smoke_pdfua_heading emit 三個 heading (H1/H2/H3) 加 Level=7 範圍檢查異常路徑;Python verifier 斷言三個 /S /H<n> StructElem 與解壓後頁內容流中的匹配 /H<n> BDC 算子。

2026-05-19 Version 2.95.0

  • PDF/UA-1 審計收口:處理 v2.94 審計中標記的剩餘三個 producer-side 缺口(§7.18.5 Link Contents、§7.16 加密 Bit 10、§7.9 StructElem ID)。PDF/UA-1 producer 面現已 spec-complete;審計原始六個缺口在 v2.94 + v2.95 橫跨閉合。
  • §7.18.5 Link Contents(HIGH):`AddURILink(Rect, URL, Description='')` 增加第三個 `Description` 參數,非空時填到 annotation 的 `/Contents` 鍵作為替代描述。PDF/UA-1 §7.18.5 強制要求 "鏈接必須透過 Contents 鍵提供替代描述"。PDFUACompliance 模式下空 Description 現在拋異常並給出清晰診斷。預設 Description='' 保 PDFUACompliance 之外的向後相容。
  • §7.16 加密 Bit 10(MED):PDFUACompliance=True 且文件加密(透過 EnableEncrypt)時,HotPDF 自動 `ProtectFlags := ProtectFlags or $200`(Bit 10 = "提取文本和圖形供輔助技術使用")。按 PDF/UA-1 §7.16:"加密的合規文件其加密字典必須含 P 鍵。P 鍵的第 10 位必須為 true"。沒這個 bit,屏幕閱讀器無法從加密 PDF 提取內容,無障礙性破壞。修復是條件性的——非 PDFUA 加密 caller-supplied flag 不變。
  • §7.9 StructElem ID(LOW):新 7 參 `AddStructureElement` 重載接受非空 `IDStr` 參數,寫入結構元素的 `/ID` 鍵。helper 維護 issued ID 內部集合並在碰撞時拋異常,防止重複 Note ID 滑過去(這會混亂交叉引用 Link → Note 跳轉和輔助技術)。按 spec:"每個 Note 標籤必須在 ID 鍵有一個唯一條目"。
  • EnableEncrypt 重構:原 body 現歸 `EnableEncryptInternal`,公開 `EnableEncrypt` 是 6 行包裝:先做 PDF/UA-1 Bit 10 stamp 再轉發。v2 / v4 / v5 加密分支字節級不變;既有加密 PDF 呼叫方除非顯式啟用 PDFUACompliance 保字節級一致。
  • 驗證器覆蓋:新 smoke_pdfua_gap_closure 行使 §7.18.5(帶 Description 的 Link)+ §7.9(兩個不同 ID 的 Note 結構元素 + 一次碰撞應拋)。Verifier 斷言 `/Contents` 存在並匹配 Description、兩個唯一 Note `/ID` 值存在。加密 Bit 10 修復在審計報告中記錄;加密 PDF 的 smoke 覆蓋推到更大型加密測試重寫。
  • spec 覆蓋閉環:v2.95 落地後,2026-05-19 PDF/UA-1 審計(`.superpowers/specs/2026-05-19-pdfua-compliance-audit.md`)的所有 6 個缺口全部閉合。HotPDF 的 PDF/UA-1 producer-side 面對 wrapper 層(§5 metadata、§6 conformance、§7.1 Catalog 要求、§7.2 Lang、§7.16 encryption、§7.18.3 Tabs、§7.18.5 Link Contents、§7.9 Note IDs)已 strict-conformant。語義結構樹決策(標題層級、列表嵌套、表頭 TH/Scope、Figure /Alt 質量)一如既往是呼叫方責任。

2026-05-19 Version 2.94.0

  • PDF/UA-1 (ISO 14289-1:2014) producer-side 合規審計後續:閉合 v2.87 高層 opt-in 沒覆蓋的三個真實合規缺口。審計逐項對照 HotPDF v2.93 輸出與 §7 文件格式要求每個子節,識別出六個 producer 缺口;本版處理三個 EndDoc 階段的修復(Suspects 鍵、annotated-page Tabs、Lang 嚴格化)。剩餘三個缺口(Link Contents、加密 Bit 10、StructElem ID)落在 v2.95-v2.97。
  • §7.1 Suspects(HIGH):`PDFUACompliance` 啟用時 Catalog → MarkInfo 字典現在發 `/Suspects false`。按 spec "聲明合規的文件 Suspects 值必須為 false" — veraPDF 等驗證器檢查鍵的**顯式存在**,不是缺席。v2.93 完全不發該鍵,spec-strict 驗證會報 "Catalog MarkInfo does not contain a Suspects entry"。
  • §7.18.3 Tabs(MED):EndDoc 現在遍歷每頁,對所有含非空 `/Annots` 數組且未聲明 `/Tabs` 的頁自動蓋 `/Tabs /S`。按 spec "任何帶註釋的頁面其頁字典必須含 Tabs 鍵 ... 值為 S"。僅在 `PDFUACompliance` 啟用時觸發;呼叫方手工設過 `/Tabs`(透過 `THPDFPage.SetTabsOrder`)的選擇被尊重。
  • §7.2 Lang(MED):`PDFUACompliance=True` 時若 `Doc.Lang` 為空現在拋 Exception 給出明確診斷,不再靜默填 `'en'`。v2.94 之前的 fallback 給非英文文件貼錯標籤(任何中文/阿拉伯/日韓等內容會靜默 emit 錯的 BCP-47 標籤,屏幕閱讀器據此切換髮音)。呼叫方現在必須顯式聲明文件語言——典型用法:`Doc.Lang := 'en-US'`、`'zh-CN'`、`'ar-SA'` 等。
  • 向後相容說明:既有 PDFUACompliance 呼叫方必須在 BeginDoc / EndDoc 之前加 `Doc.Lang := '...'`。四個範例 smoke(smoke_pdfua_compliance、smoke_pdfua_alt_actualtext、smoke_pdfua_annot_structparents、smoke_pdfua_tagged_content)已統一設 `Doc.Lang := 'en-US'`。不用 PDFUACompliance 的呼叫方不受影響。
  • 驗證器覆蓋:smoke_pdfua_compliance_verify.py 現在斷言 Catalog MarkInfo 字典含 `/Suspects false`;smoke_pdfua_annot_structparents_verify.py 斷言帶註釋的頁面含 `/Tabs /S`。兩者都在生成的 PDF 上端到端跑。
  • 審計報告:完整 PDF/UA-1 合規審計報告(覆蓋 §7 全部 21 個文件格式子節)歸檔在 `.superpowers/specs/2026-05-19-pdfua-compliance-audit.md`(項目本地,不入倉)。報告把每個子節分類為"HotPDF 自動滿足"、"呼叫方責任帶 helper API"或"真實 producer 缺口",並按嚴重度給剩餘缺口排好 v2.95+ 路線圖。

2026-05-19 Version 2.93.0

  • 新增 `RegisterColorConversionLUT3D(GridR, GridG, GridB, OutputComponents, Samples, BitsPerSample=8, Order=1): THPDFStreamObject` 高層 wrapper,針對常見的 3 輸入色彩管理 LUT 用例封裝 v2.52 Function Type 0 原語。內部自動構建標準 /Domain=[0,1]*3 + /Range=[0,1]*OutputComponents + /Size=[GridR, GridG, GridB] 數組並轉發給 RegisterSampledFunction。
  • 典型工作流程:ICC profile 驅動的 sRGB → Lab、sRGB → CMYK 或 RGB → RGB device-link 轉換表達為 3D LUT。wrapper 校驗每軸 grid size 和 OutputComponents 範圍;底層 RegisterSampledFunction 校驗 BitsPerSample / Order / 總字節數與 Sample payload size 一致。長度對不上時從原語拋出明確診斷。
  • Sample 字節佈局:3D 網格行優先(R 最快,G 次之,B 最外層);每個 cell BitsPerSample=8 時佔 OutputComponents 字節。總數 = GridR * GridG * GridB * OutputComponents。更高比特深度(12、16)需要呼叫方按 spec MSB-first 字節打包規則手工封裝好。
  • 使用者可見影響:色彩管理工作流程現在可以用一行 17x17x17 RGB → CMYK ICC 模擬 LUT,參數是預計算好的樣本數組,不再需要手工建 /Domain / /Range / /Size。返回的 indirect THPDFStreamObject 插入任何接受 Function 的 API:Pattern Type 2 axial/radial shading 的 /Func 項、Separation tint transform(透過 RegisterSeparationLUT)、/TR 傳輸函數 ExtGState、/BG 黑色生成 ExtGState。
  • 向後相容:既有 RegisterSampledFunction 原語不變;新 wrapper 只是薄薄一層。需要非預設 /Domain(如 Lab L* 在 [0..100]、a*/b* 在 [-128..127])或非矩形 Range 的呼叫方繼續直接用 RegisterSampledFunction。
  • 候選 #4 狀態:這是矩陣候選 "3D Function Type 0" 唯一的一刀。高層 wrapper 讓既有的 N=3 原語在典型色彩管理用例中變得 ergonomic;候選 #4 完成。

2026-05-19 Version 2.92.0

  • 新增 `RegisterHalftoneType5(ColorantNames, Halftones, DefaultHalftone, HalftoneName)` 收口 ExtGState `/HT` halftone 家族。Type 5 是多 component 字典,按顏色名 key(如 /Cyan /Magenta /Yellow /Black /Red /Green /Blue /Gray 加任何已註冊的 Separation/DeviceN spot color),值是指向 Type 1/6/10/16 sub-halftone 的 indirect ref。CMYK prepress 工作流程現在可以在一個 ExtGState 裡給每個 ink 單獨設置屏蔽頻率/角度/網點形狀。
  • 並行數組簽章:`ColorantNames` 和 `Halftones` 按下標配對,長度必須相同。空 colorant 名或 nil halftone 拋異常並指出問題下標。可選 `DefaultHalftone` 進 dict 的 /Default fallback,消費閱讀器對不在顯式列表裡的 colorant 用它(文件含意外 spot color 時常用)。
  • 輸出字典結構(PDF 1.7 ISO 32000-1 10.5.5.2):/Type /Halftone + /HalftoneType 5 + 可選 /HalftoneName + 每對一個 /ColorantName 條目 + 可選 /Default。返回 indirect THPDFDictionaryObject,呼叫方可以像其他 halftone 物件一樣傳給 v2.64 `RegisterHalftoneState`。
  • 校驗:至少要有一個 component 或 DefaultHalftone(空 Type 5 沒語義)。helper 不驗證 sub-halftones 不是 Type 5(spec 禁止 Type 5 嵌套),因為呼叫方要主動構造自引用圖才會觸發,實際 prepress 工作流程不會。
  • 使用者可見影響:製作四色冊子的 prepress 工程師現在可以一次設四個獨立屏蔽(Cyan 105°/75 lpi、Magenta 75°/75 lpi、Yellow 90°/75 lpi、Black 45°/75 lpi 用 Type 1 spot 函數,或換 Type 6 threshold raster 做 FM 屏蔽)包進一個 ExtGState。同一個 ExtGState 由後續任何需要 per-channel 屏蔽的繪圖呼叫激活。
  • 候選 #3 狀態:這是 ExtGState `/HT` halftone 家族的第二刀,也是最後一刀。完整功能集(v2.64 Type 1 spot 函數 + v2.92 Type 5 多 component + v2.91 Type 6/10/16 threshold-stream)現在 PDF 1.7 spec 完整。候選 #3 完成。

2026-05-19 Version 2.91.0

  • 新增三個 threshold-stream halftone builder 收口 v2.64 起步的 ExtGState `/HT` halftone 家族:`RegisterHalftoneType6`(8-bit threshold raster,Width/Height 鍵)、`RegisterHalftoneType10`(8-bit threshold raster,平行四邊形 cell 透過 Xsquare/Ysquare 表示帶角度屏蔽)、`RegisterHalftoneType16`(16-bit threshold raster,65536 級精度用於高端 prepress)。
  • 每個 builder 返回 indirect /Type /Halftone 流物件,呼叫方可傳給 v2.64 `RegisterHalftoneState` 包成 ExtGState /HT 項,與 Type 1 spot 函數 halftone 用法一致。可選 /HalftoneName、/TransferFunction 或 /TransferFunction /Identity 條目與 Type 1 模式相同。
  • 體積校驗:Type 6 要求 ThresholdBytes 長度 = Width*Height;Type 10 要求 Xsquare^2 + Ysquare^2(PDF 1.7 10.5.5.4 stacked-squares 佈局);Type 16 要求 Width*Height*2(big-endian uint16 對,呼叫方自己擺好)。長度對不上拋 Exception 同時列出實際和期望字節數。
  • 共享 `_HotPDFCreateHalftoneStream` 內部 helper 去重每個 Type 的構造邏輯:indirect 流分配、/Type /Halftone + /HalftoneType N 頭部、可選 name + transfer function 條目、payload 寫入 + /Length 標。每個對外函數只校驗自己 type 特定的 size 鍵再轉發。
  • 使用者可見影響:需要使用者自定義屏蔽 pattern 的 prepress 工作流程(自定義網點形狀、頻調網點、角度網點)現在在 HotPDF 中有了入口。呼叫方提供 threshold raster(通常用屏蔽生成器離線生成),HotPDF 發 spec 合規的 /Type /Halftone 流物件並接進 ExtGState 資源鏈。
  • Spec 覆蓋:PDF 1.7 ISO 32000-1 10.5.5.3 (Type 6) + 10.5.5.4 (Type 10) + 10.5.5.5 (Type 16)。自動 bump 到 PDF 1.2(與 Type 1 同 floor,halftone 在 1.2 一起進入)。
  • 候選 #3 狀態:這是矩陣候選 "ExtGState /HT halftone 剩餘類型" 的第一刀。Type 5 多 component halftone(按顏色元件名 key 的字典,每通道委託給 Type 1/6/10/16 sub-dict,CMYK prepress 用)是第二刀也是最後一刀,落在 v2.92。

2026-05-19 Version 2.90.0

  • 新增高層 marked-content 序列 helper:`THotPDF.BeginTaggedContent(Role, Parent): THPDFDictionaryObject` + `THotPDF.EndTaggedContent`。Helper 自動分配 per-page MCID、在當前頁內容流發 BDC 算子、在 Parent 下構造 StructElem、把它接進 /ParentTree——一次呼叫完成。結果:PDF/UA-1 呼叫方可以標記可見內容段落而無需手工管理 MCID 計數器。
  • 典型用法:`Para := Doc.BeginTaggedContent('P', Root); Doc.CurrentPage.TextOut(...); Doc.EndTaggedContent;` 返回的 StructElem 可以鏈式傳給 AddStructureElement('Span', Para, ...) 構造子結構,或透過 v2.88 屬性路徑攜帶 /Alt / /ActualText。
  • 新 THPDFPage.FNextMCID 欄位跟蹤每頁 MCID 分配;每頁重置(在 BeginDoc init 中 lazy 初始化為 0)。低層 BeginMarkedContentMCID / EndMarkedContent 算子(HotPDF 自 v2.11 起就有)仍可供需要顯式 MCID 控制的呼叫方使用。
  • Pipeline 集成:BeginTaggedContent 在當前頁內容流發 "/Role <</MCID n>> BDC",調 AddStructureElement(Role, Parent, PageIdx, MCID) 構造 StructElem 並跑 RegisterMCIDForPage(v2.11 路徑,lazy 給頁字典標 /StructParents 並擴 /ParentTree 的 per-page array)。EndTaggedContent 在當前頁發 "EMC"。嵌套透過頁內容流線性順序隱式工作。
  • 使用者可見影響:PDF/UA-1 候選文件現在可以在每個可見段落、標題、span 或圖說前後兩行就給它標語義結構。veraPDF 接受產生的頁內容 marked-content 序列 + StructTree 聯動;輔助技術沿文件大綱走進 marked content,朗讀其角色 + 文本。
  • 候選 #1 狀態:第四刀也是最後一刀。PDF/UA-1 producer-side 面現在覆蓋 wrapper opt-in (v2.87) + /Alt / /ActualText 屬性 (v2.88) + 註釋 /StructParent + OBJR 反向接入 (v2.89) + 頁內容 BDC/EMC 自動包裹 (v2.90)。呼叫方仍需自負責結構樹拓撲決策(標題層級、列表嵌套、表頭),但機械接線全部自動化。候選 #1 完成。

2026-05-19 Version 2.89.0

  • 新增註釋到結構樹接入,按 PDF 1.7 14.7.4.4。新 `THotPDF.RegisterAnnotForStructure(AnnotDict, StructElem)` helper 分配新的 /ParentTree key、給 annotation 標 /StructParent、把 StructElem 直接存到 /ParentTree[Key](註釋用單 ref 形式,區別於頁面 MCID 用的數組形式)、並把 <</Type /OBJR /Obj <annotRef>>> 追加到 StructElem 的 /K 數組。屏幕閱讀器現在可以從任何 tagged 註釋向上導航到父結構元素,反向也通。
  • 新增 `THPDFPage.AddURILink(Rect, URL): THPDFDictionaryObject` 讓 PDF/UA-1 呼叫方有個返回值的 URI 註釋入口。既有 AddGoToLink / AddGoToRLink / AddLaunchLink 方法不返回 annot 字典(早期 API 侷限);新 AddURILink 返回 indirect 註釋字典,可直接傳給 RegisterAnnotForStructure。
  • 使用者可見影響:PDF/UA-1 候選文件現在用三行代碼就能給超鏈接打語義結構標籤:`LinkAnnot := Doc.CurrentPage.AddURILink(R, 'https://example.org/'); LinkElem := Doc.AddStructureElement('Link', RootElem, -1, -1); Doc.RegisterAnnotForStructure(LinkAnnot, LinkElem);` 跟隨文件大綱的輔助技術現在可以達到鏈接、朗讀其用途、並以可激活元素方式呈現。
  • 實現說明:v2.11 EmitTaggedPDFRoot 發 /ParentTree /Nums 條目的循環原本用硬強轉 `THPDFArrayObject(FParentTree.Items[I])`。v2.89 把強轉放寬到 THPDFObject 因為註釋條目存的是單個字典而非數組;THPDFArrayObject.AddObject 本來就靠執行時 IsIndirect 探測分派,所以強轉其實一直是名義上的。v2.11+ 在 FParentTree 裡存數組的 smoke 字節級穩定。
  • Spec 說明:PDF 1.7 14.7.4 允許 /ParentTree 值是數組(marked-content 序列按 MCID 索引)或直接 StructElem ref(註釋、beads 等非 MCID 結構元素)。v2.89 是第一刀用單 ref 形式;數組形式繼續透過 v2.11 AddStructureElement-帶-MCID 路徑工作。
  • 候選 #1 狀態:PDF/UA producer-side 充實的第三刀。還剩一刀:頁面內容 BDC/EMC 自動包裹,讓 AddTextField + CurrentPage.TextOut 路徑自動發 marked-content 序列而不需要手工算子呼叫。之後 PDF/UA producer 面落到滿意的基線。

2026-05-19 Version 2.88.0

  • 給 `AddStructureElement` 增加重載簽章,接受可選的 `/Alt` 和 `/ActualText` 屬性字串。PDF/UA-1 (ISO 14289-1) 要求非文本內容(圖形、公式、裝飾字形)必須提供屏幕閱讀器友好的替代文本;新重載讓一行呼叫就把它們掛到 StructElem 上。
  • `/Alt`(替代描述)是輔助技術為非文本內容朗讀的文本——典型用法:包裹圖像或圖表的 Figure 結構元素。`/ActualText`(實際文本)是複製粘貼時返回的內容(當可見字形與預期 Unicode 不同時使用)——典型用法:裝飾連字、首字下沉、難以提取的書法字形。
  • 兩個屬性都作為 PDF 文本字串透過標準 byte-safe SaveStringObject 轉義路徑發出;空字串跳過對應條目,讓既有四參數呼叫方保持字節級輸出。原四參 `AddStructureElement(Role, Parent, PageIndex, MCID)` 簽章透過 Pascal `overload` 指令保留。
  • 使用者可見影響:PDF/UA-1 候選文件現在可以用 `AddStructureElement('Figure', Root, 0, 0, '公司 logo', '')` 標記 logo 圖形,用 `AddStructureElement('Span', Root, 0, 1, '', '公交站')` 標記裝飾字形 span;veraPDF 和輔助技術直接消費產生的 /Alt 和 /ActualText 條目,無需更多設置。
  • Pipeline 位置:v2.88 重載轉發到 v2.11 base 實現(StructTreeRoot 接線 + /K 數組追加 + /Pg 反向鏈接 + MCID/ParentTree 註冊都按原路跑),然後只追加兩個屬性條目。不動既有呼叫點;v2.74-v2.87 字節穩定性保留。
  • 候選 #1 狀態:這是 PDF/UA producer-side 充實的第二刀。後續:頁面內容 BDC/EMC 自動包裹(AddTextField + CurrentPage.TextOut 路徑無需手工調算子即可發射 marked-content 序列);註釋 /StructParents 接入(讓屏幕閱讀器導航也覆蓋 link / 表單 widget)。

2026-05-19 Version 2.87.0

  • 新增 PDF/UA-1 (ISO 14289-1) 高層 opt-in,透過新 `PDFUACompliance` 屬性開啟。在 BeginDoc / EndDoc 之前設為 True 自動啟用所有 HotPDF 能在不需要呼叫方配合的情況下滿足的 PDF/UA-1 producer-side 包裝要求:/MarkInfo /Marked = true、/StructTreeRoot stub、/Lang(空時預設 'en')、/ViewerPreferences /DisplayDocTitle = true、/Metadata XMP 流、以及 XMP 包裡 AIIM 註冊的 pdfuaid:part = 1 標識。
  • 一個屬性代替六個開關:之前要做 PDF/UA-1 合規的呼叫方需要逐個設 EnableTaggedPDF + EnableXMPMetadata + Lang + ViewerPreferences := [vpDisplayDocTitle] + Title,再手工拼一個自定義 XMP packet 加 pdfuaid namespace。v2.87 把這些摺疊成 PDFUACompliance:=True;各個單獨的 flag 仍然可用,呼叫方顯式設了的話會被尊重。
  • XMP packet 更新:BuildXMPPacket 現在在 PDFUACompliance 為 True 時發射 xmlns:pdfuaid="http://www.aiim.org/pdfua/ns/id/" 加 <pdfuaid:part>1</pdfuaid:part>。veraPDF 等 PDF/UA-1 驗證器靠這組 namespace + 標識符三元組識別文件為 PDF/UA-1 候選。
  • 使用者可見影響:用 `Doc.Title := '...'; Doc.PDFUACompliance := True; Doc.BeginDoc; ...; Doc.EndDoc;` 寫出來的 PDF 在 veraPDF 裡驗證為 PDF/UA-1 候選,不需要進一步設置——前提是文件正文透過 AddStructureElement + marked-content 序列真實構造了結構樹。政府/教育/無障礙法規驅動的發佈流現在有了一個開關。
  • 呼叫方仍需自擔的工作:PDF/UA-1 同時要求結構樹完整性(每個 glyph 屬於某個被標記的結構元素)、圖形/公式內容的 /Alt 或 /ActualText、合理的 tab 順序、有效的標題層級等。opt-in 覆蓋的是機器可檢 validator 首先檢查的 Catalog/metadata 層封裝;完整語義合規仍靠呼叫方誠實地透過 AddStructureElement 和 marked-content BDC / EMC 算子構造結構樹。
  • 向後相容:PDFUACompliance 預設 False,v2.74-v2.86 呼叫方保持字節級輸出。既有 EnableTaggedPDF / EnableXMPMetadata flag 在新 opt-in 關閉時仍獨立工作。
  • 這是矩陣候選 #1(Tagged PDF / PDF/UA producer-side 充實)的第一刀。後續(v2.88+):AddStructureElement 加 /Alt 和 /ActualText 支援、AddTextField & CurrentPage.TextOut 路徑加頁面內容 BDC / EMC helper、註釋 /StructParents 接入。

2026-05-19 Version 2.86.0

  • 擴展 RegisterUnicodeTTF 的 cmap 解析器支援 OpenType format 12(分段全 Unicode 覆蓋)。v2.75-v2.85 只解析 format 4(傳統 BMP 段映射);含 format 12 的現代字體現在使用更豐富的表。子表選擇優先 format 12 因為它對全 codepoint 範圍都權威。
  • 新 `_TTFParseCmapFormat12` walker:讀 16 字節頭(format / reserved / length / language / numGroups),然後迭代 numGroups 個 12 字節組(startCharCode / endCharCode / startGlyphID)。對範圍內每個 codepoint C,glyph ID = startGlyphID + (C - startCharCode)。每個多字節讀取都做邊界檢查;截斷或畸形的組靜默跳過。
  • 子表打分更新:
    • platform 3 (Microsoft) + encoding 10 (Unicode full) + format 12: 120(最高)
    • platform 0 (Unicode) + encoding 4 或 6 + format 12: 110
    • 其他 format 12: 105
    • platform 3 + encoding 1 (Unicode BMP) + format 4: 100(傳統 BMP 回退)
    • platform 0 + encoding 3..4 + format 4: 80
    • platform 3 + encoding 10 + format 4: 70
    • 其他 format 4: 50
  • SMP 範圍:CpToGid 輸出數組保持 BMP 大小($10000 項 × 2 字節 = 128 KB),因為我們的 Identity-H 編碼使用 2 字節 CID(0..65535)。format 12 SMP 條目(U+10000+)被解析但不存儲;format 12 walker 迭代前把 endCharCode 截到 $FFFF。/CIDToGIDMap 全 SMP 覆蓋需要不同編碼(Identity-V + surrogate-pair CMap 或 Adobe-Japan1),不在本刀範圍。
  • 使用者可見影響:只附 format 12 的字體(某些現代 CJK 字體、Segoe UI Emoji / Symbol)現在能正確填充 /W、/CIDToGIDMap、/FontFile2 和 v2.84 subsetter。v2.86 之前這些字體走 cmap 解析的靜默回退、跳過全部四個流的發射,回到 v2.74 僅 metric 的結果。
  • 字節級穩定:只有 format 4 的字體(Arial、Tahoma)仍走同一代碼路徑產生相同的 CpToGid 輸出。同時含 format 4 和 format 12 的字體現在用 format 12 處理 BMP,通常產生相同的 BMP 映射(format 12 是嚴格超集)。v2.74-v2.85 既有 smoke 保持字節級穩定。
  • 本刀完成 v2.4.0-v2.86.0 密集 PDF 規範合規階段。剩餘的 v2.86+ 工作(透過 surrogate-pair CMap 的 SMP 編碼、字體特定 GSUB 風格變體、更高級排版)超出 "基礎 Type 0 / Identity-H + AcroForm Unicode" 範圍,無限期推遲到出現真實使用者需求。

2026-05-19 Version 2.85.0

  • 新增 opt-in Arabic Presentation Form-B 上下文 shaping,透過新 `AutoShapeArabic` 屬性開啟。設為 True 時,3 個 BuildUnicode*FieldContent helper 在 bidi reversal 之前把基本阿拉伯字母(U+0621..U+064A)替換為位置對應的 presentation form(U+FE70..U+FEFF)。消費 PDF 閱讀器不再需要 in-process text shaper(HarfBuzz / FreeType / GSUB binary lookup)在渲染時挑選正確的位置形式。
  • Shaping 算法:掃 logical-order UTF-16 buffer;對每個阿拉伯字母找前一個和下一個非 Transparent 字母(NSM / harakat U+064B..U+065F + alef khanjareeya U+0670 透明)。從 joining-class 上下文判定位置:D(dual-joining:BEH、TEH、SEEN、LAM、MEEM、NOON 等)按周圍 strong 字母是否允許在各自側連接,支援 isolated / initial / medial / final;R(right-joining:ALEF、DAL、ZAL、REH、ZAIN、WAW 等)只支援 isolated / final。
  • 直接使用者影響(AutoShapeArabic=True):輸入 "بسم"(BEH + SEEN + MEEM)emit Tj 攜帶 presentation form FE91(BEH initial)、FEB4(SEEN medial)、FEE2(MEEM final)。RTL reversal 後 Tj operand 是 FEE2 FEB4 FE91,任何 PDF 閱讀器即使沒內置 shaper 也能正確渲染連寫阿拉伯文。
  • 覆蓋範圍:35 個基本阿拉伯字母(HAMZA 變體、ALEF 變體、28 字母阿拉伯字母表、YEH MAKSURA)。靜態 Unicode 標準查表代替字體特定 GSUB binary 解析,所以 shaping 對任何 U+FE70..U+FEFF 塊裡有字形的字體都有效(Arial、Tahoma、Segoe UI Arabic、Noto Sans Arabic、Amiri 等)。
  • 本刀不含:波斯/烏爾都擴展字母(U+0671..U+06D3);LAM-ALEF 連寫字形(FEFB / FEFC);蒙古/敘利亞(不同 shaping 模型);超出 4 位置基本模型的字體特定 GSUB 風格變體。
  • 字節級穩定:AutoShapeArabic 預設 False,所有 v2.74-v2.84 呼叫方保持 byte-identical /AP 輸出。已經上游 pre-shape 的呼叫方(或用消費端 shaper)不受影響。
  • Pipeline 位置:shaping 在每個 Build*UnicodeFieldContent helper 裡 UTF-8 解碼之後、bidi reversal 之前跑,所以 shape 後的 presentation form 在 AutoDetectFormBidi / FormUnicodeRTL 啟用時也能正確 RTL-reverse。
  • 剩餘 UAX #9 工作:SMP cmap format 12(U+10000+ codepoint 在 RegisterUnicodeTTF 中的覆蓋)仍待。

2026-05-18 Version 2.84.0

  • 新增 file-based TrueType subsetter 在 EndDoc 時觸發。RegisterUnicodeTTF + AddTextField 之後,文件在 BuildUnicode*FieldContent emission 過程中累積每 codepoint 的使用集;EndDoc 把已用 codepoint 轉為 glyph ID,走 composite glyph 閉包,重建嵌入字體程序只保留這些 glyph。v2.82 raw embed 被替換;其餘表結構保持有效因為 subsetter 保持 glyph ID 不變(只壓縮 glyf/loca)。
  • 直接使用者影響:嵌入 Unicode TTF 的 PDF 體積顯著縮小。"Hello World" 文件嵌入 Arial 在 v2.82 是 ~350 KB 壓縮;v2.84 降到 ~10-15 KB。CJK 字體典型 1000-3000 glyph 子集從 ~14 MB 壓縮到 ~500 KB-2 MB。
  • Subsetter 算法:保持 glyph ID 不變,cmap、hmtx、/CIDToGIDMap、/W 都仍有效。對每個 glyph index 0..numGlyphs-1,新 glyf 表要麼拷貝原字節(已用)要麼透過 loca[i+1] = loca[i] 發出空條目(未用)。loca 格式(短/長 by head.indexToLocFormat)保留。每表 checksum + head.checksumAdjustment 都按 spec 重算。
  • Composite glyph 閉包:當已用 glyph 的 numContours == -1(composite),subsetter 解析其 component 列表(每 component 的 flags + glyphIndex + 可變 args/transform 跳過),標記 components 為已用,迭代直到無新 glyph 添加。帶邊界檢查防止畸形 composite 鏈導致死循環。
  • Spec 合規:Type 0 dict + CIDFontType2 descendant 的 /BaseFont 和 FontDescriptor 的 /FontName 全部加 6 字母 AAAAAA+ subset 前綴,從已用 glyph 集的確定性 FNV-1a 哈希派生。Spec 9.6.4 要求前綴表明字體程序已 subset;沒有它 spec-strict 閱讀器會警告嵌入字體被修改。
  • 使用跟蹤基礎設施:65536 項 FUnicodeUsedCps[] Boolean 數組在首次 RegisterUnicodeTTF 時 lazy 分配。3 個 BuildUnicode*FieldContent helper(單行/多行/comb)在發射 UTF-16BE hex Tj operand 時標記 code unit。SetFormUnicodeFontDict('', nil) 和後續 BeginDoc 復位時清空。
  • 失敗安全:subsetter 任何一步無法完成(缺表、loca 畸形、composite 閉包失敗、壓縮失敗)就保留 v2.82 raw embed。PDF 仍有效;只是體積沒減。這保留了 v2.82 的可靠性同時在 happy path 上提供 subset 收益。
  • 本刀不含:OpenType GSUB Arabic/Syriac/Devanagari 上下文 joining;SMP cmap format 12(仍僅 BMP)。推到 v2.85+。

2026-05-18 Version 2.83.0

  • 給 RegisterUnicodeTTF 增加 PDF 1.7 ISO 32000-1 9.10.3 /ToUnicode CMap。Type 0 字體字典現在帶 /ToUnicode 間接引用,指向 Adobe-Identity-UCS CMap 流,消費閱讀器能從 PDF 中提取 Unicode 文本。v2.74-v2.82 的 PDF 沒 /ToUnicode 時複製粘貼出來的是原始 CID 索引而不是 Unicode codepoint;屏幕閱讀器讀不出 AcroForm 內容;PDF/A 合規失敗。
  • CMap 結構:最小 Adobe-Identity-UCS CMap,包含 /CIDSystemInfo (Adobe / UCS / 0)、/CMapName /Adobe-Identity-UCS、/CMapType 2、一個 codespacerange 覆蓋 <0000>..<FFFF>、一個 bfrange 把 <0000> <FFFF> 映射到 <0000>(identity)。PostScript CMap 文本透過 FlateDecode 壓縮到 ~150 字節,嵌入開銷可忽略。
  • Identity 映射的理由:v2.74-v2.82 配置是 Identity-H + Adobe-Identity-0 + CID = Unicode codepoint,所以 ToUnicode 反向映射在整個 BMP 範圍內本就是 identity。一個 bfrange 條目覆蓋全部映射;不需要每 codepoint 的 bfchar 列表。
  • 使用者可見影響:從 PDF 閱讀器(Adobe、Foxit、Chrome PDF 閱覽)選擇/複製粘貼文本現在產出原始 Unicode codepoint 而不是 CID 亂碼。屏幕閱讀器(NVDA、JAWS、VoiceOver)能朗讀 AcroForm 文本內容用於無障礙場景。PDF/A-1/2/3 合規現在可達成(PDF/A 要求所有 Type 0 字體必須帶 /ToUnicode)。
  • Pipeline 位置:/ToUnicode 發射在 WArrayValid try/except 塊之外,因為 identity 映射不依賴 cmap 解析成功。即使 /W / /CIDToGIDMap / /FontFile2 因字體表損壞被靜默跳過,/ToUnicode CMap 仍然被髮射且語義正確。
  • 流物件:indirect THPDFStreamObject + /Filter /FlateDecode(無 /Length1,因為 ToUnicode 是文本流不是字體程序)。透過 Result.AddValue('ToUnicode', ...) 掛到 Type 0 wrapper 字典。與 v2.77 /CIDToGIDMap 和 v2.82 /FontFile2 共享 zlib 壓縮模式。
  • 本刀不包含:每 codepoint bfchar 條目(可支援非 identity 映射如 fi → f+i 多字符序列,但我們 Identity 配置從不需要);超出 BMP 的 SMP 覆蓋(仍是 0x0000..0xFFFF 範圍)。這些推到 v2.84+。

2026-05-18 Version 2.82.0

  • 給 RegisterUnicodeTTF 增加 PDF 1.7 ISO 32000-1 9.6.4 + 9.9 /FontFile2 原始字體嵌入。實際字體程序(TTF / OTF 二進制字節)現在以 /FontFile2 流掛在 FontDescriptor 下隨 PDF 一起發出去,消費閱讀器不再需要根據 /BaseFont 名字去 OS / 應用字體緩存裡找對應字體。結果:PDF 自包含,在沒裝該字體的系統上也能正確渲染。
  • 流結構:indirect THPDFStreamObject + /Filter /FlateDecode + /Length1 = 原始字體文件未壓縮字節數(spec Table 124)。壓縮用 TZCompressionStream (zcDefault, windowBits 15) 沿 v2.77 /CIDToGIDMap 模式。典型 Latin TTF 壓縮率 30-50%(例如 700 KB Arial → 350 KB 壓縮嵌入)。
  • Pipeline 集成:嵌入與 v2.75 /W 數組和 v2.77 /CIDToGIDMap 在同一 WArrayValid 分支裡發出,cmap 解析失敗(corrupt subtable / 不支援的 format)三個特性流一起跳過,平滑回退到 v2.74 僅 metric 的結果。
  • 使用者可見影響:v2.74-v2.81 的 PDF 技術上是 Type 0 / CIDFontType2 複合字體,但字體程序缺失。消費閱讀器需要按 /BaseFont (PostScript 名) 在自己字體緩存裡查。裝了同名字體的系統上恰好渲染正確;沒裝的系統上要麼替換為別的字體(錯字形 / 錯度量),要麼渲染佔位方框。v2.82 把字體程序隨 PDF 一起發——同一個 producer 在 RegisterUnicodeTTF 解析過的字體程序——消費渲染與 OS 字體可用性無關,確定性輸出。
  • 權衡:典型 Latin TTF 嵌入後 PDF 增長 ~150-500 KB(壓縮後體積);CJK 字體增長 2-20 MB 壓縮。這正是消費端字體替換原本規避的體積代價,但同時也避免了不確定的渲染。子集化(v2.83+ 續刀)會透過裁掉未用 glyph 減少體積。
  • spec 備註:v2.82 嵌入時 /BaseFont 保留原 PostScript 名(無 "AAAAAA+" subset 前綴),因為我們嵌入完整字體。Spec 9.6.4 的 6 字母前綴僅在字體程序被子集化時使用;v2.83+ 接子集化時會加前綴。
  • 本刀不包含:字體子集化(單個嵌入字體把整個文件體積加進 PDF)、ToUnicode CMap(PDF/A copy-paste)、SMP cmap format 12(U+10000+ codepoint 仍未映射)。這些推到 v2.83+。

2026-05-18 Version 2.81.0

  • 把 UAX #9 W4(數字間分隔符)和 W5(數字鄰接終結符)移植到 LTR 段重排路徑。v2.72.0 / v2.73.0 起這兩個規則只在 RTL 路徑裡 inline 跑;v2.81 抽出共享 helper `_ApplyUAX9W4Rules` 和 `_ApplyUAX9W5Rules`,兩個段落方向都呼叫同一套弱規則變換。
  • 重構:RTL 路徑 Step 1b (W4) 與 Step 1c (W5) inline 代碼替換為單行 helper 呼叫。Helper 接 Wide 字串 + Classes[] 數組 in-place 修改 Classes[];邏輯與 v2.72/v2.73 inline 實現完全一致,因此 RTL 輸出在 refactor 後字節級穩定。
  • LTR 路徑在 W1 NSM 繼承 (Step 1b) 與 W7 (Step 1d) 之間插 Step 1c W4 + Step 1c.2 W5。後續 N 規則 (Step 1e) 與 I 規則 (Step 1f) 重新編號保持 pipeline 顯式有序。
  • LTR 端可見影響:含嵌入 RTL 的混排 LTR 段中,RTL strong 在數字/ET 之前時,W5 現在把 ET 提升為 EN,避免 N1 把它捲進 R run。例如 "Hi shin $1"(LTR 段含 shin Hebrew 字母后跟 "$1")之前輸出為 "Hi $ shin 1" —— $ 被捲進 R run 與 shin 換位。v2.81 輸出 "Hi shin $1" —— $ 保持挨著它的數字。W4 同理:"Hi shin $1,2 widgets" 保留 "$1,2" 作為邏輯整塊,不在逗號處切開。
  • LTR 路徑字節級穩定場景:純 LTR 無 R 前置(如 "12,345 widgets")無可見變更——W7 sor=L 已經把所有 EN 吸收為 L;LTR 段只有 L + RTL 無數字 ET 的輸入也不受影響。既有 v2.79 LTR smoke(smoke_bidi_n_rules_ltr、smoke_bidi_ltr_reorder)繼續字節級透過。
  • Pipeline 順序(RTL 不變):W1 -> W4 -> W5 -> W7 -> N0 -> N1 -> N2 -> I2 -> L2。LTR 現:W1 -> W4 -> W5 -> W7 -> N0 -> N1 -> N2 -> I 規則 -> L2。兩條路徑共享 W4/W5/W7/N rules helper;僅分類(Step 1a)與最終 L2 走法在 RTL 和 LTR 之間不同。
  • 剩餘 UAX #9 工作:OpenType GSUB Arabic/Syriac/Devanagari 上下文 joining、RegisterUnicodeTTF 後續(ToUnicode CMap、SMP cmap format 12、/FontFile2 嵌入 + subsetting)仍待。

2026-05-18 Version 2.80.0

  • 加 Unicode UAX #9 W7 EN 橋接:往回掃到第一個 strong type(L/R/AL)若是 L(或掃到 buffer 起點且 sor=L),則該 EN 類改為 L。W7 在 W4(數字間分隔符)和 W5(數字鄰接終結符)之後跑,覆蓋 W4 把 separator 升級為 EN 後還需被 L 橋接的邊角。
  • RTL 段可見影響:輸入 "Hello 123 Arabic" 在 RTL 段,v2.79 輸出視覺佈局 "Arabic SP 123 SP Hello"——EN run 夾在 L (Hello) 與 AL (Arabic) 之間,N 規則把 LTR phrase 切成兩段獨立 run(中間 SP 停在嵌入 level)。v2.80 W7 把 EN 轉 L(因為 L 在前面),N1 接著吸收 Hello 與 123 間的 SP 進 L run;整個 "Hello 123" 成一個 level-2 子串整體反轉。最終視覺 "Arabic SP Hello SP 123",對齊 UAX #9 嚴格行為。
  • W7 不開火的情況:EN 最近的 strong 是 R 或 AL(Arabic letters 在數字前面);EN 在 buffer 起點 + RTL 段(sor=R);EN 前沒有任何 L。這些場景 v2.79 行為保留——v2.72/v2.73 的 W4/W5 baseline smoke 字節級穩定。
  • LTR 段效果:W7 也在 LTR 路徑跑(spec 一致性),sor=L(掃到起點時)。HotPDF 簡化的單嵌入 LTR I 規則下,L 與 EN 都落 level 0,所以 EN→L 不直接改 Levels[],但確實改 N1 吸收模式:L 與"被橋接的 EN"之間的 SP 現在滿足 N1 同向條件能合併。純 LTR 輸入無內嵌 RTL 時是字節級 no-op;LTR 輸入含尾部 RTL 時(如 "Hello 123 shalom")SP 相對 RTL 塊的位置移一位。
  • W6(按 UAX #9 嚴格定義殘餘 ES/CS/ET → ON)在 HotPDF 簡化 Classes[] 表中隱式落地:ES、CS、ET、WS、ON 都歸 class 0 (bcOther),N 規則統一處理 class 0。W6 的 "升 ON" 在我們模型中是 no-op(N1/N2 不區分 ON 與 WS)。代碼 W7 helper 註釋裡同步說明。
  • Pipeline 順序(RTL 路徑):W1 NSM 繼承 -> W4 數字間 ES/CS -> W5 數字鄰接 ET -> W7 EN 前置 L -> N0 配對括號 -> N1 同向 NI 吸收 -> N2 嵌入預設 -> I2 級別分配 -> L2 反轉-再反轉。LTR 路徑同順序但缺 W4/W5(仍 RTL 唯一;LTR W4/W5 移植是下一個候選)。
  • 新增共享 helper `_ApplyUAX9W7Rules(Classes, ParaIsRTL)`,in-place 修改 Classes[]。掃描跳過 weak/NSM/EN/AN,只 L/R/AL 算 strong;掃到 buffer 起點未找到 strong 時用段落方向(sor)作隱式 strong。RTL 路徑傳 ParaIsRTL=True,LTR 路徑 False。
  • 剩餘 UAX #9 工作:LTR 路徑 W4/W5 移植(當前 RTL 唯一)、OpenType GSUB Arabic/Syriac/Devanagari 上下文 joining、RegisterUnicodeTTF 後續(ToUnicode CMap、SMP cmap format 12、/FontFile2 嵌入 + subsetting)仍待。

2026-05-18 Version 2.79.0

  • 把 v2.78.0 的 N0/N1/N2 規則鏡像到 LTR 段重排路徑。修復對稱 bug:多詞 RTL phrase 嵌入 LTR 段(比如英文句子含多個 Hebrew/Arabic 詞帶詞間空格)時,RTL 讀者看到的詞序倒——之前詞間空格停在 level 0,把 RTL phrase 切成多段獨立 R run。v2.79 N1 把空格吸收進周圍 R run,整個 phrase 成一個 level-1 子串,L2 反轉保留詞的邏輯順序。
  • 重構 LTR 段路徑(`_ApplyUAX9L2ReversalLTRPara`)使其結構與 RTL 段對齊:先把每個 UTF-16 code unit 分類到 Classes[] 字節數組,再在 Classes[] 上做 W1 NSM 繼承(v2.79 前是直接在 Levels[] 上做),呼叫共享 helper `_ApplyUAX9NRules`(接受嵌入方向參數:1=L 用於 LTR 段、2=R 用於 RTL 段);I 規則再從 Classes[] 推 Levels[]。RTL 與 LTR 兩條路徑現共享單一 N 規則實現。
  • 共享 helper `_ApplyUAX9NRules(Wide, Classes, EmbedDirCls)` 把嵌入方向作為類參數(1 或 2),統一應用 N0 配對括號解析 + N1 同向 NI 吸收 + N2 嵌入預設。RTL 路徑傳 2 (R);LTR 路徑傳 1 (L)。v2.78 RTL 端行為字節級保留。
  • LTR 端可見影響:"Hi shalom olam World"(邏輯輸入 H i SP shin lamed vav final-mem SP ayin vav lamed final-mem SP W o r l d)之前輸出把兩個 Hebrew 詞相對位置換位(每個詞內部正確反轉,但詞與詞的相對位置錯了)。v2.79 保留邏輯詞序——RTL 讀者看到的 Hebrew chunk 內順序與預期一致。括號包裹的多詞 RTL phrase 透過 N0 + N1 協作同樣修復。
  • LTR 段 pipeline 順序(鏡像 RTL):分類到 Classes[] -> W1 NSM 繼承 -> N0 配對括號 -> N1 同向 NI 吸收 -> N2 嵌入預設 -> I 規則(推 Levels[])-> L2 反轉 level-1 run。W4/W5 數字處理 pass 還沒移植到 LTR 路徑;LTR 段中含數字 + 分隔符的輸入直接走 N 規則。
  • 既有 LTR smoke 字節級穩定:純 LTR ASCII、LTR 段中單詞 RTL、RTL + LTR 混排但 RTL 詞間無空格——重構後產生相同 Levels[](W1 NSM 繼承在 Levels[] 上做與在 Classes[] 上做對外輸出可觀測等價)。v2.67 / v2.69 / v2.71 的 LTR smoke 繼續字節級透過。
  • 剩餘 UAX #9 工作:W6/W7 殘餘弱類清理、W4/W5 LTR 路徑數字處理(當前 RTL 唯一)、OpenType GSUB Arabic/Syriac/Devanagari 上下文 joining、RegisterUnicodeTTF 後續(ToUnicode CMap、SMP cmap format 12、/FontFile2 嵌入 + subsetting)仍待。

2026-05-18 Version 2.78.0

  • 給 RTL 段重排 pipeline 加 Unicode UAX #9 簡化 N0 配對括號解析 + N1 同向 strong 中間中性類吸收 + N2 殘餘中性回退到嵌入方向。修復 HotPDF 之前的可見 bug:多詞 LTR phrase 嵌在 RTL 段(比如 Hebrew/Arabic 段裡夾帶英文短語帶詞間空格)時,詞序會倒——因為空格停在嵌入級別(level 1)、把 LTR phrase 切成多段獨立 L run。N1 把空格吸收進周圍 L run,整個 phrase 成一個 level-2 子串,L2 反轉-再反轉後保留邏輯順序。
  • N0 配對括號:覆蓋 22 個 BMP 括號對,從 ASCII 圓/方/花括號到數學/排印(ceiling、floor、math 角括號、math 白方括號、白花括號)到 CJK 標點括號(角括號、雙角括號、corner、白 corner、黑/白 lenticular、tortoise shell、白 tortoise、白方)再到全角形式。BD16 棧式配對檢測(按 spec 上限 63 條);配對解析掃描內部第一個強方向(L、R、AL、EN、AN——其中 EN/AN 按 spec 算 R 類),如果內部方向與嵌入方向不一致則查左側(開括號之前)的強方向上下文作為回退。
  • N1 吸收:掃描 Classes[] 找 bcOther 的最長 run,看左右兩側(跳過 NSM)非中性強方向,兩側方向影響一致(都是 L,或都是 R 等價:含 EN/AN)則整 run 取該方向。實際影響:嵌在 Arabic/Hebrew 段裡的英文短語中的空格、逗號、句號、冒號現在被歸到 phrase 而不是把它切碎。
  • N2 預設:未被 N0/N1 處理的 bcOther 取嵌入方向。RTL 段取 R(class 2)。N2 後 Classes[] 全部落到 {1..6},I2 不再依賴 bcOther 預設 level 1。
  • 使用者可見影響:之前 HotPDF 把 "aleph aleph SP a b c SP d e f SP aleph aleph"(邏輯輸入:英文 phrase "abc def" 嵌在 RTL 段)輸出為 "aleph aleph SP d e f SP a b c SP aleph aleph"——詞被換位(因為詞間空格停在 level 1)。v2.78 輸出 "aleph aleph SP a b c SP d e f SP aleph aleph"——phrase 完整保留。嵌入 phrase 周圍的括號透過 N0 + 消費端 L4 mirror 正確渲染。
  • Pipeline 順序:W1 NSM 繼承 -> W2/I2(EN/AN BIDI 表分類,不在本 pass)-> W4 數字間 ES/CS -> W5 數字鄰接 ET -> N0 配對括號 -> N1 同向吸收 -> N2 嵌入預設 -> I2 級別分配 -> L2 反轉-再反轉。N 規則夾在 W 與 I 之間;既有 W 規則輸出餵給 N 規則作輸入。
  • 對沒有 RTL 段嵌入多詞 LTR phrase 的既有 smoke 字節級穩定:純 RTL、純 LTR(函數原樣返回)、單詞 LTR 嵌 RTL(沒有內部中性需要吸收)、Arabic + 格式化數字(帶空格 + 逗號)——空格從 bcOther 變 R-等價但級別相同,L2 反轉輸出不變。v2.66/v2.67/v2.68/v2.71/v2.72/v2.73 基線 smoke 繼續字節級透過。
  • 剩餘 UAX #9 工作:W6/W7 殘餘弱類清理、LTR 段的 N 規則鏡像(多詞 RTL phrase 嵌入 LTR 段)、OpenType GSUB Arabic/Syriac/Devanagari 上下文 joining、RegisterUnicodeTTF 後續(ToUnicode CMap、SMP cmap format 12、/FontFile2 嵌入 + subsetting)仍待。

2026-05-18 Version 2.77.0

  • 給 RegisterUnicodeTTF 增加 PDF 1.7 ISO 32000-1 9.7.4.2 /CIDToGIDMap 流。每個 BMP Unicode codepoint(CID)現在映射到嵌入字體程序內真正的 glyph index。v2.77 之前,HotPDF 的 Type 0 / CIDFontType2 + Identity-H 配置沒寫 /CIDToGIDMap 條目,按 spec 預設為 /Identity——消費閱讀器直接拿 CID 當字形表索引,結果幾乎每個字符都映射到錯誤的字形(真字體字形表裡 glyph index N 幾乎從不等於 Unicode codepoint N)。
  • 實現複用 v2.75 /W 數組已做的 cmap 解析。CpToGid[0..$FFFF] 內存表序列化為 131072 字節大端流(每個 CID 2 字節)並 FlateDecode 壓縮;典型真字體壓縮率 80-95%(絕大多數 BMP codepoint 無字形映射、序列化為 0x0000)。壓縮後流以間接物件形式掛到 CIDFontType2 descendant 字典的 /CIDToGIDMap 條目。
  • 使用者可見影響:用 RegisterUnicodeTTF + SetFormUnicodeFontDict + AcroForm Tx widget 生成的 PDF,現在消費閱讀器渲染的字形與源字體原生渲染一致。v2.77 之前依賴 /Identity 預設值的 PDF 在 spec 嚴格的閱讀器上肉眼可見地渲染錯誤(應該出現的 Latin / 數字 / 標點位置出現隨機字形);那些回退到透過 Unicode 解讀 cmap 的閱讀器恰好渲染正確——但走的是非標準 fallback 行為。
  • Pipeline 位置:/CIDToGIDMap 構造在 v2.75 同一 WArrayValid 分支裡建 /W 時進行,兩條掛接共享 cmap walk,新增的只有第二次壓縮。cmap / hmtx / maxp 解析失敗時,silent fallback 同時跳過 /W 和 /CIDToGIDMap;消費閱讀器看到 v2.77 之前的字典並回退到自己的預設 cmap 解讀。
  • 本刀不包含(推到 v2.78+):SMP cmap format 12(U+10000+ codepoint 在表裡仍映射為 GID 0)、/FontFile2 流嵌入(消費閱讀器仍按 /BaseFont 名透過自己的字體匹配機制解析)、字體子集化(128 KB 原始映射表覆蓋全 BMP)、ToUnicode CMap(複製/粘貼 + 屏幕閱讀器往返)。

2026-05-18 Version 2.76.0

  • 把 v2.75.0 的 TTF /W advance-width 數組接進 HotPDF 自身的 multiline word-wrap 算法。v2.65.0 BuildUnicodeMultilineFieldContent.CodeUnitAdvance helper 現在查 RegisterUnicodeTTF 填充的 per-codepoint advance 緩存,取代 0.5/1.0 narrow/wide 啟發式。producer 端斷行現在與 consumer 端 /W 渲染對齊:HotPDF 選的 wrap 點與消費閱讀器渲染 /Tj 時實際換行位置一致。
  • 新增私有欄位:FAcroFormUnicodeAdvances(dynamic Word 數組,大小 65536 或 0)緩存每 codepoint 的 advance 寬度(PDF 設計單位,1000 per em)。FAcroFormUnicodeAdvancesActive 標誌區分 "緩存已被 RegisterUnicodeTTF 填充" 與 "未載入字體(回退到啟發式)"。RegisterUnicodeTTF 在構建 /W 數組的同一次 hmtx + cmap 遍歷中填這兩個欄位,不需要額外解析。
  • CodeUnitAdvance 查找順序:若 FAcroFormUnicodeAdvancesActive 且緩存對該 code unit 有非零條目,把縮放後寬度除以 1000.0 作為 em 分數返回;否則回退到 v2.65 啟發式(ASCII / Latin-1 narrow,CJK / Hangul / Hiragana / Katakana / 全角寬 wide)。Surrogate pair 半邊仍走啟發式(緩存僅覆蓋 BMP)。
  • 緩存生命週期:THotPDF.Create 時清空 / inactive,SetFormUnicodeFontDict('', nil) 顯式重置時清空,每次後續 RegisterUnicodeTTF 呼叫時重新填充。佔 128 KB(64K codepoint * 2 字節)僅在載入過 TTF 時;從未用過 Unicode 字體的實例零內存代價。
  • RegisterUnicodeFontDict(v2.70.0)和無 /W 數組的 RegisterUnicodeTTF(v2.74.0,比如 maxp / cmap / hmtx 表缺失)讓緩存保持空 / inactive,multiline word-wrap 回退到 v2.65 啟發式——這些路徑輸出與 v2.65 字節級一致。
  • 使用者可見影響:用典型 Latin 字體(Arial、Segoe UI、Times)的 multiline AcroForm Tx widget 現在在與消費閱讀器實際渲染一致的字符邊界換行。v2.76 之前,v2.65 啟發式把每個 ASCII 字符當 0.5 em 寬;真實字體中 "M" ~0.8 em、"i" ~0.3 em,啟發式高估/低估 30-60%,導致消費閱讀器換行與 HotPDF 規劃不符,造成文本溢出或短行。
  • Single-line BuildUnicodeTextFieldContent 和 comb BuildUnicodeCombFieldContent 不用 CodeUnitAdvance,本刀不影響(單行無 wrap,comb 用等寬 cell)。
  • 本刀不包含:SMP cmap format 12(U+10000+ codepoint 仍按 surrogate 半邊走啟發式)、ToUnicode CMap、/FontFile2 流嵌入、字體子集化。這些推到 v2.77+。

2026-05-18 Version 2.75.0

  • 擴展 v2.74.0 的 THotPDF.RegisterUnicodeTTF,加入 hmtx + maxp + cmap 三表解析,讓生成的 CIDFontType2 descendant 攜帶按 codepoint 真實數值的 /W advance-width 數組。消費閱讀器現在按真實字體度量渲染文本寬度,不再對每個字形回退 /DW = 1000——AcroForm /AP 外觀流中的文本與源字體渲染寬度一致。
  • 新增 unit-level helper 解析三張額外 SFNT 表:_TTFParseMaxpNumGlyphs(從 maxp 讀 numGlyphs)、_TTFParseHmtxAdvances(按 hhea 的 numberOfHMetrics 大小生成每字形 advance-width 數組)、_TTFFindAndParseCmap + _TTFParseCmapFormat4(透過 BMP segment-mapping format 4 子表查 Unicode codepoint -> 字形 ID)。_TTFBuildWArray 拼裝 PDF 1.7 9.7.4.3 form 1 稀疏 /W 數組:把連續非預設寬度 codepoint 合併成 [startCID [w1 w2 w3 ...]] run,跳過寬度等於 /DW = 1000 的 codepoint 以裁剪數組大小。
  • cmap 子表選擇優先 Microsoft Unicode BMP(platform 3, encoding 1, format 4)——Windows 字體通用 cmap 佈局。回退到 Unicode platform(0, encoding 3 或 4)覆蓋跨平臺 OpenType 字體,再到 platform 3 encoding 10(Unicode full / 僅 format 4),最後任意 format 4。非 format 4 子表(format 0/2/6/8/12/13/14)在本刀忽略——SMP 透過 format 12 推到 v2.76+。
  • /W 數組透過直接走樹掛到 CIDFontType2 descendant:Type0 -> /DescendantFonts -> [0] -> AddValue('W', WArray)。v2.70 RegisterUnicodeFontDict 簽章不變;descendant 字典在裝配後原地修改。
  • hmtx 的 FUnit 寬度按 head 表 unitsPerEm 縮放到 PDF 設計單位(1000 per em)。cmap 無映射(返回 0 / .notdef)的 codepoint 當作 DW = 1000 處理,從 /W 中省略。典型 Latin 字體(Arial、Segoe UI、Times)產出的 /W 含 500-1500 條 codepoint;CJK 字體可達 10K+ 條。
  • 本刀不包含(推到 v2.76+):/W 寬度資料尚未被 HotPDF 自身的 multiline word-wrap 算法消費——v2.65 BuildUnicodeMultilineFieldContent 仍用 0.5/1.0 窄/寬啟發式做斷行計算;/W 數組純粹用於消費端渲染精度。完整 producer 端 perfect-wrap(用 /W 驅動 wrap 計算)推到 v2.76+。也推後:ToUnicode CMap(cmap 反向映射)、/FontFile2 流嵌入、字體子集化、SMP cmap format 12。
  • /W 解析帶 try/except 回退——maxp / cmap / hmtx 缺失或任一子表畸形時,RegisterUnicodeTTF 靜默繼續使用 v2.74 僅含 metric 的結果;消費閱讀器對每個 codepoint 回退 /DW = 1000。無 silent 損壞:表讀取的每個多字節都有邊界檢查。

2026-05-18 Version 2.74.0

  • 新增 THotPDF.RegisterUnicodeTTF,基於文件路徑的 v2.70.0 RegisterUnicodeFontDict 包裝:載入 TTF / OTF 字體文件,解析 head、hhea、OS/2、post 和 name 表,把 FUnit 度量縮放成 PDF 設計單位(每 em 1000),把數值交給 RegisterUnicodeFontDict 完成 Type 0 / CIDFontType2 + Identity-H 複合字體字典構造。返回的字典直接給 SetFormUnicodeFontDict 用——呼叫方不再需要知道字體的精確 metric 值,也不必懂 SFNT 二進制格式。
  • API:RegisterUnicodeTTF(FontPath, LogicalName='')。FontPath 是 .ttf / .otf 文件的絕對或相對路徑。LogicalName 保留給 v2.75+(屆時可用於區分同 PostScript 名的字體)。
  • 解析的表:head(unitsPerEm,FontBBox xMin/yMin/xMax/yMax in FUnits)、hhea(ascender、descender in FUnits)、OS/2(usWeightClass 用於估算 /StemV、sCapHeight、fsSelection 用於 italic bit)、post(italicAngle 從 FIXED 16.16 轉角度、isFixedPitch -> /Flags bit 1)、name(PostScript 名取自 nameID 6 的 Windows 或 Mac 平臺記錄,回退到 nameID 4 的完整字體名)。每個表偏移/長度 + 每次多字節讀取都有邊界檢查,畸形字體拋清晰異常而不是內存錯誤。
  • 自動導出的 metrics:/FontBBox L/B/R/T 縮放到 PDF 設計單位、/Ascent + /Descent 縮放、/CapHeight 從 OS/2 sCapHeight(version < 2 時回退到 ascent)、/ItalicAngle 從 post.italicAngle、/StemV 估算為 50 + (usWeightClass - 400) / 5 限制在 [50, 250]、/Flags = Symbolic + FixedPitch(post 說是)+ Italic(fsSelection bit 0 置位或 italicAngle != 0)。/BaseFont 用解析的 PostScript 名;name 表無可用名時回退 "UnnamedTTF"。
  • 異常分支(帶描述消息):文件缺失、size 不合理(< 12 字節或 > 64 MB)、無法識別的 sfntVersion(必須是 0x00010000 / 'OTTO' / 'true' / 'typ1')、缺必需表(head / hhea / OS/2 / post / name)、表小於所需欄位。
  • 本刀不包含(推到 v2.75+):/W advance-width 數組從 hmtx 讀出(需要 maxp 提供 numGlyphs + cmap 提供 Unicode -> glyph 映射;今 v2.65 multiline word-wrap 仍用 0.5/1.0 啟發式)、ToUnicode CMap 從 cmap 反向(今 v2.56+ Identity-H 映射假定 CID == Unicode codepoint)、把字體原字節嵌入為 /FontFile2 流、字體 subsetting。v2.74.0 階段消費閱讀器仍需透過自身 font-matching 解析 /BaseFont 名。
  • Smoke smoke_unicode_ttf.dpr 載入 Windows 系統字體(按順序探測 %SystemRoot%\Fonts 下 arial.ttf / segoeui.ttf / times.ttf / verdana.ttf)驗證 RegisterUnicodeTTF 返回攜帶文件解析 metric 的 Type 0 字典。Verifier 檢查結果 /BaseFont 不是 stub 佔位、FontBBox / Ascent / Descent / ItalicAngle 在真實字體合理範圍。

2026-05-18 Version 2.73.0

  • 新增 Unicode UAX #9 簡化 W5(European Terminator 鄰接 European Number)規則,應用於 RTL 段落。修復 Arabic 文本含貨幣 / 百分號時的可見 bug——"$12.50"、"50%"、"€100"、"شار 12.50$ ريال"——之前貨幣符號或百分號字形在數字子串與周圍 RTL 文本的邊界處孤立漂移。v2.73 W5 讓鄰接數字的 ET 加入數字 run 一起反轉,在 RTL 段落裡保留 "貨幣 + 數字" 單元作為一個 LTR 子串。
  • 識別的 W5 ET(codepoint 集):U+0023 # (number sign)、U+0024 $ (dollar)、U+0025 % (percent)、U+00A2..U+00A5 (¢ £ ¤ ¥)、U+00B0 ° (degree)、U+00B1 ± (plus-minus)、U+066A ٪ (Arabic percent)、U+2030..U+2031 (‰ ‱ per-mille / per-ten-thousand)、U+20A0..U+20CF (Currency Symbols block 含 € ₹ ₽ ₩ 等)。任一側(跳過 NSM)有 EN 的 ET 序列整體轉換為 EN。
  • 規範擴展:HotPDF 簡化 W5 同時把鄰接 AN(Arabic-Indic 數字)的 ET 轉換為 AN,超出 spec 的 "僅 EN" 限制。這讓 ASCII 和 Arabic-Indic 數字上下文對 ET 處理對稱——"٥٠٪"(Arabic-Indic 50 + Arabic percent)和 "50%"(ASCII)行為一致。
  • 具體修復:"شار $12.50 ريال"(logical UTF-16 0634 0627 0631 0020 0024 0031 0032 002E 0035 0030 0020 0631 064A 0627 0644)。v2.72 輸出:0644 0627 064A 0631 0020 0031 0032 002E 0035 0030 0024 0020 0631 0627 0634——$ 字形孤立在 memory 位置 11,介於數字子串與尾部空格之間,讀起來彆扭。v2.73 輸出:0644 0627 064A 0631 0020 0024 0031 0032 002E 0035 0030 0020 0631 0627 0634——"$12.50" 完整保持為 RTL 流中的一個 LTR 子串。
  • BIDI_Class 表修正:U+066A ARABIC PERCENT SIGN 從 bcAL 移到 bcOther(以便 W5 ET pass 能識別並轉換它)。Arabic block 查表現在包含數字區段(bcAN)、harakat / shadda 塊(bcNSM)、alef khanjareeya(bcNSM)、十進制 / 千分位分隔符(bcAN)和百分號(bcOther + 經 W5 處理為 ET)。
  • 管線順序:W1 NSM 繼承(LTR 路徑顯式,RTL 隱式)-> W4 數字間 ES/CS -> W5 數字鄰接 ET -> I2 級別分配。W5 在 W4 之後執行,讓經 W4 轉成 EN 的分隔符也被 W5 視為 "EN 鄰接",複雜的 "數字 + 分隔符 + 貨幣" 表達式在單次管線遍歷中完整解析。
  • 不含 ET 鄰接數字的輸入字節級與 v2.72 輸出一致。現有 v2.59-v2.72 smoke(RTL Arabic / Hebrew / SMP RTL / NSM positioning / LTR-para reorder / 數字處理 / W4)全部 byte-stable。
  • 剩餘 UAX #9 工作(W6 / W7 cleanup、N0 bracket pair via UAX #9 BD16 stack scan、N1 / N2 neutral resolution、OpenType GSUB Arabic / Syriac contextual joining、文件級 RegisterUnicodeTTF)仍排在後續版本。

2026-05-18 Version 2.72.0

  • 新增 Unicode UAX #9 簡化 W4(ES / CS 在兩個同類型數字之間轉換)規則,應用於 RTL 段落。修復 Arabic 文本含格式化數字時的可見 bug——"السعر 12,345 ريال"(帶千分位逗號的價格)、"12.50"(小數點)、"12:30"(時間冒號)——之前在反轉的 /Tj 輸出中數字 run 被分隔符切開,產生在 RTL 流中倒著讀的視覺錯亂數字。v2.72 W4 讓分隔符加入數字 run,兩者一起反轉一次再隨整體一起反轉一次,在 RTL 段落裡保留數字 + 分隔符的 logical 順序。
  • 識別的 W4 分隔符:European Separator U+002B (+) / U+002D (-)、Common Separator U+002C (,) / U+002E (.) / U+002F (/) / U+003A (:) / U+00A0 (NBSP)、Arabic Common Separator U+060C(阿拉伯逗號)。每個在被兩個 EN 包圍時轉成 EN,在被兩個 AN 包圍時轉成 AN。混合類型相鄰(EN + AN 或 數字 + 非數字)保持分隔符為 bcOther / level 1 / 周圍 RTL 流不變。完整 UAX #9 W4 簡化點:跨 NSM 的 peek 已處理(緊鄰分隔符的 NSM 不會破壞 W4 查找),但多個分隔符連續時是逐位置變換而不是 spec 的 "單個" 分隔符限定(實際場景影響很小,因為真實數字很少有相鄰分隔符)。
  • 具體修復:"شار 12,345 ريال"(logical UTF-16 是 阿拉伯字母 空格 "1" "2" "," "3" "4" "5" 空格 阿拉伯字母)。v2.71 輸出:0644 0627 064A 0631 0020 0035 0034 0033 002C 0031 0032 0020 0631 0627 0634——數字被逗號切開、每段單獨反轉("345" 在 "12" 前),使用者在 LTR 子串內讀到 "345,12"。v2.72 修復後:0644 0627 064A 0631 0020 0031 0032 002C 0033 0034 0035 0020 0631 0627 0634——"12,345" 完整作為一個 LTR 子串,使用者按數值自然順序閱讀。
  • BIDI_Class 表修正(v2.72.0):U+066B ARABIC DECIMAL SEPARATOR 和 U+066C ARABIC THOUSANDS SEPARATOR 現按 Unicode UnicodeData 正確分類為 bcAN(返回值 5),不再分類為 bcAL。這兩個分隔符規範上屬於 Arabic 數字格式化的一部分,因此在 L2 重排時自然加入 Arabic-Indic 數字 run,不需要 W4 pass。U+066A ARABIC PERCENT SIGN 現歸 bcAL(佔位;規範的 ET / European Number Terminator 處理推遲到 W5)。
  • 內部重構:_ApplyUAX9L2Reversal 的 level-assignment 步驟現在構建一個顯式的 Classes[] 並行數組(每個 UTF-16 code-unit 位置一字節),讓 W4 pass 不必重新解碼 codepoint 就能 peek 相鄰 class。Surrogate-pair codepoint 的 Classes[] 和 Levels[] 字節在 high + low 兩半共享。_ApplyUAX9L2ReversalLTRPara 的同類重構被推遲(W4 在 LTR 段無可見影響,因為簡化單嵌入級別模型裡 EN / AN 在 LTR 段已經在 base level 0)。
  • 不含 W4 分隔符(在兩個同類型數字之間)的純 RTL / LTR / 混合文本字節級與 v2.66 至 v2.71 輸出一致。現有 v2.59-v2.71 smoke(RTL Arabic / Hebrew / SMP RTL / NSM positioning / LTR-para reorder / 數字處理 / detector)全部 byte-stable。
  • 剩餘 UAX #9 工作(W5 ET 鄰接 EN、W6 / W7 cleanup、N0 bracket pair via UAX #9 BD16 stack scan、N1 / N2 簡化中性解析、OpenType GSUB Arabic / Syriac contextual joining、文件級 RegisterUnicodeTTF)仍排在後續版本。

2026-05-18 Version 2.71.0

  • 修復 Arabic / Hebrew 文本重排中的 NSM(non-spacing mark,非間距標記)位置 bug。原先 naive 整串反轉把 combining mark(Arabic 的 fatha / kasra / damma / shadda 等 harakat;Hebrew 的 sheva / kamatz / patah 等 niqqud;以及 U+0300..U+036F 的 Latin combining diacritic)移到了被 /Tj 反轉串裡基字符的錯誤一側。PDF 閱讀器的 combining-mark 渲染器隨後把 NSM 附著到了顯示順序中前面的那個字形上——錯的 base。肉眼可見的 bug:"ALEF + FATHA + BA"(阿拉伯文)會把 fatha 渲染到 BA 字形上,而不是 ALEF 上。
  • 新增 UAX #9 W1 簡化的 NSM 繼承規則 + 三種 L2 重排算法(RTL 段 step 2 + step 3,LTR 段單遍)共享的 group-aware 反轉通道。反轉通道現在把 [base, NSM*] 視為一個單元:當 R→L 遍歷時 NSM 被推入棧,遇到下一個非 NSM base 時棧按 logical 順序 flush 到輸出,緊跟在該 base 之後。Surrogate pair 仍跨整個反轉通道保持完整,SMP 範圍內的 NSM(罕見)也按對稱方式處理。
  • 具體修復:"ALEF + FATHA + BA"(logical UTF-16 0623 064E 0628)此前 emit 為 0628 064E 0623(整串反轉,fatha 跑到了 BA 和 ALEF 之間)。v2.71.0 NSM-aware 反轉後同樣輸入 emit 為 0628 0623 064E——BA 在左、ALEF 在中、FATHA 緊跟 ALEF 之後,渲染器正確將其附著到 ALEF。
  • 內部 BIDI_Class 表擴展 bcNSM 類(返回值 6)覆蓋主要 combining-mark 區段:通用 Combining Diacritical Marks U+0300..U+036F(Latin / 通用 accent)、Hebrew niqqud U+0591..U+05BD 及散落的 U+05BF / U+05C1..U+05C2 / U+05C4..U+05C5 / U+05C7(從 Hebrew R 範圍中切出)、Arabic harakat U+064B..U+065F 與 alef khanjareeya U+0670(從 Arabic AL 範圍中切出)。NSM 仍在段落方向 P2/P3 第一-strong 掃描中被跳過。
  • 對 LTR 段落,在初始 level 分配後增加一個顯式的 W1 NSM-level-繼承 pass:每個 NSM codepoint 採用前一個非 NSM codepoint 的 level,讓跟在 AL base 後面的 Arabic NSM 加入該 base 的 level-1 run 一起進入單遍 L2 反轉。RTL 段落裡這個繼承隱式發生(NSM 和 R / AL 在簡化的單嵌入級別模型裡都已經解析到 level 1),不需要單獨的 W1 pass。
  • 不含 NSM 的純 RTL / LTR / 混合輸入字節級與 v2.66 / v2.67 / v2.68 / v2.69 / v2.70 輸出完全一致(沒 NSM 就沒行為變更)。現有 v2.59 RTL Arabic / v2.66 LTR-in-RTL / v2.67 LTR-para / v2.68 EN-AN / v2.69 SMP-RTL smoke 全部 byte-stable。
  • 剩餘 UAX #9 工作(W3-W7 詳細弱類轉換、N0-N2 中性 + bracket-pair 解析、OpenType GSUB Arabic / Syriac contextual joining、文件級 RegisterUnicodeTTF)仍排在後續版本。

2026-05-18 Version 2.70.0

  • 新增 THotPDF.RegisterUnicodeFontDict helper,一次呼叫即可構建完整的 PDF 1.7 ISO 32000-1 9.7 / 9.7.6 Type 0 / CIDFontType2 + Identity-H 複合字體字典。使用 v2.56.0 SetFormUnicodeFontDict AcroForm /AP 路徑的呼叫方不再需要手寫 ~30 行 CIDSystemInfo / FontDescriptor / CIDFontType2 / Type 0 / Identity-H 子字典構造代碼。返回一個間接 THPDFDictionaryObject,可直接傳給 SetFormUnicodeFontDict。
  • API:RegisterUnicodeFontDict(BaseFont, FontBBoxL/B/R/T, Ascent, Descent, CapHeight, ItalicAngle, StemV, Flags, DefaultWidth)。所有 metric 參數都有合理預設值(CJK / Arabic 嵌入字體典型幾何:FontBBox [-1000 -300 2000 1300]、Ascent 1000、Descent -300、CapHeight 750、StemV 100、Flags 4 = Symbolic、DW 1000)。Latin / Hebrew / Cyrillic 等字體可單獨覆蓋任一參數(更小 bbox、Flags = 32 非 symbolic 等)。
  • 構建的字典結構與 v2.59-v2.69 各 smoke_acroform_cid_rtl / smoke_bidi_* 中使用的 spec-correct Type 0 + CIDFontType2 佈局完全一致:Adobe / Identity / Supplement 0 的 CIDSystemInfo、含全部 9.8.2 必需項的 FontDescriptor、Identity-H 編碼、DescendantFonts 數組中的 CIDFontType2 後代字典、/DW 預設字符寬度。/CIDToGIDMap 在未顯式指定時預設為 /Identity(CID == GID),這是 Identity-H + Adobe-Identity-0 ordering 的隱含約定。
  • 後續 v2.71+ 計劃新增基於文件的 RegisterUnicodeTTF:解析 .ttf / .otf,提取真實 metric 和 hmtx /W advance 寬度數組實現 perfect-wrap、把字體作為 /FontFile2 嵌入、從 cmap 生成 ToUnicode CMap,內部複用 RegisterUnicodeFontDict 處理字典結構部分。

2026-05-18 Version 2.69.0

  • 擴展內部 Unicode BIDI_Class 查找表,覆蓋 SMP(Supplementary Multilingual Plane)右向腳本區段 U+10800..U+10FFF。段落方向檢測和 L1-L2 重排現在正確識別 Phoenician(腓尼基)、Imperial Aramaic(帝國阿拉米)、Palmyrene、Nabataean、Hatran、Lydian、Meroitic Hieroglyphs / Cursive、Kharoshthi、Old South Arabian、Old North Arabian、Manichaean、Avestan、Inscriptional Parthian / Pahlavi、Psalter Pahlavi、Old Turkic、Old Hungarian、Hanifi Rohingya(AL,緬甸 Rohingya 語言當今實際使用的腳本)、Garay、Yezidi、Arabic Extended-C(AL)、Old Sogdian、Sogdian、Old Uyghur、Chorasmian、Elymaic 等。
  • SMP RTL 段落現在透過 DetectBidiParagraphDirection 自動識別為 RTL(第一個 strong 字符掃描穿越 surrogate pair 匹配相應的 R / AL 類),並按 v2.66 RTL L1-L2 路徑產出視覺順序的 UTF-16BE Tj 輸出。LTR 段中嵌入的 SMP RTL 子串如果設置了 EnableLTRParaReorder(v2.67 opt-in)也會被反轉;否則按 logical 順序輸出由消費閱讀器的 intrinsic BIDI 處理。
  • Surrogate pair 在所有 L2 反轉中持續保對:SMP RTL codepoint 在 /Tj hex 流中保持完整的 high+low 對,同時段落整體正確重排。
  • v2.67 smoke 測試(smoke_bidi_ltr_reorder)斷言 #7 原本用 U+10840 IMPERIAL ARAMAIC LETTER ALEPH 演示 "LTR 段中 SMP codepoint 當作 bcOther 處理"。本次發佈同步更新該斷言以反映現在正確的 bcR 分類:LTR 段中的 U+10840 變成 level-1 R/AL run 的一部分,會與鄰近的 Hebrew / Arabic 子串一起被重排到視覺位置。
  • 剩餘 UAX #9 工作(W1 NSM 繼承 + W3-W7 弱類型轉換 + N0-N2 中性 + bracket pair 解析 + I1 顯式級別解析 + OpenType GSUB Arabic / Syriac contextual joining)仍排在後續版本。SMP RTL 覆蓋落地後,所有標準化 Unicode RTL 腳本現在都能正確分類用於段落方向和基本 L1-L2 重排。

2026-05-18 Version 2.68.0

  • 修復 Arabic / Hebrew 段中嵌入數字的方向顯示 bug。新增 Unicode UAX #9 弱類 BIDI_Class:European 數字(EN,U+0030..U+0039)和 Arabic-Indic 數字區段(AN,U+0660..U+0669 + U+06F0..U+06F9)現在被單獨識別。簡化 UAX #9 I2 + L2 級別分配:RTL 段中這些數字 codepoint 現在取 resolved level 2(與嵌入 LTR 子串相同),而不是和周圍 RTL 文字一起被當作 level 1。兩遍 L2 重排因此保留數字在視覺 RTL 流裡的 logical 順序,與符合規範的 "شارع 12345" 使用者閱讀體驗一致——即使 PDF /Tj 流是按 LTR 渲染的。
  • 具體修復:輸入 "شار 12345"(logical UTF-16 0634 0627 0631 0020 0031 0032 0033 0034 0035)此前 Tj operand 輸出為 0035 0034 0033 0032 0031 0020 0631 0627 0634(整串反轉——數字被倒置,是肉眼可見的 bug)。v2.68 修復後同一輸入 emit 為 0031 0032 0033 0034 0035 0020 0631 0627 0634——數字保持 1-2-3-4-5 reading order,Arabic 單詞仍按視覺 RTL 渲染。
  • DetectBidiParagraphDirection 現在按 UAX #9 P2 把 EN 和 AN 視作弱類:純數字或前導數字的段落不再以數字錨定 RTL,第一個 STRONG 字符(L / R / AL)才決定。空 / 純弱輸入仍按 P3 預設 LTR。Smoke 驗證:純數字 → LTR,前導數字+Arabic → RTL(AL 是第一個 strong),前導數字+Latin → LTR(L 是第一個 strong)。
  • Arabic block U+0600..U+06FF 在 lookup 表中拆開,讓兩段數字範圍作為 bcAN 單獨命中;周圍的 U+0600..U+065F + U+066A..U+06EF + U+06FA..U+06FF 仍是 bcAL。其它 Arabic block codepoint(標點、百分號、貨幣等)暫時仍是 bcAL;更細的弱類處理(ET / CS / ON / NSM)等後續 W1-W7 / N0-N2 全管線一起做。
  • 無數字 run 的純 RTL 輸入與 v2.66 / v2.67 字節級一致(不觸發任何 W 類轉換)。LTR 段不受影響(數字本來就按段落基方向 LTR 渲染)。修復對所有已經使用 AutoDetectFormBidi 或 FormUnicodeRTL 配合 UseUAX9LevelReversal=True(預設)的呼叫方自動生效。
  • 剩餘 UAX #9 + GSUB 工作(W1 NSM 繼承 + 完整 W3/W4/W5/W6/W7 + N0-N2 brackets + I1 顯式級別 + OpenType GSUB Arabic / Syriac contextual joining + SMP RTL scripts BIDI_Class)仍排在後續版本。

2026-05-18 Version 2.67.0

  • 新增 Unicode UAX #9 L2 重排,應用於 LTR 段中嵌入的 RTL 子串。 新屬性 THotPDF.EnableLTRParaReorder(預設 False)讓呼叫方顯式選擇 spec-strict / reader-independent 的 /AP 輸出:LTR 段中嵌入 Hebrew / Arabic 在 /AP 生成時就被反轉到視覺順序, 消費閱讀器不必再跑自己的 intrinsic BIDI。
  • 單遍算法,與 v2.66.0 的 RTL 段 L1-L2 對稱:LTR 段 base level 0;每個 strong-R / strong-AL codepoint 取 level 1;其它保持 level 0。UAX #9 L2 最低奇數級別 = 1,所以循環只一遍:反轉每個最大 level-1 子串(連續 R/AL run)。L 字符和弱 / 中性字符原樣拷貝。兩遍中 surrogate pair 全程保對。
  • 公開方法 THotPDF.ApplyUAX9L2ReversalLTRPara 將該算法作為獨立 helper 暴露(UTF-8 進 UTF-8 出)。與 v2.66.0 ApplyUAX9L2Reversal 區分:後者 ParagraphRTL=False 路徑仍保留 v2.66 直通契約(依賴 v2.66 字節級行為的呼叫方不受影響), LTR 方向重排請改用新方法。
  • EnableLTRParaReorder 預設 False,保留 v2.59-v2.66 字節級 /AP 輸出。該 toggle 在 UseUAX9LevelReversal=False 時無效 (v2.59 naive 反轉從不處理 LTR 段);其餘情況下兩 toggle 相互獨立。
  • 完整 UAX #9 W1-W7 弱類型轉換 + N0-N2 中性 + bracket pair + I1-I2 顯式級別 + OpenType GSUB shaping 仍排到 v2.68+。

2026-05-18 Version 2.66.0

  • 新增 Unicode UAX #9 L1-L2 run-aware reversal,應用於 AcroForm Unicode 外觀流。新屬性 THotPDF.UseUAX9LevelReversal(預設 True)把 v2.59.0 RTL 段落的"整串簡單反轉"換成符合規範的兩遍 L2 重排,保留 RTL 段中嵌入 LTR 子串的內部 logical 順序。
  • 具體修復:輸入 "<Hebrew>AB"(logical UTF-16 05D0 05D0 0041 0042)此前在 Tj operand 中以十六進制 0042 0041 05D0 05D0 ("BAאא") 輸出——把 "AB" 倒著寫,按 UAX #9 是錯的。L1-L2 啟用後同一輸入 emit 為 0041 0042 05D0 05D0 ("ABאא")。純 RTL 輸入且無 L runs (例如 v2.59.0 預成形 Arabic smoke) 與傳統簡單反轉字節一致。
  • 公開方法 THotPDF.ApplyUAX9L2Reversal 把新算法作為獨立 helper 暴露(UTF-8 進 UTF-8 出),方便呼叫方自建外觀流或在 /AP 生成前預覽重排結果。
  • 本次刀使用 UAX #9 I1 + L2 的簡化單嵌入級子集:RTL 段落裡每個 strong-L codepoint 取得 level 2;其它一切(R、AL、弱、中性、 surrogate)保持 level 1。L2 先反轉每個 level-2 run(恢復 LTR 子串的 logical 順序)再反轉整個 level-1 全段(產生視覺 RTL 排版)。Surrogate pair 在兩遍中均保持完整。
  • 完整 UAX #9 W1-W7(弱類型轉換)+ N0-N2(中性 + bracket pair)+ I1-I2(顯式級別解析)+ LTR 段嵌入 RTL run 的重排仍排到 v2.67+。v2.66.0 解決最常見的可觀察 bug:含多字符 LTR 子串的 RTL 段落。
  • UseUAX9LevelReversal 預設 True。設 False 可恢復 v2.59.0 樸素整串反轉,獲得字節級與舊版一致的輸出。兩種形式仍按相同方式讀 FormUnicodeRTL 與 AutoDetectFormBidi。

2026-05-18 Version 2.65.0

  • 新增 Unicode 標準附件 #9 段落方向自動檢測,應用於 AcroForm Unicode AP 外觀流。新屬性 THotPDF.AutoDetectFormBidi 把 BuildUnicode*FieldContent 三個 helper(單行、多行、分格) 從 v2.59.0 的手動 FormUnicodeRTL 切換為按呼叫自動檢測段落方向。設置一次屬性即可讓同一批 setter 序列處理同一文件裡 LTR + RTL 混合欄位,無需手動切換標誌。
  • 方向由 UAX #9 P2 + P3 規則解析:掃描輸入找第一個強字符 (BIDI_Class L / R / AL)。R 或 AL 錨定段落為 RTL;L 錨定 LTR;無強字符按 P3 預設 LTR。
  • 識別的 BIDI_Class: Strong L ASCII Latin、Latin-1、Latin Extended、Greek、 Coptic、Cyrillic、Armenian、CJK 漢字、Hangul、 Hiragana、Katakana、Yi Strong R Hebrew (U+0590..U+05FF)、Hebrew presentation forms (U+FB1D..U+FB4F)、N'Ko、Samaritan、Mandaic Strong AL Arabic、Arabic Supplement、Arabic Extended-A、 Syriac、Thaana、Arabic presentation forms A + B (U+FB50..U+FDFF + U+FE70..U+FEFF) Surrogate pair 和弱 / 中性字符(數字、標點、空白)在掃描中跳過。
  • 公開方法 THotPDF.DetectBidiParagraphDirection 暴露檢測器, 呼叫方可預先計算方向(用於 /Lang 標籤、對稱中性字符輸出、 自定義欄位路由等)。接收 UTF-8 AnsiString,返回 Boolean (True = RTL)。空輸入按 P3 返回 False。
  • AutoDetectFormBidi 預設 False,保持 v2.59.0-v2.64.0 的字節級行為完全一致。設為 True 時,三個 helper 按呼叫忽略 FormUnicodeRTL。設回 False 即恢復手動控制。
  • 完整 UAX #9 隱式級 + 弱類型 + 中性括號解析(規則 W1-W7、 N0-N2、I1-I2、L1-L4)和自動 Arabic / Syriac OpenType GSUB contextual joining 仍排到 v2.66+。混合 bidi 段落超出段落級方向部分仍需呼叫方手動介入。

2026-05-18 Version 2.64.0

  • 新增 PDF 1.2 ISO 32000-1 10.5.5 ExtGState 半色調屏蔽(/HT)項支援,以及 Type 1 spot-function 半色調字典 builder。新方法 THotPDF.RegisterHalftoneType1 構建 PDF 1.7 Table 76 Type 1 半色調字典,呼叫方可控 CMYK 分色屏蔽(頻率 lpi、屏幕角度、 spot 形狀、可選的精確屏蔽、轉換函數、描述性半色調名)。配合 THotPDF.RegisterHalftoneState 把該字典引用包成 ExtGState /HT 項,供 THPDFPage.SetGraphicsState 使用。
  • /SpotFunction 可以是 PDF 1.7 Table 78 的 21 個內置 spot 名(SimpleDot、InvertedSimpleDot、DoubleDot、 InvertedDoubleDot、CosineDot、Double、InvertedDouble、Line、 LineX、LineY、Round、Ellipse、EllipseA、InvertedEllipseA、 EllipseB、EllipseC、InvertedEllipseC、Square、Cross、 Rhomboid、DiamondRhomboid),也可以是呼叫方自建的 spot Function 字典引用。未知的內置名拋異常,並在消息裡列出完整 spec 列表。Spot 名和 Function 互斥。
  • /TransferFunction 可選。傳 Function 字典引用做呼叫方自控色調再現,或設 TransferFunctionDefault = True emit /TransferFunction /Identity(消費閱讀器預設)。兩種形式互斥。
  • RegisterHalftoneState 接受半色調字典引用(典型為 RegisterHalftoneType1 返回值)或 HTDefaultName = True 走 /HT /Default 名字字面量復位路徑,恢復消費閱讀器內置半色調。
  • 所有項寫入時自動把文件版本提到 PDF 1.2。Frequency 必須 > 0; 無效的 spot-function 名在字典分配前拋異常。
  • 剩餘半色調類型排到 v2.65+:Type 5 多 component、Type 6 / 10 / 16 threshold-stream 半色調。Type 1 落地後,矩陣 "ExtGState entries" 候選距完整覆蓋只剩一刀。

2026-05-18 Version 2.63.0

  • 新增 PDF 1.4 ISO 32000-1 11.6.5 + 11.7.4 ExtGState 軟掩膜 + alpha-is-shape 項支援。新方法 THotPDF.RegisterSoftMaskState 把 /SMask 和 /AIS 兩個透明度圖形狀態參數打包進一個 ExtGState 字典,至此 v2.20.0 + v2.60.0 + v2.61.0 + v2.62.0 + v2.63.0 覆蓋 ExtGState 全部 spec 定義條目,僅餘多類型 /HT halftone 屏蔽(推到 v2.64+)。
  • /SMask 可以是字面名 /None(呼叫方傳 SMaskNone = True, 常見於複雜合成後的復位模式),也可以是間接 soft-mask 字典引用(呼叫方傳 SMaskDict,進階用法)。兩種形式互斥。 soft-mask 字典內容和底層透明度 Form XObject 由呼叫方自行構造;v2.64+ 會加專門 builder 助手。
  • /AIS 控制當前 alpha 值在圖形狀態後續部分被解釋為 alpha (false) 還是 shape (true)。哨兵預設 AIS = -1 完全跳過 /AIS 項;AIS = 0 或 1 分別 emit /AIS false / /AIS true,其它值拋帶說明的異常。
  • /SMask(None 或 Dict)或 /AIS 至少要供一項;全為預設值的呼叫會拋異常。任何項寫入時自動把文件版本提到 PDF 1.4。
  • 返回自動生成的 ExtGState 名(GS1、GS2…)交給 THPDFPage.SetGraphicsState 使用。和 v2.42.0 AddImageWithSMask 區分:那條路徑是單個 XObject 上的圖像級 alpha;本方法是 ExtGState 級遮罩,對所有後續繪圖操作生效。
  • 剩餘 ExtGState 項排到 v2.64+:/HT halftone 屏蔽 (Type 1 / 5 / 6 / 10 / 16)。

2026-05-18 Version 2.62.0

  • 新增 PDF 1.2/1.3+ ISO 32000-1 11.7.5.4 ExtGState 黑色生成 + 底色去除項支援。新方法 THotPDF.RegisterBlackGenerationState 把 4 個 Function 引用的圖形狀態參數 /BG、/BG2、/UCR、/UCR2 打包進一個 ExtGState 字典,適用於在光柵化時做 RGB→CMYK 轉換的 CMYK 印前流程(典型場景:報紙 / 包裝 / 大幅面生產, 油墨投放決策與輸出設備相關)。
  • /BG 和 /UCR(PDF 1.2)是 1 輸入 / 1 輸出 Function 字典; /BG2 和 /UCR2(PDF 1.3+)可以是 Function 字典,也可以是字面名 /Default 讓消費閱讀器使用其預設曲線。setter 每個 Function 槽接受一個 THPDFObject(典型由 v2.52.0 RegisterSampledFunction 生成),加 BG2DefaultName / UCR2DefaultName 兩個布爾標誌走 /Default 名字面形式。同一個 /BG2 或 /UCR2 槽裡混 Function 字典和 Default 標誌會拋帶說明的異常。
  • /BG、/BG2、/UCR、/UCR2(Function 或 Default)至少要供一項; 全為預設值的呼叫會拋異常。任何 /BG2 / /UCR2(Function 或 Default)寫入時自動把文件版本提到 PDF 1.3。
  • 返回自動生成的 ExtGState 名(GS1、GS2…)交給 THPDFPage.SetGraphicsState 使用。可與 v2.60.0 RegisterTransferFunctionState(按通道輸出曲線)自然搭配—— 典型 CMYK 生產鏈註冊一個 BG/UCR ExtGState 做 RGB→CMYK 轉換, 再註冊一個 /TR ExtGState 做輸出設備上的最終色調再現。
  • 剩餘 ExtGState entries 排到 v2.63+:/HT halftone 屏蔽 (Type 1 / 5 / 6 / 10 / 16) + ExtGState 級 /SMask + /AIS soft mask。

2026-05-17 Version 2.61.0

  • 新增 PDF 1.2/1.3+ ISO 32000-1 8.6.5.7 + 8.6.5.8 + 11.7.4 ExtGState 印前控制項支援。新方法 THotPDF.RegisterPrintControlState 把面向印前的圖形狀態參數 /OP、/op、/OPM、/SA、/RI、/FL 打包進一個 ExtGState 字典, 適用於需要 overprint、stroke adjustment、rendering intent、 flatness 控制的 PDF/X-1/X-3/X-4 生產工作流程。
  • 6 個參數各自獨立可選。預設哨兵值:Overprint = -1(跳過 /OP + /op)、OverprintMode = -1(跳過 /OPM)、StrokeAdjustment = -1(跳過 /SA)、RenderingIntent = ''(跳過 /RI)、Flatness < 0(跳過 /FL)。呼叫方至少要傳一項;全部預設時拋異常。
  • Overprint 同時設 /OP 和 /op(PDF spec 預設 /op 繼承 /OP 但 spec-strict PDF/X 流水線要求兩項都顯式)。OverprintMode = 1 啟用 PDF 1.3 CMYK-aware overprint(任意零分量繪成透明);自動把文件版本提到 1.3。
  • RenderingIntent 接受四種標準值 'AbsoluteColorimetric' / 'RelativeColorimetric' / 'Saturation' / 'Perceptual';其它非空字串拋異常。Flatness 限定在 spec 範圍 [0.0..100.0], 超出拋異常。
  • 返回自動生成的 ExtGState 名(GS1、GS2…)交給 THPDFPage.SetGraphicsState 使用。可與 v2.20.0 RegisterExtGState (透明度 / blend mode)以及 v2.60.0 RegisterTransferFunctionState (輸出曲線)自然搭配——典型 PDF/X 流水線每種鏈一個狀態。
  • Function 驅動的 /BG、/UCR、/BG2、/UCR2(black generation + undercolor removal)以及更復雜的 /HT halftone screen + ExtGState 級 /SMask soft mask 留作後續工作。

2026-05-17 Version 2.60.0

  • 新增 PDF 1.3+ ISO 32000-1 11.7.3.4 ExtGState /TR(transfer function)支援。新方法 THotPDF.RegisterTransferFunctionState 註冊一個攜帶 /TR 項的 ExtGState 字典,在顏色光柵化時對輸出應用色調再現曲線。曲線由呼叫方用 v2.52.0 Function Type 0 Sampled LUT(或任何其它 Function 字典)提供;本 wrapper 和已存在的 RegisterSampledFunction 原語天然配套,讓手工調的 gamma / 亮度 / 印刷特性曲線落地,不必走 ICC profile 鏈路。
  • 兩種呼叫形式:
  • SingleFunc 形式:一個 Function 應用到所有輸出通道 (gamma / 亮度場景)。
  • PerChannel 數組形式:4 元素數組 [TR_R, TR_G, TR_B, TR_A] 對應 RGB-A 通道,或 [TR_C, TR_M, TR_Y, TR_K] 對應 CMYK 再現曲線;按 PDF spec 4 個槽位都必須非 nil。
  • 返回自動生成的 ExtGState 名稱(GS1、GS2…),交給 THPDFPage.SetGraphicsState 使用。在需要應用 transfer 曲線的繪製操作(文字 / 路徑 / 圖像)之前 set 該狀態。
  • 混合呼叫(SingleFunc 非 nil + PerChannel 非空)會拋異常, spec 強制的互斥關係在 API 表面就攔截。

2026-05-17 Version 2.59.0

  • 新增 AcroForm Unicode /AP 的右到左方向支援(PDF 1.7 ISO 32000-1 12.7.4.3)。新的 THotPDF.FormUnicodeRTL 布爾屬性:開啟後三個 Unicode /AP helper(single-line、multi-line、comb)在發出 hex Tj 操作數前反轉 UTF-16 碼元順序,讓預先字形整形過的阿拉伯文 / 希伯來文 / 敘利亞文按視覺右到左順序渲染。UTF-16 代理對在反轉時整體保留(高代理緊跟低代理的原始順序),SMP 碼位(古文字 letterform 等)也能正確顯示。
  • 作用範圍:v2.59.0 只做方向反轉這一步。呼叫方負責另兩件 v2.59.0 不做的事情:(1)完整 UAX #9 雙向算法消解(混合 LTR / RTL / 數字 / 中性字符)和(2)阿拉伯 / 敘利亞字形 contextual joining (Initial / Medial / Final / Isolated 四形態選擇)。呼叫方應在傳入 AddTextField 前把阿拉伯文預先映射到 Unicode 表示形態區段(U+FB50..U+FDFF + U+FE70..U+FEFF)。希伯來文沒有 contextual joining,所以不需要預映射。
  • /V(邏輯 Unicode 順序)不變:PDF text string 永遠是輸入順序, spec-following 文本提取器看到正確的邏輯序列。只有 /AP Tj 操作數翻轉順序,渲染器畫時視覺為 RTL。本次發佈之後 v2.55.0-v2.59.0 AcroForm 國際化 /AP 鏈完整閉環:/RV 富文本、單行/多行/comb CID 字體 /AP、以及 RTL 方向反轉。完整 UAX #9 + 自動 GSUB 字形整形仍是 v2.60.0+ scope。

2026-05-17 Version 2.58.0

  • 把 v2.56.0 / v2.57.0 的呼叫方自帶 Unicode 字體 /AP 鏈擴展到 ffComb 分支(PDF 1.7 ISO 32000-1 12.7.4.3 Tx /Ff 第 25 位)。 當 SetFormUnicodeFontDict 已註冊 Type 0 複合字體、且 Tx widget 加上 ffComb + 非 ASCII 初值時,HotPDF 現在寫出真正的 /AP /N 外觀流:每個 CJK 字符放進一個等寬 comb 格,每格用一個絕對 Tm 矩陣定位 + 一個 UTF-16BE hex-string Tj 操作符。
  • UTF-16 代理對(碼位 >= U+10000,例如 emoji 和 CJK 擴展 B/C/D 超平面漢字)佔據一個 comb 格,與 Acrobat 處理複合字體單字形 comb 的方式一致。每格的居中公式與 v2.46.0 ASCII comb 分支完全相同,視覺佈局沿用 ASCII 單字符佈局。
  • ASCII comb 欄位與 v2.46.0 輸出字節級相同。非 ASCII comb 但沒註冊 SetFormUnicodeFontDict 時仍走 v2.46.0 空 /AP 佔位 (不變)。本次發佈之後 v2.55.x–v2.58.0 AcroForm 國際化 /AP 鏈(單行、多行、comb)完整閉環;RTL bidi 整形(UAX #9 + 阿拉伯 contextual joining)作為 v2.59.0+ scope。

2026-05-17 Version 2.57.0

  • 把 v2.56.0 的呼叫方自帶 Unicode 字體 /AP 路徑擴展到多行文本欄位(PDF 1.7 ISO 32000-1 12.7.4.3 ffMultiline / Tx /Ff 第 13 位)。當 SetFormUnicodeFontDict 已註冊 Type 0 複合字體、且 Tx widget 加上 ffMultiline + 非 ASCII 初值時,HotPDF 現在按 UTF-16 字符做 word-wrap,並對每條可見行寫一個 UTF-16BE hex-string Tj,透過 Td/T* + /TL leading 佈局(與 v2.46.0 ASCII 多行排版方式相同)。
  • 換行寬度按簡單 advance 估算:CJK / 寬字符(≥ U+2E80)每個 1 em, 窄字符(ASCII 範圍 + Latin-1 標點)每個 0.5 em。這樣 Latin / CJK 混排不用讀字體 /W 數組也能合理折行。CR / LF / CRLF 硬換行按字面處理。超出 widget 矩形的行按字號能容納的行數截斷 —— 與 ASCII 多行分支一致。
  • ASCII 多行、ASCII 單行、ASCII comb 以及 v2.56.0 非 ASCII 單行路徑全部字節級不變。非 ASCII comb 路徑(ffComb + 多字節文本) 目前仍走 v2.56.0 單行 helper;ffComb 專屬的 Unicode 佈局留作 v2.58.0+,RTL bidi(UAX #9 + 阿拉伯 contextual joining)也是 v2.58.0+ scope。

2026-05-17 Version 2.56.0

  • 新增呼叫方自帶 Unicode 字體的 AcroForm /AP 渲染支援(PDF 1.7 ISO 32000-1 12.7.2 + 12.7.4.3)。本次發佈前,GenerateTextFieldAP 遇到任何含 ≥0x80 字節的 InitialValue 都只能寫一個空的 /AP 佔位 Form XObject,非 ASCII 文本只能靠 /NeedAppearances=true 讓閱讀器重生成(依賴閱讀器自帶字體),或者透過 v2.55.0 的 /RV 富文本路徑 (依賴閱讀器富文本引擎)。v2.56.0 把這個缺口補上:呼叫方註冊一個 Type 0 / CIDFontType2 + Identity-H 複合字典之後,HotPDF 寫出真正的 /AP /N 流,裡面透過 Tf 選用註冊字體、用 UTF-16BE 十六進制字串 Tj 操作符渲染值。
  • 新方法 THotPDF.SetFormUnicodeFontDict(LogicalName, FontDict): 註冊一個邏輯名 + 字體字典對。註冊之後,AcroForm 頂層 /DA、每個 Tx widget 的 /DA、以及非 ASCII Tx 初始值的 /AP 流都切到邏輯名; AcroForm 的 /DR/Font 字典除了 /Helv 和 /ZaDb 也帶上該字體;Form XObject 的 /Resources/Font 子字典也引用同一個 indirect 字體,讓 /AP 自包含,不依賴渲染時去 /DR 查表。傳 '' + nil 撤銷註冊,恢復 v2.46.0 的 /Helv-only 行為。
  • 新方法 THotPDF.CreateIndirectFontDict:公開 helper,分配一個空的 THPDFDictionaryObject 並註冊為 indirect PDF 物件,讓呼叫方能構造任何需要序列化成 "N G R" indirect 引用的字典(custom 字體、 色彩空間、OCG、Function 等)。和 SetFormUnicodeFontDict 配套用來搭 Type 0 複合字體最自然。
  • 純 ASCII Tx 欄位繼續用 /Helv,/AP 輸出與 v2.46.0 / v2.55.0 字節完全相同。多字節 Tx 但**沒**註冊 SetFormUnicodeFontDict 時仍走 v2.46.0 的空 /AP 佔位(語義不變,保後向相容)。
  • 多行 + 分格的非 ASCII /AP 覆蓋、RTL bidi 整形(UAX #9 + 阿拉伯 contextual joining)仍是 v2.57.0+ 的工作;v2.56.0 覆蓋單行邏輯序的 CJK / 西里爾 / 越南語 / 希臘語等腳本。

2026-05-17 Version 2.55.0

  • 新增 AcroForm 富文本 Tx widget 支援(PDF 1.7 ISO 32000-1 12.7.4.3 + Annex L)。新方法 THPDFPage.AddRichTextField 寫出帶 /RV(rich-text XHTML 主體)、/DS(CSS 風格預設樣式)、 ffRichText(/Ff 第 26 位)以及 /V + /DV 純文本回退的文本 widget。 當 RichText 位開啟時,Acrobat / Foxit 直接根據 /RV 渲染,從閱讀器自身安裝的 Unicode 字體裡取字形回退 —— 這樣 HotPDF 不必在 /DR Resources 裡嵌入 CID 字體也能讓多字節內容(CJK / 西里爾 / 阿拉伯 / 帶音標拉丁)正確顯示。讓 HotPDF 自己的外觀流(/AP) 生成器原生支援非 ASCII 仍是後續工作;懂富文本的閱讀器無需這步。
  • /V 和 /RV 都自動檢測多字節輸入,需要時切換成 UTF-16BE 十六進制字串(FE FF BOM + 大端碼元),與 AddTextField 處理國際化純文本欄位一致。ASCII 內容保持 PDF 文字字面量字串,與 v2.46.0 純文本輸出字節完全相同。
  • AcroForm 國際字符候選剩三項後續:(1)CID 字體 /DR Resources 路徑,讓 HotPDF 生成的 /AP 流自己覆蓋非 ASCII,而非依賴閱讀器富文本引擎;(2)阿拉伯 / 希伯來富文本的 RTL bidi 整形; (3)/AA /K 鍵盤動作 helper。

2026-05-17 Version 2.54.0

  • 擴展 PDF 1.7 ISO 32000-1 7.10.2 Function Type 0(Sampled)支援 cubic-spline 插值。RegisterSampledFunction 新增可選 Order 參數 (預設 1,按 PDF 1.7 Table 38 僅接受 1 或 3)。Order = 3 在每個輸入軸上使用三次樣條插值;Order = 1 保留現有的線性行為,字節完全相同,v2.52.0 / v2.53.0 呼叫方零感知。
  • 新增多輸入 / 多輸出 Function Type 0 端到端覆蓋。新增的 smoke 註冊一個 2 輸入 / 3 輸出、4×4 網格、cubic 插值的 sampled 函數, 按 spec sample 順序規則("input 座標沿第一個輸入維變更最快") 逐字節核對所有 16 網格點 × 3 通道,對照值由 Python verifier 獨立按 analytic 公式重新計算。
  • Acrobat / Foxit / qpdf 都支援 Order = 3;部分老牌移動端閱讀器遇到不認識的 Order 值會悄悄降級為線性插值,所以 cubic 仍然保留為 opt-in,以維持最大化閱讀器相容性。

2026-05-17 Version 2.53.0

  • 新增 Separation 色彩空間的高級註冊接口,tint transform 用 Function Type 0(LUT)實現(PDF 1.7 ISO 32000-1 8.6.6.4 + 7.10.2)。新方法 THotPDF.RegisterSeparationLUT(ColorantName, AlternateCS, Samples) 直接複用 v2.52.0 的 RegisterSampledFunction 原語,呼叫方只需提交按 (M 元組) 排列的扁平字節流,不必手工構造 Function Type 0 字典。
  • LUT 變體適合非線性色彩過渡場景:PANTONE Hexachrome 風格的 tint ramp、gamma 校正的密度曲線、按印刷特性表手繪的色調曲線、把 sRGB→spot 色彩轉換塞進 ICC LUT 但不願帶完整 ICC profile 鏈路等。線性 ramp(最常見的單油墨 PANTONE spot color)仍可繼續用 v2.45.0 的 RegisterSeparation。
  • Samples 是 8-bit RGB / CMYK / Gray 字節,按 (c0_0, c1_0, ..., cM-1_0, c0_1, ..., cM-1_S-1) 順序排列,S = Length(Samples) / M 自動推導,且 S ≥ 2(保證函數可插值)。線性插值是預設行為 (PDF 1.7 /Order 1)。返回 Sep1 / Sep2 / … 這樣的色彩空間名, 可直接用 THPDFPage.SetFillColorSpace / SetStrokeColorSpace + SetFillColor([tint]),tint ∈ [0, 1]。
  • 內部把 THPDFSeparationParams.TintFunc 從 THPDFDictionaryObject 擴到 THPDFObject 公共基類,可以同時容納 Function Type 2 (v2.45.0 路徑)和 Function Type 0 stream(v2.53.0 路徑);兩者在 THPDFArrayObject.AddObject 裡都序列化成 "N G R" indirect 引用,對下游解析透明。

2026-05-17 Version 2.52.0

  • 新增 PDF 1.7 ISO 32000-1 7.10.2 Function Type 0(Sampled)註冊支援。Sampled function 以規則的 N 維網格 + M 維輸出樣本表表達任意 input→output 映射;閱讀器在網格點之間線性插值得到中間值。 適合那些用 ICC profile 太重、但又想精細控制的色彩 LUT 場景 —— ExtGState `/TransferFunction` 色調曲線、`/Separation` / `/DeviceN` 的 sampled tint transform(區別於已支援的線性 Type 2 / 算式 Type 4 路徑)、halftone 閾值曲線,以及任何接受 Function 字典的 PDF 結構。
  • 新方法 THotPDF.RegisterSampledFunction(Domain, Range, Size, BitsPerSample, Samples) 寫出一個 indirect `/FunctionType 0` stream,字典包含 `/Domain`(2N)、`/Range`(2M)、`/Size`(N)、 `/BitsPerSample`(1 / 2 / 4 / 8 / 12 / 16 / 24 / 32)、 `/Order 1`(線性插值),加上原始按位打包的樣本載荷。返回 indirect `THPDFStreamObject`,呼叫方可以把它接到任何接受 Function 字典的位置。
  • Samples 字節數組長度按 `ceil(GridPoints * M * BitsPerSample / 8)` 校驗; `BitsPerSample` 8 / 16 / 24 / 32 是字節對齊大端, 1 / 2 / 4 / 12 按 PDF 1.7 7.10.2 的 MSB-first 打包規則, 最末字節按需補零。
  • Function Type 3(stitching)/ Type 4(PostScript calculator) 已在 v2.18.0 / v2.47.0 起透過內部 helpers 可用;本次發佈把 Type 0 提升到同樣的公開 API 級別。

2026-05-17 Version 2.51.6

  • 收尾 v2.51.x 二進制安全 sweep:修復最後一處 TStringList "Source=Target" 往返點 —— FStructRoleMap(PDF 1.7 ISO 32000-1 14.7.3 /StructTreeRoot /RoleMap)。透過 AddStructRoleMap 註冊的自定義結構 role 名在 Windows CP_ACP=65001("Beta: Use Unicode UTF-8")系統上不再被悄悄破壞;存儲改為 array of (Source: TBytes; Target: TBytes) 記錄的動態數組, 所有插入/讀取訪問都用字節級 Move() 保真。標準 PDF struct types (Document、P、H1..H6、Span、Div 等)按 spec 都是 ASCII,所以之前的版本在常規用例下能跑;本次修復隻影響把工具特定的 Latin-1 role 名映射到標準類型的呼叫者。
  • 把 PDF Name #XX 轉義(PDF 1.7 7.3.5)擴展到 SaveDictionaryObject 的字典 KEY。之前字典鍵直接原樣寫入輸出流,任何 ≥ 0x80 的字節都不會被轉義,生成 spec 不合規的輸出 —— 透過 AddStructRoleMap 傳入非 ASCII source role 即觸發。字節級 trim + #XX 轉義邏輯現在抽到共享 helper(_EscapePDFNameBytes),由 SaveNameObject (name 值)和 SaveDictionaryObject(字典鍵)共同呼叫。ASCII 鍵(HotPDF 自動生成字典的通用情況)轉義後字節完全相同, 所以現有文件和測試不受影響。
  • 本次發佈之後 v2.51.x 二進制安全鏈(PubSec 接收者、DeviceN ColorantNames、PDF Name 值輸出、PDF Name 鍵輸出、struct role map 存儲)結構性閉環 —— HotPDF 已知任何字節 blob 路徑都不再存在 AnsiString-via-UnicodeString round-trip。34/34 smoke + 27/27 verifier 全部透過。

2026-05-17 Version 2.51.5

  • 延續 v2.51.4 的二進制安全 sweep,把 Windows CP_ACP=65001 ("Beta: Use Unicode UTF-8 for worldwide language support")系統下另外兩條會悄悄破壞非 ASCII 字節的發送路徑一併修好。
  • DeviceN 油墨名(ColorantNames)現在以 THPDFDeviceNParams 內的 array of TBytes 動態數組存儲(之前是 TStringList 的 UnicodeString 條目)。舊實現強制每個油墨名經過 AnsiString → UnicodeString → AnsiString 往返,UTF-8 ANSI 主機會把 ≥ 0x80 的字節改寫成 3 字節替換序列 EF BF BD。純 ASCII 油墨名 (PANTONE / Hexachrome 以及 "Red" / "Blue" 之類)不受影響; 自定義非 ASCII 油墨名(例如非英語印刷流程裡的 Latin-1 重音 spot-ink 名)則在本次發佈前悄悄被破壞。
  • PDF Name 輸出路徑(SaveNameObject)現在二進制安全且符合 spec。 舊實現 AnsiString(Trim(String(ValObject.Value))) 對每個 PDF Name 都跑同樣的破壞性往返。現在按字節比較裁剪("char ≤ 0x20" 與 Delphi 的 Trim 語義一致),並按 PDF 1.7 ISO 32000-1 7.3.5 把任何超出 0x21..0x7E 常規字符範圍的字節用 #XX 轉義寫出。 純 ASCII 且無前後空白、無嵌入特殊字節的 Name 與之前字節完全一致, 所以現有文件和測試都不受影響。
  • 新增 round-trip 驗證(smoke_devicen_binary_safe)註冊一個名字裡含 0xA0 字節的 DeviceN 油墨,並斷言生成的 /Names 數組帶 spec 規定的 "#A0" 轉義、而不是會出錯的 "#EF#BF#BD" 序列。本次發佈之後 v2.51.x 二進制安全鏈(PubSec 接收者、DeviceN 油墨名、 通用 PDF Name 輸出)正式閉環;33/33 smoke + 26/26 verifier 全部透過。

2026-05-17 Version 2.51.4

  • 修復 Public-Key Security Handler(PDF 1.7 ISO 32000-1 7.6.5) 中接收者信封字節悄無聲息被破壞的問題。當宿主系統啟用 Windows "Beta: Use Unicode UTF-8 for worldwide language support" (CP_ACP=65001)時,先前基於 TStringList 存儲 PKCS#7 envelopedData blob 的方案會強制經過 AnsiString → UnicodeString → AnsiString 往返,把每個非 ASCII 字節改寫成 UTF-8 替換序列(EF BF BD)。這種破壞同樣作用於算法 9 的 SHA-1 文件密鑰計算 和 寫出的 /Recipients 十六進制字串,所以生成的 PDF 用 HotPDF 自己(在同一 CP_ACP 鎖定系統上)能解密,但任何第三方閱讀器都無法從原始信封字節推導出相同的密鑰 —— 加密文件實際只能由 HotPDF 本身在同一系統上讀取。
  • 修復方案把接收者存儲改為 array of TBytes 動態數組; AddPubKeyRecipient 公開 API 簽章不變。信封字節經 Move() 逐字節拷貝,不再有任何代碼頁轉換路徑。
  • /Recipients 十六進制現在與傳入的信封字節完全一致,不受宿主 locale 影響;Acrobat / Foxit / qpdf 以及任何懂 PKCS#7 的閱讀器都能按 spec 還原文件加密密鑰。
  • v2.33.0 起的 round-trip 驗證腳本 smoke_pubsec_verify 因此而失敗已久,v2.51.4 把它從 FAIL 變為 OK。本次發佈之後整條 v2.51.x audit 鏈(R=5 audit、R=6 user-pw audit、R=6 owner-pw K0 修復、PubSec 接收者字節修復)完整閉環,25/25 smoke verifier 全部清乾淨 —— 自 v2.33.0 以來第一次。

2026-05-16 Version 2.51.3

  • 修復 AES-256 V=5 R=6 所有者口令驗證哈希以符合 ISO 32000-2 算法 2.B 字面規定。PDF 2.0 hash dance 要求初始 K 取 SHA-256(password || salt || udata),其中所有者口令路徑的 udata 是完整的 48 字節 /U 項。之前的 HotPDF 版本(v2.22.0 至 v2.51.2)只把 udata 放進迭代 K1 步而漏掉初始 K,得到的 /O[0:32] 不合 spec,Acrobat / Foxit / qpdf 類閱讀器會在所有者口令驗證時拒絕。使用者口令解密路徑不受影響 —— 因為它的 hash dance 是用空 udata 呼叫的,初始 K 在修復前後字節相同。
  • 修復後 Acrobat / Foxit / qpdf 可以用 HotPDF 寫出的 R=6 文件完成所有者口令驗證。v2.51.3 之前生成的 R=6 文件用使用者口令解密仍然可讀,但所有者口令不能被 spec-following reader 解鎖; 如需被外部閱讀器驗證所有者口令,請用 v2.51.3 重新生成。
  • /U / /UE / /Perms 以及 V=5 R=5 和 V=4 路徑與 v2.51.3 前的輸出完全相同 —— 修復只動 PDF20HashDanceR6 的初始 K SHA-256, 且只在 UEntry 非空(即 CreateKeysV5 owner-pw 呼叫點)時改變輸出。
  • 新增 round-trip audit(smoke_aes256_r6_owner_verify)透過修復前和 spec 兩種算法各自推導 /O[0:32],斷言 emitted /O[0:32] 與 spec 變體一致、且修復前的變體已不再被產出。

2026-05-16 Version 2.51.2

  • 將 v2.51.1 的 /Perms audit 擴展到 V=5 R=6("hash dance")標準安全處理程序路徑(ISO 32000-2 7.6.4.3.4 / 算法 2.B)。新增的往返驗證腳本用純 Python 重新實現迭代式 SHA-256 / SHA-384 / SHA-512 + AES-128-CBC 混合器,獨立從空使用者口令派生 32 字節文件加密密鑰,再 AES-256-ECB 解密 16 字節 /Perms 塊,並逐項斷言每個欄位與加密字典裡的值一致(/P 小端、0xFF 填充、'T' / 'F' 標誌位、'a' 'd' 'b' 字面標記)。本次發佈行為不變,純為 v2.51.1 已鎖定的 R=5 路徑之外補齊 R=6 路徑的迴歸覆蓋。

2026-05-16 Version 2.51.1

  • 在迴歸測試套件中鎖定 V=5 R=5 標準安全處理程序的 /P → /Perms 綁定。AES-256 加密路徑按 ISO 32000-1 Algorithm 10 寫出 16 字節 /Perms 塊:字節 0-3 是 /P 的 32-bit 小端整數、字節 4-7 是 0xFF 填充、字節 8 是 'T' / 'F' 跟隨 /EncryptMetadata、字節 9-11 是字面 'a' 'd' 'b' 標誌、字節 12-15 是隨機填充。新增的 audit smoke 用算法 2.A(SHA-256(pw || U_Key_Salt) → AES-CBC 解密 /UE → 取出文件密鑰)獨立派生密鑰、AES-256-ECB 解密 /Perms、再逐欄位對照加密字典裡的值。本次發佈行為不變, 純為防止日後重構悄悄打破 spec 強制的 /P ↔ /Perms 聯動。

2026-05-16 Version 2.51.0

  • 新增 PDF 1.3+ ISO 32000-1 8.7.4.5.7 tensor product patch 網格陰影 (Shading Type 7),網格陰影家族最後一項(前三項是 v2.48 Type 4 自由形式 / v2.49 Type 5 lattice / v2.50 Type 6 Coons)。每個 tensor-product patch 攜帶完整的 4×4 雙三次貝塞爾控制點網格 p[i][j] (12 個邊界點 + 4 個內部點),加每角一個顏色,可以同時精細控制 patch 邊界與內部曲面。適合 SVG mesh-gradient 完整往返、以及任何需要 tensor-product Bezier 曲面(而非 Coons 拼接曲面)的矢量插畫。
  • 新方法 THotPDF.RegisterTensorProductPatchMesh(XMin, YMin, XMax, YMax, NumComponents, Patches) 打包二進制 Shading 流 (/ShadingType 7 + /BitsPerCoordinate 16 + /BitsPerComponent 8 + /BitsPerFlag 8),外包成 Pattern Type 2,返回 Pattern 名 (Sh1、Sh2、…),用法與前三項完全一致。
  • Patches 平鋪數組每個 patch 由 16 個控制點(32 個 X+Y 浮點,按 spec stream 序:p[0][0..3]、p[1][3]、p[2][3]、p[3][3]、p[3][2..0]、 p[2][0]、p[1][0]、p[1][1]、p[1][2]、p[2][2]、p[2][1])+ 4 個角顏色(p[0][0] / p[0][3] / p[3][3] / p[3][0],每個 NumComponents 浮點)組成,stride = 32 + 4 × NumComponents。所有 patch flag = 0。
  • 本次發佈之後,整個 ISO 32000-1 8.7.4.5 mesh shading 家族 (Types 4 / 5 / 6 / 7)已全部覆蓋。

2026-05-16 Version 2.50.0

  • 新增 PDF 1.3+ ISO 32000-1 8.7.4.5.6 Coons patch 網格陰影 (Shading Type 6),是網格陰影家族第三項(前兩項是 v2.48 Type 4 自由形式與 v2.49 Type 5 lattice)。每個 Coons patch 的四條邊都是三次貝塞爾曲線、每個角都帶一個顏色;閱讀器在四條邊內擬合 Coons 曲面,得到一塊帶任意曲邊的彩色四邊形。適合貼在彎曲路徑上的金屬 / 箔漸變、SVG gradient mesh 導入、以及任何用三角網逼近不划算的曲邊四邊形。
  • 新方法 THotPDF.RegisterCoonsPatchMesh(XMin, YMin, XMax, YMax, NumComponents, Patches) 打包二進制 Shading 流(/ShadingType 6 + /BitsPerCoordinate 16 + /BitsPerComponent 8 + /BitsPerFlag 8), 外包成 Pattern Type 2,返回 Pattern 名(Sh1、Sh2、…),可直接用 SetFillPattern / SetStrokePattern 呼叫。
  • Patches 平鋪數組每個 patch 由 12 個控制點(24 個 X+Y 浮點) + 4 個角顏色(4 × NumComponents 浮點)組成,stride = 24 + 4 × NumComponents。控制點 c1..c12 按 patch 邊界順時針順序排列,c1 / c4 / c7 / c10 是 4 個角,其餘 8 個是貝塞爾內控點。 所有 patch 的 flag 字節固定為 0(獨立 patch);共邊繼承(flag 1 / 2 / 3)未在本便利重載中暴露。
  • Type 7(tensor product patch mesh)作為後續工作。

2026-05-16 Version 2.49.0

  • 新增 PDF 1.3+ ISO 32000-1 8.7.4.5.5 lattice 形式 Gouraud 三角網格陰影(Shading Type 5),是 v2.48.0 Type 4 自由形式的姊妹特性。當源資料本身位於規則採樣網格上(地形、有限元結果、科學熱圖等)、呼叫方不願顯式編排三角形拓撲時,由閱讀器自動把相鄰兩行連成 triangle strip。
  • 新方法 THotPDF.RegisterLatticeFormGouraudShading(XMin, YMin, XMax, YMax, NumComponents, VerticesPerRow, Vertices) 把 M 行 × N 列 lattice 打包為二進制 Shading 流(/BitsPerCoordinate 16、/BitsPerComponent 8、 /VerticesPerRow N)。與 Type 4 不同:沒有逐頂點的 flag 字節, /BitsPerFlag 也不再出現在 shading 字典裡。返回 Pattern 名(Sh1、 Sh2、…),可直接用 SetFillPattern / SetStrokePattern 呼叫。
  • Vertices 平鋪數組按 row-major 排列,每個頂點 (X, Y, c0, c1, …, c_{NumComponents-1});總頂點數必須是 VerticesPerRow 的整數倍,至少兩行。NumComponents 接受 1 (DeviceGray)、3 (DeviceRGB)、4 (DeviceCMYK)。
  • Type 6(Coons patch)/ Type 7(tensor product)網格陰影仍待。

2026-05-16 Version 2.48.0

  • 新增 PDF 1.3+ ISO 32000-1 8.7.4.5.4 自由形式 Gouraud 三角網格陰影 (Shading Type 4),適合向量插畫中超出 Type 2 / 3 軸向 / 徑向漸變能力範圍的顏色過渡。任何帶頂點顏色的三角化曲面都可以直接嵌入。
  • 新方法 THotPDF.RegisterFreeFormGouraudShading(XMin, YMin, XMax, YMax, NumComponents, Vertices) 把三角網格打包為二進制 Shading 流 (/BitsPerCoordinate 16、/BitsPerComponent 8、/BitsPerFlag 8), 包裝成 Pattern Type 2,返回 Pattern 名(Sh1、Sh2、…),可直接用 THPDFPage.SetFillPattern / SetStrokePattern 呼叫。
  • Vertices 是平鋪數組,每個頂點 (X, Y, c0, c1, …) row-major;每三個頂點構成一個獨立三角形。輸出座標 / 分量以大端無符號整數編碼; /Decode 數組將編碼範圍映射回呼叫方指定的使用者空間矩形。

2026-05-16 Version 2.47.0

  • 新增 DeviceN 色彩空間支援(PDF 1.3+ ISO 32000-1 8.6.6.5),將 Separation 推廣到 N 個 colorant,覆蓋六色印刷、金屬 / 熒光油墨混合、PDF/X 自定義油墨等印前工作流程。新方法 THotPDF.RegisterDeviceN(ColorantNames, AlternateCS, TintC1Matrix) 返回自動分配的色彩空間名(DevN1、DevN2、…),可直接配合 SetFillColorSpace + SetFillColor 使用,提供 N 個 [0..1] tint 分量。
  • tint transform 是 PostScript 計算器(Function Type 4),按呼叫方傳入的 N×M 矩陣線性加權混合,無 spot 支援的閱讀器在備用色彩空間中按"各 colorant 貢獻相加"渲染。
  • ColorantNames 接受任意 spot ink 名,含空格的按 PDF 1.7 7.3.5 自動轉義為 #20。特殊名 "None" 表示未使用的 colorant 槽位。
  • AlternateCS 接受 DeviceGray、DeviceRGB 或 DeviceCMYK;其它值拋異常。

2026-05-15 Version 2.46.0

  • 擴展 AcroForm 自動外觀流(AutoFormAppearances)對文本欄位的支援, 符合 PDF 1.7 ISO 32000-1 12.7.4.3。v2.28.0 早期版本對所有文本控制項都只輸出單行字面值;現在多行欄位和分格(comb)欄位各走專門的 AP 佈局路徑。
  • 多行文本欄位(Flags 含 ffMultiline)會按控制項寬度對初始值做單詞換行,識別 CR / LF / CRLF 行分隔符,按可見行數截斷,並使用 Td + T* + /TL 的標準多行版式輸出。
  • 分格文本欄位(Flags 含 ffComb 且 MaxLen > 0)按格寬逐字符使用絕對 Tm 矩陣定位,渲染效果與 Acrobat 一致。
  • 單行文本欄位的 AP 內容流保持 v2.28.0 字節級行為,舊呼叫方無需改動。

2026-05-14 Version 2.45.0

  • 新增 Separation 色彩空間支援,覆蓋印前 spot color 工作流程(ISO 32000-1 8.6.6.4)。新方法 THotPDF.RegisterSeparation(ColorantName, AlternateCS, TintC1) 返回自動分配的色彩空間名(Sep1、Sep2、…), 可直接配合 THPDFPage.SetFillColorSpace / SetStrokeColorSpace + SetFillColor([tint]) / SetStrokeColor([tint]) 使用,其中 tint ∈ [0..1] 表示 spot 油墨的濃度。
  • AlternateCS 接受 DeviceGray、DeviceRGB 或 DeviceCMYK;TintC1 描述 tint=1.0 時的備用色彩。HotPDF 自動構造線性 Function Type 2 作為 tint transform,無 spot 支援的閱讀器在 tint=0(無墨)與 TintC1 (滿墨)之間平滑插值。
  • Pantone 等含空格的油墨名可直接傳入,HotPDF 在寫出 PDF 名字時按 PDF 1.7 7.3.5 自動轉義為 "#20" 序列。
  • 接口經過 RequirePDFVersion 限制為 PDF 1.3 及更高版本,避免嚴格模式 1.2 / 更舊輸出意外引入新特性。

2026-05-14 Version 2.44.0

  • 新增 CIELab 色彩空間支援,符合 ISO 32000-1 8.6.5.3。新方法 THotPDF.RegisterLabColorSpace(Xw, Yw, Zw, aMin, aMax, bMin, bMax) 返回自動分配的色彩空間名(Lab1、Lab2、...),可直接配合 THPDFPage.SetFillColorSpace / SetStrokeColorSpace + SetFillColor([L, a, b]) / SetStrokeColor([L, a, b]) 使用。
  • 典型流程:每種光源各註冊一個空間(ICC 印刷常用 D50,sRGB 顯示常用 D65),用 L* 取值 [0..100],a*、b* 取值 [-128..127] 繪製。Adobe Acrobat、Foxit、MuPDF、瀏覽器內置閱讀器都會按 WhitePoint 把 Lab 轉換為設備 RGB。
  • 接口經過 RequirePDFVersion 限制為 PDF 1.3 及更高版本,避免嚴格模式 1.2 / 更舊輸出意外引入新特性。

2026-05-14 Version 2.43.1

  • 在真實位圖上端到端驗證現有 CCITTFaxDecode 編碼器:240×120 pf1bit 黑白條紋 TBitmap 分別經 icCCITT31(G3 1D)、icCCITT32(G3 2D)、 icCCITT42(G4 / T.6)三種模式嵌入 PDF,壓縮比按預期排序 G3-1D > G3-2D > G4,Adobe Acrobat / Foxit / MuPDF 解碼均無警告,逐像素採樣確認黑白條紋三種模式都能完美還原。本次僅補充 PDF 1.7 ISO 32000-1 7.4.9 的 smoke 覆蓋,編碼器代碼未改動。

2026-05-14 Version 2.43.0

  • 新增未著色 Tiling Pattern(PaintType=2)的端到端渲染支援,符合 ISO 32000-1 8.6.6.1。瓷磚流只描述幾何,顏色透過頁面 scn / SCN 操作符的 tint 參數在填充 / 描邊時傳入。
  • THPDFPage 新增 SetFillPatternRGB / SetStrokePatternRGB / SetFillPatternGray / SetStrokePatternGray / SetFillPatternCMYK / SetStrokePatternCMYK 方法,接收 RegisterTilingPattern 返回的圖案名以及 DeviceRGB / DeviceGray / DeviceCMYK 的 tint 顏色分量(取值 0..1)。每個呼叫會在首次使用時為頁面自動註冊對應的 [/Pattern /BaseCS] 著色空間。
  • 已有 SetFillPattern / SetStrokePattern 繼續覆蓋 PaintType=1(已著色) 情形 —— 瓷磚自帶顏色,scn 操作符不需要 tint 參數。
  • RegisterTilingPattern 入口保持不變:Colored=true 寫 PaintType=1, Colored=false 寫 PaintType=2。

2026-05-14 Version 2.42.0

  • 新增 PDF 1.4 軟掩膜(SMask)圖像支援。新方法 THotPDF.AddImageWithSMask 接收一段原始 RGB 像素資料與一段對應的 8 位 alpha 資料,分別輸出彩色圖像 XObject 與 DeviceGray 軟掩膜 XObject,並按 ISO 32000-1 8.9.5.4 自動寫入 /SMask 引用關係。返回的圖像索引可繼續走 ShowImage 渲染,無需額外接線。
  • 新增便捷封裝 THotPDF.AddImageWithSMask32,可直接從 32 位 BGRA 的 TBitmap 拆出彩色與 alpha 通道,讓帶 alpha 的 PNG 風格位圖能一次嵌入。
  • 上述接口均透過 RequirePDFVersion 限制為 PDF 1.4 及更高版本,避免嚴格的 1.3 輸出意外引入新版本特性。

2026-05-14 Version 2.41.0

  • 新增 PDF 1.5 物件流輸出。同時啟用 THotPDF.UseObjectStreams 與 UseXRefStream 後, SaveToStream 會把可壓縮的間接物件(除 stream 物件、加密字典以及 trailer 引用的 Catalog / Info 字典外)打包到一個或多個 /Type /ObjStm 容器流中。
  • 對含有大量小字典的 PDF(多頁、註釋、AcroForm 控制項、結構樹節點、可選內容圖層等) 顯著減小文件體積。30 頁純圖形測試從 14502 字節縮減到 8488 字節(減少 41.5%), 視覺輸出保持一致。
  • 交叉引用流新增 type-2 壓縮物件條目,field-2 為宿主 ObjStm 物件號,field-3 為該物件在容器中的序號。若 UseXRefStream 未啟用(舊式 xref 表無法表達 type-2 條目)或 Version 低於 PDF 1.5,UseObjectStreams 會被自動降級為 false。

2026-05-12 Version 2.40.1

  • 修復在啟用 "Beta:使用 Unicode UTF-8 提供全球語言支援" 區域設置的 Windows 10 / 11 上生成的 PDF 在 Adobe Acrobat、Foxit、SumatraPDF、瀏覽器內置閱讀器中顯示空白頁的問題。 之前 HotPDF 會在每個頁面內容流開頭多寫 3 字節 UTF-8 BOM (EF BB BF),嚴格閱讀器視為語法錯誤,整頁拒絕渲染;MuPDF 等容錯閱讀器會跳過 BOM 正常顯示,因此問題在部分環境下不易察覺。

2026-05-11 Version 2.40.0

  • 新增 CID-keyed CFF 字體子集化,支援中日韓等大字符集 OpenType-CFF 字體,以及多 FD Adobe 字體。
  • 改進 CFF 子例程處理,大型 OpenType-CFF 字體現在可嵌入為更小的 PDF 子集字體,而不必整字體嵌入。

2026-05-11 Version 2.39.1

  • 改進真實 OpenType-CFF 字體相容性,覆蓋 Adobe MinionPro 類字體中較大的 CFF 表和多字節偏移結構。
  • 新增 HPDFExtractTTFPostScriptName,方便自定義字體載入流程讀取 TrueType 和 OpenType-CFF 字體中的 PostScript 名稱。

2026-05-11 Version 2.39.0

  • 新增 CFF Global Subr 和 Local Subr 子集化,進一步降低嵌入式 OpenType-CFF 字體體積。
  • 保留實際使用的 CFF 子例程字節碼,並將未使用條目安全替換為緊湊的 return stub。

2026-05-11 Version 2.38.0

  • StoreFont 新增 OpenType-CFF 自動嵌入。GDI 載入 sfnt 'OTTO' 容器時,HotPDF 會輸出 CFF-based CID 字體。
  • 新增 HPDFSfntIsOTF、HPDFOTFFindCFFTable 和 HPDFSubsetOTFContainer,供需要直接處理 OpenType-CFF 字體的應用呼叫。

2026-05-11 Version 2.37.0

  • 新增 HPDFSubsetCFF,用於 Compact Font Format 和 Type 1C 字體載荷,可生成更小的嵌入式 CFF 字體程序。
  • CFF 子集化會保留原始 glyph ID,確保現有 Type0 / Identity-H 文本輸出保持相容。
  • CFF 子集器已透過單元接口開放,適合使用自定義字體載入流程的應用直接呼叫。

2026-05-10 Version 2.36.0

  • 新增可選 TrueType 字體子集化。啟用 THotPDF.EnableFontSubsetting 後,只嵌入實際使用字形,可顯著減小 PDF 體積。
  • 新增符合 PDF 規範的子集字體命名,同時保留源字體 glyph ID,相容 Identity-H 文本輸出。
  • 預設仍使用完整字體嵌入,保證需要完整字體程序的工作流程不受影響。

2026-05-10 Version 2.35.1

  • 修復使用 Windows 替代字體生成的 PDF 在 Adobe Acrobat 中可能觸發的 "Font Capture" 崩潰。HotPDF 現在會讓 PDF 字體名稱與內嵌 TrueType 資料中的 PostScript 名稱保持一致。

2026-05-10 Version 2.35.0

  • 新增 PDF 增量更新支援,可保留源文件字節,並透過 THotPDF.SaveIncrementalUpdate 追加合規的增量修訂。
  • 新增 THotPDF.MarkDirty,應用可在增量更新中顯式標記需要重新保存的物件。
  • 支援多簽章工作流程,可在保留既有簽章 ByteRange 的前提下追加後續簽章欄位或文件修改。

2026-05-10 Version 2.34.0

  • 新增 THPDFPage.SetAnnotationBorderStyle,支援 Solid、Dashed、Beveled、Inset 和 Underline 等註釋邊框樣式。
  • 新增 Popup 註釋關聯能力,彈出註釋可引用父註釋,閱讀器中會顯示預期的批註連接關係。
  • 新增 THPDFPage.LastAnnotation,便於在不改變現有註釋建立接口的情況下繼續設置樣式或 Popup。

2026-05-10 Version 2.33.0

  • 新增 PDF Public-Key Security Handler。文件現在可使用 X.509 證書接收者加密,而不只依賴共享密碼。
  • 新增 THotPDF.EnablePubKeyEncryption 和 THotPDF.AddPubKeyRecipient,用於證書接收者加密流程。
  • HPDFCrypt 新增純 Pascal SHA-1 支援,並保留現有哈希原語。

2026-05-10 Version 2.32.0

  • 新增頁面級透明組。THPDFPage.SetTransparencyGroup 和 SetTransparencyGroupICC 可讓透明 PDF 內容合成結果更可預測。
  • 支援 DeviceGray、DeviceRGB、DeviceCMYK、省略顏色空間,以及 ICC 設定檔透明組。
  • 新增 THPDFPage.ClearTransparencyGroup,用於移除已設置的頁面透明組。

2026-05-09 Version 2.31.0

  • 為 AcroForm 按鈕新增交互動作支援。此前 HotPDF 生成的按鈕控制項外觀正常但點擊無效果;現在按鈕可執行:提交表單資料、重置欄位値、執行 JavaScript 腳本或跳轉至 URI。
  • 提交表單動作將當前 AcroForm 欄位値發送到伺服器 URL,可在 Adobe Reader 和 Foxit 中無需單獨 Web 閱讀器直接實現基於 PDF 的資料收集表單。
  • 重置表單動作將所有欄位恢復為預設値,可選僅針對指定欄位子集。JavaScript 和 URI 動作遵循 v2.26.0 引入的 PDF 版本門控機制。
  • 此前 AddPushButtonWithAction 僅接受按鈕控制項的視覺屬性;此版本後,按鈕外觀與點擊行為均可在單次呼叫中完整控制。

2026-05-09 Version 2.30.0

  • 新增全屏演示 PDF 頁面轉場,THPDFPage.SetPageTransition 可設置頁面切換動畫。
  • 新增 THPDFPage.SetPageDuration,頁面可按指定延遲自動前進。
  • 新增 Fly、Push、Cover、Uncover、Fade 等 PDF 1.5 轉場樣式的版本感知處理。

2026-05-09 Version 2.29.0

  • 新增 ViewArea 和 ViewClip 屬性,完成 PDF 1.4 ViewerPreferences 頁面邊界集,與已有的 PrintArea 和 PrintClip 形成完整配套。
  • ViewArea 控制閱讀器用於屏幕顯示的頁面框(MediaBox、CropBox、TrimBox、BleedBox 或 ArtBox);ViewClip 控制屏幕顯示時的裁切邊界——對包含出血和裁切標記、正常預覽時不應顯示的設計審稿 PDF 尤為重要。
  • 這兩個選項在印前檢查和列印預覽工作流程中尤為有用,允許屏幕裁切與列印裁切獨立設置。兩個屬性均要求 PDF 1.4,目標版本較舊時自動省略。

2026-05-09 Version 2.28.0

  • 新增 THotPDF.AutoFormAppearances,可為文本框、列表、按鈕、複選框和單選按鈕自動生成 AcroForm 外觀流。
  • 自動外觀模式會加入 Helvetica 和 ZapfDingbats 預設資源,讓忽略 /NeedAppearances 的閱讀器也能可靠顯示錶單。
  • AutoFormAppearances 預設關閉,保持舊版 AcroForm 行為相容。

2026-05-09 Version 2.27.0

  • 將 PDF 版本門控擴展至 ViewerPreferences 和 PageMode 條目。各偏好設定値現在強制執行其最低 PDF 版本要求:UseAttachments 和 UseOC 需要 PDF 1.5,PrintScaling 需要 PDF 1.6,Duplex、NumCopies 和 PickTrayByPDFSize 需要 PDF 1.7。
  • 針對舊版 PDF 的文件會自動省略不支援的檢視器偏好設定條目,避免在嚴格 PDF 處理器和歸檔驗證器中產生警告或靜默誤解。
  • 啟用 THotPDF.StrictVersionLock 後,PDF 1.3 或 PDF 1.4 輸出不會攜帶任何較新的檢視器偏好設定欄位,使文件符合印刷生產和長期歸檔工作流程的規範要求。

2026-05-09 Version 2.26.0

  • 對此前忽略目標版本的部分舊功能 API 新增 PDF 版本門控。註釋類型、JavaScript 動作、Type 0 字體、ToUnicode CMap 及 Catalog 附加動作,現在會在寫入前驗證文件版本是否支援該功能。
  • 目標為 PDF 1.0 或 PDF 1.1 的文件在使用較新功能時會自動升級到所需版本,避免生成不符合規範的 PDF,且無需修改呼叫代碼。
  • 啟用 THotPDF.StrictVersionLock 後,需要版本升級的功能呼叫將被拒絕而非靜默升級,適用於必須以指定 PDF 版本輸出的工作流程。
  • 該版本檢查機制在 v2.27.0 擴展至 ViewerPreferences 和 PageMode,並在 v2.31.0 前覆蓋所有主要功能領域。

2026-05-09 Version 2.25.0

  • 修復 PDF 字典輸出中的鍵名大小寫敏感性問題,符合 PDF 規範要求。此前,僅大小寫不同的相關鍵名——如 ExtGState 字典中的 /ca(填充透明度)和 /CA(描邊透明度)——被錯誤地合併為一條,導致其中一個値被靜默丟失。
  • 此修復恢復了在同一圖形狀態中對每個填充和描邊分別設置透明度的正確行為。Adobe Acrobat、Foxit 和瀏覽器 PDF 閱讀器均可正確渲染修復後的輸出。
  • 公開的字典查詢 API 仍保持大小寫不敏感,讀取存在鍵名大小寫不一致的非規範 PDF 時,現有代碼無需修改。

2026-05-09 Version 2.24.0

  • v2.4.0 之後新增的功能 API 增加 PDF 版本門控,說明生成文件保持在選擇的 PDF 版本範圍內。
  • 新增 THotPDF.StrictVersionLock。關閉時 HotPDF 會按需自動提升文件版本;開啟時,超過目標版本的功能呼叫會被拒絕。
  • ConfigurePDFVersion 現在會防止 XRef 流、XMP 中繼資料、Tagged PDF 和 AES-256 選項洩漏到較舊 PDF 目標。

2026-05-09 Version 2.23.0

  • 新增三步數字簽章工作流程,用於集成外部 PKI 和 CMS / PKCS#7 簽章庫:建立帶佔位符的簽章域,計算待簽章的字節範圍和摘要,最後在外部簽章完成後注入完整的 CMS 簽章。
  • 字節範圍策略確保哈希値覆蓋簽章容器以外的文件內容,與 PDF 簽章驗證器和 PAdES 一致性檢查器的要求完全吧合。
  • 所有加密操作——證書鏈、CMS 結構、時間戳令牌——均由呼叫方的外部簽章庫(OpenSSL、Windows CAPI、Bouncy Castle 等)負責,使 HotPDF 獨立於任何 PKI 基礎設施。
  • 支援多簽章文件:每個附加簽章作為增量更新追加,不重新生成整個 PDF,也不覆蓋先前的簽章字節範圍。

2026-05-09 Version 2.22.0

  • 新增 PDF 2.0 AES-256 V=5 R=6 標準安全處理器,可透過 THotPDF.UseAES256R6 啟用。
  • HPDFCrypt 新增純 Pascal SHA-384 和 SHA-512。
  • 新增 PDF 2.0 hash-dance 輔助邏輯,用於 Acrobat DC 和 PDF/A-4 相關加密工作流程。

2026-05-09 Version 2.21.0

  • Tagged PDF 從基礎標記擴展為完整的 PDF 可訪問性結構樹。
  • 新增角色映射、頁面 StructParents 分配和 ParentTree 輸出,便於 PDF/UA 驗證器遍歷結構樹。
  • 改進 StructTreeRoot 處理,後續 Tagged PDF 呼叫會更新同一個文件結構。

2026-05-09 Version 2.20.0

  • 新增頁面級 /UserUnit 和 /Tabs 支援,對應 THPDFPage.SetUserUnit 和 THPDFPage.SetTabsOrder。
  • 新增 Optional Content(PDF 圖層),包括 THotPDF.RegisterOptionalContentGroup 和 BeginOptionalContent / EndOptionalContent。
  • 新增 ExtGState 輔助接口,用於透明度 alpha 和混合模式設置。

2026-05-09 Version 2.19.0

  • 新增 CropBox、BleedBox、TrimBox、ArtBox 和頁面旋轉輔助接口,服務印刷和生產 PDF 工作流程。
  • 新增 THotPDF.AddStructureElement,可構建包含角色、頁面鏈接和 MCID 引用的 Tagged PDF 結構樹。
  • 新增平鋪圖案支援,可用於重複的彩色或非彩色 PDF 圖案填充和描邊。

2026-05-09 Version 2.18.0

  • 新增 THPDFPage.DrawInlineImage,小型柵格圖像可直接寫入頁面內容流。
  • 新增多段軸向漸變,用於更平滑的 PDF 色彩過渡效果。
  • 新增 OutputIntents 支援,服務 PDF/A、PDF/X 和色彩管理出版流程。

2026-05-09 Version 2.17.0

  • 新增 AES-256 標準安全處理器(PDF 1.7 擴展級別 3),適用於需要比預設 AES-128 更強保護的文件。加密後的 PDF 可在 Adobe Acrobat 9 及更高版本、Foxit Reader、Google Chrome、Apple Preview 及所有現代 PDF 閱讀器中開啟。
  • 使用者密碼和所有者密碼均按 Adobe 擴展級別 3 規範採用 SHA-256 哈希推導,確保與任何合規 PDF 解密器的相容性,無需自定義支援。
  • 此版本的 AES-256 加密為可選啟用;現有 AES-128 路徑仍為預設,以保持與舊版 Acrobat 的向後相容性。
  • v2.22.0 進一步新增 PDF 2.0 AES-256-R6,採用改進的密鑰派生算法,滿足 Acrobat DC 和 PDF/A-4 工作流程的最高安全強度需求。

2026-05-09 Version 2.16.0

  • 新增六種註釋子類型,面向多媒體、法律合規及無障礙訪問場景:Watermark(顯示與列印水印覆蓋層)、Redact(標記待刪除內容區域)、Screen(嵌入影片和音頻)、3D(交互式 U3D/PRC 模型檢視器)、RichMedia(交互式媒體內容)以及 Popup(關聯父註釋的評論氣泡)。
  • Watermark 註釋支援分離的顯示和列印渲染,可在屏幕上顯示“草稿”或“機密”標記而不列印,或僅在列印時顯示。
  • Redact 註釋標記內容區域以備分發前刪除;閱讀器的標註清除工作流程在最終應用前保留原始內容,避免不可逆操作。
  • 六種註釋類型均設有 PDF 版本門控,目標版本低於相應要求時,較新的註釋子類型將自動從輸出中省略。

2026-05-09 Version 2.15.0

  • 新增 Type 3 字體支援,可將自定義矢量字形定義直接嵌入 PDF 輸出。Type 3 字體非常適合公司徽標、專有符號集、地圖圖標及無法用標準字體表達的圖形符號。
  • 每個字形均以 PDF 內容流形式使用標準繪圖操作符定義,因此 Type 3 字形在任何縮放比例和列印精度下均保持清晰,無需外部字體文件。
  • 完整工作流程——註冊字體、定義各字形、在頁面上選用字體——透過 RegisterType3Font、AddType3Glyph 和 SetType3Font 完成。
  • Type 3 字體可在 Adobe Reader、Foxit 及所有規範相容的 PDF 閱讀器中正確渲染,無需在閱讀器系統上安裝字體。

2026-05-09 Version 2.14.0

  • 新增純 Pascal 實現的 AES-256 和 SHA-256,作為更強文件加密的內部加密原語。這兩種算法是 PDF 1.7 擴展級別 3 及 PDF 2.0 加密標準所要求的。
  • 新加密代碼無需外部 DLL 或操作系統提供的加密庫,使 HotPDF 在所有受支援的 Delphi 和 C++Builder 目標及 Windows 版本上保持自包含。
  • AES-128 仍為此版本的預設文件加密格式;新加密原語為 v2.17.0 的 AES-256 安全處理器和 v2.22.0 的 PDF 2.0 安全處理器奠定基礎。

2026-05-09 Version 2.13.0

  • 新增 PDF 矢量漸變填充:軸向(線性)漸變和徑向漸變。矢量漸變生成的 PDF 文件遠小於等效的位圖漸變,且在任何縮放比例和列印精度下均保持清晰。
  • 兩種漸變類型均支援 DeviceGray、DeviceRGB 和 DeviceCMYK 顏色空間,覆蓋屏幕顯示、RGB 印刷和 CMYK 四色印刷工作流程。
  • 漸變可作為填充色或描邊色應用於頁面上的任意路徑,可在 Adobe Reader、Foxit、SumatraPDF 及所有現代 PDF 閱讀器中正確渲染。

2026-05-09 Version 2.12.0

  • 透過 THPDFPage.AddSignatureField 新增未簽章簽章域控制項。生成的 PDF 包含可視化簽章佔位區,外部 PKI 工作流程、簽章門戶及 CMS / PKCS#7 簽章庫可直接填入真實加密簽章。
  • 只要存在至少一個簽章域,AcroForm 簽章標誌即自動設置,無需額外呼叫即可保持文件規範合規。
  • 簽章域控制項可被 Adobe Acrobat、Foxit 及其他 PDF 簽章方案識別為可簽章欄位。完整的字節範圍簽章工作流程參見 v2.23.0。

2026-05-09 Version 2.11.0

  • 新增 Tagged PDF 基礎架構,符合 PDF/UA 及現代無障礙訪問標準要求。標籤文件包含邏輯閱讀順序和語義結構,屏幕閱讀器、輔助技術及文本提取工具均可藉助此結構正確處理內容。
  • THotPDF.EnableTaggedPDF 啟用文件結構樹,THotPDF.Lang 設置主文件語言,兩者均為無障礙一致性驗證所必需。
  • 標記內容操作符允許將頁面上的各繪圖操作標註語義角色(段落、標題、圖形等)和標識符,使生成的 PDF 支援正確的內容重排和屏幕閱讀提取。
  • 結構元素和標記內容標識符按頁面和文件分別管理,與 PDF 規範對多頁標籤文件的要求一致。

2026-05-09 Version 2.10.0

  • 新增 PNG 預測器和 TIFF 水平差分預測器,用於 FlateDecode 圖像流。預測器在壓縮前對每行資料進行自適應濾波,可顯著減小攝影圖像和漸變圖像的輸出體積。
  • PNG 最優預測器(自適應行模式)和 TIFF 預測器 2(水平差分)作為獨立編碼輔助函數提供,可在自定義圖像嵌入流程中單獨使用。
  • 兩種預測器均支援 DeviceGray、DeviceRGB 和 DeviceCMYK 顏色空間,覆蓋屏幕顯示和四色印刷生產流程。

2026-05-09 Version 2.9.0

  • 在傳統 Info 字典之外新增 XMP 中繼資料流輸出。XMP 是嵌入式 PDF 中繼資料的現代標準,PDF/A、PDF/X 及眾多歸檔工作流程均要求支援。
  • 桌面搜索引擎、數字資產管理系統及不再讀取舊 Info 字典的 PDF 處理流程均可識別 XMP 中繼資料。
  • XMP 流在輸出文件中保持不壓縮,方便外部工具和命令列實用程序直接檢查中繼資料內容,無需解碼文件。
  • 需要精確控制中繼資料的應用,可透過 THotPDF.CustomXMP 提供完整的自定義 UTF-8 XMP 資料包,跳過自動生成邏輯。
  • 啟用文件加密時,XMP 流預設隨文件一起加密,保證中繼資料的保密性。

2026-05-09 Version 2.8.0

  • 新增可選的 PDF 1.5 交叉引用流輸出。交叉引用流以緊湊的二進制格式編碼物件偏移量表,替代傳統的大段純文本,使每個生成的 PDF 文件均可獲得體積減小的收益。
  • PDF 1.5 特性(如 v2.41.0 引入的物件流)依賴交叉引用流;目標版本低於 1.5 時該選項自動關閉。
  • 使用交叉引用流的 PDF 可被現代閱讀器、歸檔工具和 PDF/A 驗證器更高效地處理。
  • 傳統純文本 xref 表仍為預設輸出,以相容舊版 PDF 閱讀器和嚴格格式校驗工具。

2026-05-09 Version 2.7.0

  • 新增原生 DeviceCMYK 顏色輸出,適合印刷和 PDF/X 工作流程。
  • 新增 THotPDF.RegisterICCProfile,用於註冊 ICCBased 顏色空間。
  • 新增通用填充和描邊顏色空間 API,支援 ICC 設定檔和任意分量顏色值。

2026-05-09 Version 2.6.0

  • 新增 Highlight、Underline、Squiggly 和 StrikeOut 文本標記註釋。
  • 新增 Polygon、Polyline、Ink 和 Caret 註釋。
  • 新增 GoTo、GoToR 和 Launch 鏈接動作,用於文件內跳轉、跨文件跳轉和外部文件啟動。

2026-05-09 Version 2.5.0

  • 新增 AcroForm 支援,包括文本框、複選框、單選按鈕、下拉框、列表框和按鈕。
  • 新增 THPDFFormFieldFlags,應用可直接配置常用表單欄位選項,無需手工處理位標誌。
  • 生成的表單會設置 /NeedAppearances,常見 PDF 閱讀器可自動顯示欄位。

2026-05-08 Version 2.4.0

  • 修復 AES-128 PDF 加密。V=4 / R=4 安全處理器現在會真正用 AES-CBC 加密字串和流。
  • CryptKeyLength=aes128 現在會生成可由合規閱讀器用配置密碼開啟的加密 PDF。
  • 新增 ASCIIHexDecode、ASCII85Decode 和 RunLengthDecode 編碼輔助函數。
  • 更新內置 JBIG2 和 JPEG 2000 stub,未鏈接真實解碼後端時會明確報告不支援,而不是返回佔位圖像資料。

2026-05-06 Version 2.3.23

  • 調整內置 zlib-ng、libjpeg-turbo 和 libtiff 物件構建,以適配當前 RAD Studio 和 Visual Studio 工具鏈。
  • 改進 Delphi 和 C++Builder 目標上的原生壓縮與圖像庫堆內存對齊。
  • 驗證 Delphi 和 C++Builder 自動化迴歸測試在 Win32、Win64 和 Win64x 目標上的執行結果。

2026-05-05 Version 2.3.22

  • 內置 64 位 Flate 壓縮構建啟用 zlib-ng 執行時 SIMD 調度。
  • Win32 zlib-ng 保持在穩定的 generic object 路徑,相容經典工具鏈。
  • 加強原生物件構建檢查,編譯器成功但未生成輸出物件時會視為構建失敗。

2026-05-05 Version 2.3.21

  • 內置 Win32、Win64 和 Win64x 物件構建啟用 libjpeg-turbo SIMD 加速。
  • SIMD 支援改為透過 HotPDF 構建標誌顯式控制。
  • 修復 Win32 NASM OMF 輸出問題,解決 Delphi Win32 無法鏈接 SIMD JPEG 物件集的問題。
  • 修復 SIMD 與 zlib-ng 重建後暴露的 Win64 TIFF 圖像迴歸。

2026-05-05 Version 2.3.20

  • 內置 Flate 後端切換到 zlib-ng 相容模式,覆蓋頁面流、字體、CMap、圖像、TIFF 輸出和 FlateDecode 輔助函數。
  • 修復 zlib-ng 遷移中發現的密集流壓縮和 TIFF 小圖導入問題。
  • JPEG 工作流程繼續由 libjpeg-turbo 支援,TIFF 工作流程繼續由 libtiff 支援。
  • 新增覆蓋 Delphi 和 C++Builder 的自動化迴歸測試,包含 PDF 生成、圖像導入、壓縮、加密、 鏈接、頁面設置和複製/合併/編輯流程。

2026-05-01 Version 2.3.19

  • 修復密集條碼輸出下的 Win64 FlateDecode 頁面流生成問題。
  • 現代 Delphi 頁面流和字體流壓縮改用穩定的 RTL zlib 路徑。

2026-05-01 Version 2.3.18

  • 修復 C++Builder Win64x 加密 PDF 生成中的 RC4 指針寬度問題。
  • 修復 C++Builder Win64x 構建中的 TIFF 導入問題。
  • 修復 LoadFromFile 開啟的 PDF 追加頁面流程,確保追加頁以安全物件編號保存。

2026-05-01 Version 2.3.17

  • 更新 CanvasDrawing 和 GraphicDraw C++Builder 範例,使其與改進後的 Delphi 圖形範例保持一致。
  • 改進 ViewerPref C++Builder 範例,增加清晰的 UI 狀態、輸入驗證、預設保存/載入和方向測試輸出。

2026-05-01 Version 2.3.16

  • 修復合併含嵌入式 CID TrueType 字體和嵌套寬度數組的 PDF 時頁面複製錯誤。
  • 改進從多個源 PDF 連續複製頁面時的物件映射,避免後續頁面複用舊資源。

2026-05-01 Version 2.3.15

  • 改進 ViewerPref Delphi 範例,僅在相關選項啟用時開放對應控制項。
  • ViewerPref 範例新增錯誤提示、複製份數驗證和命名預設保存/載入支援。

2026-05-01 Version 2.3.14

  • PDFmerge Delphi 範例改為自包含合併範例,可在需要時自動建立源 PDF。
  • 改進合併驗證、輸出索引和 UI 成功/失敗提示。

2026-05-01 Version 2.3.13

  • 改進 CanvasDraw 和 GraphicDraw Delphi 範例,使視覺輸出更清晰、更可重複。
  • 改進 GDI 字體路徑中的 TrueType 字體選擇,減少 raster fallback 導致的嵌入失敗。
  • 修復同一 PDF 中多段文本複用同一字體時的字符間距問題。
  • 字體嵌入錯誤資訊現在包含請求字體名和字符集,便於診斷。

2026-05-01 Version 2.3.12

  • 改進 CopyPage 範例,使其可直接複製包含非標準 /Pages 樹的 PDF,無需額外工具。
  • CopyPage 無論使用哪條複製路徑成功,都會寫入 FlateDecode 壓縮輸出。
  • 獨立 CopyPageFixed 範例已合併到主 CopyPage 範例中。

2026-05-01 Version 2.3.11

  • 生成的 PDF 預設以頁面適應窗口高度方式開啟。
  • 新增大量無 ps 前綴的預定義紙張尺寸名稱,覆蓋辦公、大幅面、繪圖、證件、照片和中日常用規格,並保留舊名稱相容。
  • Delphi 頁面尺寸範例重組為 LargeSize、NormalSize 和 SmallSize 項目。

2026-04-29 Version 2.3.10

  • 修復 RAD Studio XE7 包構建中的 TIFF 相容層問題。
  • 減少 RAD Studio 10 Seattle 和 10.1 Berlin 下的編譯警告。
  • 修正 RAD Studio ProductVersion 9.0 到 12.0 的命令列庫構建映射。
  • 恢復 RAD Studio ProductVersion 9.0 的命令列包構建。
  • 修復 RAD Studio XE2 Win64 構建,補齊 Win64 相容 stub 所需的 CRT vsnprintf 符號。
  • 舊版 Delphi 和 C++Builder 工程文件改用數字布爾值,提高相容性。

2026-04-29 Version 2.3.9

  • 修復 RAD Studio 10.1 Berlin 庫包構建,使包從 Lib 目錄編譯並穩定解析包內單元。
  • 修復舊 Delphi 編譯器上的 Trial 庫構建,移除 Trial 水印路徑中的 inline variable declaration。

2026-04-29 Version 2.3.8

  • 移除 RAD Studio 10.3 Rio 構建中 TIFF stream callback 路徑的廢棄 TStream.Seek 編譯警告。

2026-04-29 Version 2.3.7

  • 修復使用內置 libtiff 4.7.x 物件文件時的 TIFF-to-PDF 轉換問題。
  • 修復嚴格 Delphi 編譯設置下內置 zlib Pascal bridge 的 RAD Studio Win32 編譯問題。
  • 新增 TIFF-to-PDF 轉換路徑的 DUnitX 迴歸測試覆蓋。

2026-04-28 Version 2.3.5

  • 修復使用經典 Borland C++ Win32 編譯器重建內置 zlib、libjpeg-turbo 和 libtiff 源包的問題。
  • 重建並對齊隨附 Win32 和 Win64 第三方物件文件,提高 Delphi 和 C++Builder 構建可靠性。
  • 無公開 API 變更。現有 Delphi、C++Builder 和 RAD Studio 項目可將本版作為相容性更新使用。

2026-04-19 Version 2.3.3

  • 改進 RAD Studio 工程可靠性,避免宿主 INCLUDE 環境設置干擾 HotPDF 資源編譯。
  • 減少包構建中的重複資源警告,尤其是 RAD Studio 13.1 Florence 項目。

2026-04-19 Version 2.3.2

  • 包和範例工程輸出目錄會自動跟隨當前 RAD Studio 版本。
  • 改進 HotPDF370 包構建行為,避免舊資源文件與新生成資源一起鏈接。

2026-04-19 Version 2.3.1

  • C++Builder TextOut 範例現在可在受支援 RAD Studio 版本中免手工修改構建。
  • 修復 TextOut 範例 Win64x 重建流程,確保鏈接前已準備好所需資源文件。

2026-04-19 Version 2.3.0

  • 新增完整 C++Builder 13.1 Florence 支援,覆蓋 Win32、Win64 和 Win64x 目標。
  • 統一 Delphi 與 C++Builder 的 TextOut 重載可用性,同時保留舊 C++Builder 輔助名稱相容。
  • 清理 Delphi Win64 靜態鏈接,移除內置 zlib、libjpeg-turbo 和 libtiff 物件文件帶來的舊鏈接警告。
  • 改進 Win64x 包輸出,C++Builder 項目可透過常規 RAD Studio 搜索路徑找到生成的 HotPDF 庫。

2026-04-17 Version 2.2.1

  • 消除內置第三方壓縮和圖像庫在 Delphi Win32 下產生的鏈接警告。
  • 改進 Delphi 和 C++Builder 構建中 zlib、JPEG 和 TIFF 支援的靜態鏈接相容性。

2026-04-14 Version 2.2.0

  • 內置第三方庫升級到 zlib 1.3.2、libjpeg-turbo 3.1.90 和 libtiff 4.7.1。
  • 現代化 Win32 和 Win64 靜態鏈接,適配更新後的壓縮、JPEG 和 TIFF 庫。
  • 擴展使用 JPEG 或 TIFF 輸入的 PDF 生成場景相容性。
  • 更新 HTML help,使其匹配當前 HotPDF API、範例和庫佈局。

2026-04-13 Version 2.1.4

  • 修復 RAD Studio XE2 到 XE8 的 Win64 編譯問題。
  • 改進舊 Delphi 編譯器使用的內置物件文件相容性。
  • 移除可能觸發重複資源鏈接警告的舊包資源文件。
  • 修正 Delphi XE3 HotPDF 包工程中繼資料。

2026-04-12 Version 2.1.3

  • Delphi TestNumeric 範例擴展為實用的數值 PDF 輸出迴歸測試。
  • 增加小數、分數、整數和 PDF 重新載入行為驗證。
  • 可選調試輸出文件現在透過專用編譯開關啟用。
  • 更新調試日誌和數值輸出測試相關說明內容。

2026-04-10 Version 2.1.2

  • 改進 Win32 和 Win64 PDF 輸出中的嵌入字體渲染。
  • 修復在嵌入字體之間切換時字形渲染不完整的問題,包括 Calibri 等常見 Windows 字體。
  • 更新 FontTest 範例和生成的樣例 PDF,便於視覺檢查。
  • 刷新字體嵌入、Unicode 文本輸出和嵌入字體範例相關 HTML help。

2026-04-08 Version 2.1.1

  • 更新 Delphi 和 C++Builder ViewerPreferences 範例,使其匹配當前 HotPDF API。
  • 增加較新 PDF viewer preference 選項覆蓋。
  • 改進生成的範例輸出,使其只反映 UI 中選中的 viewer preference 設置。
  • 更新 ViewerPreferences 和相關文件屬性的 HTML help 頁面。