疑難排解:字型、子集化與標記
適用範圍
標題為「適用範圍」的區段這些條目涵蓋引擎透過 NextPDF\Exception\FontNotFoundException 與 NextPDF\Exception\FontParsingException 拋出的字型解析(resolve)與剖析失敗,也涵蓋 CJK 涵蓋範圍診斷,以及影響標記輸出的結構樹問題。每個條目都會指出確切的例外或測試,讓你確認成因。
條目:找不到字型
標題為「條目:找不到字型」的區段- 症狀。 拋出
FontNotFoundException,訊息格式為Font "<name>" not found. Searched: [<paths>]。 - 可能成因。 要求的字型家族或檔案路徑不存在、無法讀取,或位於執行階段無法存取的字型目錄中。字型資料本身可能有效,但引擎仍無法取得它。
- 佐證/診斷。
getContext()會回傳font_name、search_paths與fallback_attempted。檢視search_paths,可看到引擎嘗試過的每個位置;檢視fallback_attempted,可確認是否已嘗試過後備字型。 - 解法。
- 比對要求的
font_name與實際存在的字型檔案。 - 將存放字型的目錄加入已設定的字型目錄,或修正你傳入的路徑。
- 確認執行階段使用者具備該檔案的讀取權限。
- 重新執行該呼叫。
- 比對要求的
- 相關。 例外參考。
條目:字型檔案剖析失敗
標題為「條目:字型檔案剖析失敗」的區段- 症狀。 拋出
FontParsingException,訊息格式為Failed to parse font file "<file>": <reason>。 - 可能成因。 字型檔案已找到,但內容無法使用——例如標頭遭截斷、表目錄無效,或缺少必要的表,如
head、hhea或OS/2。 - 佐證/診斷。
getContext()會回傳font_file與parse_error。parse_error欄位會指出結構性問題所在。 - 解法。
- 讀取
parse_error,找出結構性缺陷。 - 以同一字型且已知正常的副本替換該字型檔案。
- 重新執行該呼叫。
- 讀取
- 相關。 例外參考。
條目:字型表毀損導致子集化失敗
標題為「條目:字型表毀損導致子集化失敗」的區段- 症狀。 拋出
FontParsingException,其中font_file的值為font-subset,且parse_error例如Invalid head table: too short、Invalid hhea table: too short、Invalid maxp table: too short或Failed to unpack font data。 - 可能成因。 字型通過了初始載入,但子集化所需的某個表遭截斷或無法解開。子集化器會拒絕該字型,而不會輸出毀損的子集。
- 佐證/診斷。 當
head、hhea或maxp表過短或解開失敗時,src/Typography/FontSubsetter.php會拋出FontParsingException,並使用字面 tokenfont-subset作為檔名。這個 token 表示失敗發生在子集化階段,而非初始載入。 - 解法。
- 以同一字型的完整、未截斷副本替換來源字型。
- 如果字型是由建構工具產生,請重新產生並驗證
head、hhea與maxp表是否完整。 - 重新執行建構。
- 相關。 PDF/A 與 PDF/UA 驗證。
條目:CJK 文字算繪時缺少字元圖形
標題為「條目:CJK 文字算繪時缺少字元圖形」的區段- 症狀。 中文、日文或韓文文字算繪成空白方框或缺字,且字型的 CJK 涵蓋範圍不確定。
- 可能成因。 所選字型未涵蓋該文字系統所需的 Unicode 區塊。除了共用表意文字區塊外,每種 CJK 文字系統還需要各自的專屬區塊。
- 佐證/診斷。
src/Typography/CjkFontValidator.php提供validateCoverage(FontInfo $font, CjkScript $script)。它會回傳一個CjkCoverageResult,內含涵蓋百分比,以及低於 50% 回報門檻的區塊。驗證器會抽樣碼點;它是診斷工具,不會更動字型載入。 - 解法。
- 針對該字型與目標文字系統執行
CjkFontValidator::validateCoverage()。 - 檢視
missingRanges,確認哪些區塊未涵蓋——例如繁體中文的注音符號、日文的平假名與片假名、韓文的諺文音節。 - 選用涵蓋這些區塊的字型,或加入能涵蓋這些區塊的後備字型。
- 重新算繪,並再次檢查涵蓋範圍。
- 針對該字型與目標文字系統執行
- 相關。 例外參考。
條目:預先定義的 CMap 與 CJK 文字系統不符
標題為「條目:預先定義的 CMap 與 CJK 文字系統不符」的區段- 症狀。 CJK 文字被對應到錯誤的字元圖形,或選用了與文件語言不符的預先定義 CMap。
- 可能成因。 偵測到的文字系統會決定 Adobe 預先定義的 CMap 名稱。若字型只涵蓋共用表意文字區塊,且沒有任何文字系統專屬區塊,依設計會被偵測為簡體中文。
- 佐證/診斷。
CjkFontValidator::detectScript()會回傳偵測到的文字系統,而resolvePredefinedCMapName()會將它對映為:簡體中文對映到UniGB-UTF16-H、繁體中文對映到UniCNS-UTF16-H、日文對映到UniJIS-UTF16-H、韓文對映到UniKS-UTF16-H。若不存在任何文字系統專屬區塊,偵測會退回簡體中文。 - 解法。
- 確認字型隨附文字系統專屬區塊:繁體中文的注音符號、日文的平假名或片假名,以及韓文的諺文。
- 如果文件是繁體中文,但字型不含注音符號區塊,請選用含有該區塊的字型,讓偵測能解析為你預期的文字系統。
- 重新算繪。
- 相關。 例外參考。
條目:標記內容未產生可用的結構樹
標題為「條目:標記內容未產生可用的結構樹」的區段- 症狀。 標記建構未產生任何結構,或下游無障礙檢查回報結構樹為空或缺漏。
- 可能成因。 內容輸出時未經過標記路徑,因此沒有建立任何結構元素。結構樹會維持為空。
- 佐證/診斷。
src/Accessibility/StructureTree.php與src/Accessibility/TaggedContentEmitter.php會從標記內容建構結構樹。測試tests/Integration/Accessibility/EmptyTaggedPdfDoesNotAdvertisePdfUa2Test.php確認空的結構樹不會宣告為 PDF/UA-2。 - 解法。
- 確認內容是透過標記路徑輸出,以便建立結構元素。
- 驗證每個標記內容序列都對映到一個結構元素。
- 重新執行建構並檢視結構樹。
- 相關。 PDF/A 與 PDF/UA 驗證。
條目:結構元素的語言標籤遭拒
標題為「條目:結構元素的語言標籤遭拒」的區段- 症狀。 建構失敗,因為結構元素或文件上的某個語言值不是有效標籤。
- 可能成因。 提供的語言不是有效的 BCP-47 標籤。驗證器會拒絕格式錯誤的標籤,而不是將它輸出。
- 佐證/診斷。
src/Accessibility/Bcp47Validator.php會驗證標籤。無效標籤會引發src/Accessibility/InvalidBcp47TagException.php。嚴格的 PDF/UA-2 語言要求由tests/Unit/Conformance/PdfUa2Section844LangStrictTest.php驗證。 - 解法。
- 將語言值換成有效的 BCP-47 標籤,例如
en-US、de-DE或zh-Hant-TW。 - 如果某段文字的語言與文件語言不同,請在該特定結構元素上設定語言。
- 重新執行建構。
- 將語言值換成有效的 BCP-47 標籤,例如
- 相關。 PDF/A 與 PDF/UA 驗證。
邊際情況與陷阱
標題為「邊際情況與陷阱」的區段FontNotFoundException與FontParsingException是兩個不同的例外。找不到表示無法取得該檔案;剖析失敗表示已取得檔案,但它的位元組無法使用。讀取例外類別即可判斷是哪一種。font-subset出現在font_file中時,是子集化階段刻意設定的標記,並非實際路徑。不要去找名為font-subset的檔案。CjkFontValidator是抽樣碼點,而非逐一檢查每個碼點,因此它的涵蓋率是字型選擇用的估計值,不是逐位元組的精確稽核。- 空的結構樹依設計會被回報為非 PDF/UA-2。這是引擎已記載的行為,而非缺陷。