跳到內容

疑難排解:字型、子集化與標記

這些條目涵蓋引擎透過 NextPDF\Exception\FontNotFoundExceptionNextPDF\Exception\FontParsingException 拋出的字型解析(resolve)與剖析失敗,也涵蓋 CJK 涵蓋範圍診斷,以及影響標記輸出的結構樹問題。每個條目都會指出確切的例外或測試,讓你確認成因。

  • 症狀。 拋出 FontNotFoundException,訊息格式為 Font "<name>" not found. Searched: [<paths>]
  • 可能成因。 要求的字型家族或檔案路徑不存在、無法讀取,或位於執行階段無法存取的字型目錄中。字型資料本身可能有效,但引擎仍無法取得它。
  • 佐證/診斷。 getContext() 會回傳 font_namesearch_pathsfallback_attempted。檢視 search_paths,可看到引擎嘗試過的每個位置;檢視 fallback_attempted,可確認是否已嘗試過後備字型。
  • 解法。
    1. 比對要求的 font_name 與實際存在的字型檔案。
    2. 將存放字型的目錄加入已設定的字型目錄,或修正你傳入的路徑。
    3. 確認執行階段使用者具備該檔案的讀取權限。
    4. 重新執行該呼叫。
  • 相關。 例外參考
  • 症狀。 拋出 FontParsingException,訊息格式為 Failed to parse font file "<file>": <reason>
  • 可能成因。 字型檔案已找到,但內容無法使用——例如標頭遭截斷、表目錄無效,或缺少必要的表,如 headhheaOS/2
  • 佐證/診斷。 getContext() 會回傳 font_fileparse_errorparse_error 欄位會指出結構性問題所在。
  • 解法。
    1. 讀取 parse_error,找出結構性缺陷。
    2. 以同一字型且已知正常的副本替換該字型檔案。
    3. 重新執行該呼叫。
  • 相關。 例外參考
  • 症狀。 拋出 FontParsingException,其中 font_file 的值為 font-subset,且 parse_error 例如 Invalid head table: too shortInvalid hhea table: too shortInvalid maxp table: too shortFailed to unpack font data
  • 可能成因。 字型通過了初始載入,但子集化所需的某個表遭截斷或無法解開。子集化器會拒絕該字型,而不會輸出毀損的子集。
  • 佐證/診斷。headhheamaxp 表過短或解開失敗時,src/Typography/FontSubsetter.php 會拋出 FontParsingException,並使用字面 token font-subset 作為檔名。這個 token 表示失敗發生在子集化階段,而非初始載入。
  • 解法。
    1. 以同一字型的完整、未截斷副本替換來源字型。
    2. 如果字型是由建構工具產生,請重新產生並驗證 headhheamaxp 表是否完整。
    3. 重新執行建構。
  • 相關。 PDF/A 與 PDF/UA 驗證
  • 症狀。 中文、日文或韓文文字算繪成空白方框或缺字,且字型的 CJK 涵蓋範圍不確定。
  • 可能成因。 所選字型未涵蓋該文字系統所需的 Unicode 區塊。除了共用表意文字區塊外,每種 CJK 文字系統還需要各自的專屬區塊。
  • 佐證/診斷。 src/Typography/CjkFontValidator.php 提供 validateCoverage(FontInfo $font, CjkScript $script)。它會回傳一個 CjkCoverageResult,內含涵蓋百分比,以及低於 50% 回報門檻的區塊。驗證器會抽樣碼點;它是診斷工具,不會更動字型載入。
  • 解法。
    1. 針對該字型與目標文字系統執行 CjkFontValidator::validateCoverage()
    2. 檢視 missingRanges,確認哪些區塊未涵蓋——例如繁體中文的注音符號、日文的平假名與片假名、韓文的諺文音節。
    3. 選用涵蓋這些區塊的字型,或加入能涵蓋這些區塊的後備字型。
    4. 重新算繪,並再次檢查涵蓋範圍。
  • 相關。 例外參考

條目:預先定義的 CMap 與 CJK 文字系統不符

標題為「條目:預先定義的 CMap 與 CJK 文字系統不符」的區段
  • 症狀。 CJK 文字被對應到錯誤的字元圖形,或選用了與文件語言不符的預先定義 CMap。
  • 可能成因。 偵測到的文字系統會決定 Adobe 預先定義的 CMap 名稱。若字型只涵蓋共用表意文字區塊,且沒有任何文字系統專屬區塊,依設計會被偵測為簡體中文。
  • 佐證/診斷。 CjkFontValidator::detectScript() 會回傳偵測到的文字系統,而 resolvePredefinedCMapName() 會將它對映為:簡體中文對映到 UniGB-UTF16-H、繁體中文對映到 UniCNS-UTF16-H、日文對映到 UniJIS-UTF16-H、韓文對映到 UniKS-UTF16-H。若不存在任何文字系統專屬區塊,偵測會退回簡體中文。
  • 解法。
    1. 確認字型隨附文字系統專屬區塊:繁體中文的注音符號、日文的平假名或片假名,以及韓文的諺文。
    2. 如果文件是繁體中文,但字型不含注音符號區塊,請選用含有該區塊的字型,讓偵測能解析為你預期的文字系統。
    3. 重新算繪。
  • 相關。 例外參考

條目:標記內容未產生可用的結構樹

標題為「條目:標記內容未產生可用的結構樹」的區段
  • 症狀。 標記建構未產生任何結構,或下游無障礙檢查回報結構樹為空或缺漏。
  • 可能成因。 內容輸出時未經過標記路徑,因此沒有建立任何結構元素。結構樹會維持為空。
  • 佐證/診斷。 src/Accessibility/StructureTree.phpsrc/Accessibility/TaggedContentEmitter.php 會從標記內容建構結構樹。測試 tests/Integration/Accessibility/EmptyTaggedPdfDoesNotAdvertisePdfUa2Test.php 確認空的結構樹不會宣告為 PDF/UA-2。
  • 解法。
    1. 確認內容是透過標記路徑輸出,以便建立結構元素。
    2. 驗證每個標記內容序列都對映到一個結構元素。
    3. 重新執行建構並檢視結構樹。
  • 相關。 PDF/A 與 PDF/UA 驗證
  • 症狀。 建構失敗,因為結構元素或文件上的某個語言值不是有效標籤。
  • 可能成因。 提供的語言不是有效的 BCP-47 標籤。驗證器會拒絕格式錯誤的標籤,而不是將它輸出。
  • 佐證/診斷。 src/Accessibility/Bcp47Validator.php 會驗證標籤。無效標籤會引發 src/Accessibility/InvalidBcp47TagException.php。嚴格的 PDF/UA-2 語言要求由 tests/Unit/Conformance/PdfUa2Section844LangStrictTest.php 驗證。
  • 解法。
    1. 將語言值換成有效的 BCP-47 標籤,例如 en-USde-DEzh-Hant-TW
    2. 如果某段文字的語言與文件語言不同,請在該特定結構元素上設定語言。
    3. 重新執行建構。
  • 相關。 PDF/A 與 PDF/UA 驗證
  • FontNotFoundExceptionFontParsingException 是兩個不同的例外。找不到表示無法取得該檔案;剖析失敗表示已取得檔案,但它的位元組無法使用。讀取例外類別即可判斷是哪一種。
  • font-subset 出現在 font_file 中時,是子集化階段刻意設定的標記,並非實際路徑。不要去找名為 font-subset 的檔案。
  • CjkFontValidator 是抽樣碼點,而非逐一檢查每個碼點,因此它的涵蓋率是字型選擇用的估計值,不是逐位元組的精確稽核。
  • 空的結構樹依設計會被回報為非 PDF/UA-2。這是引擎已記載的行為,而非缺陷。

詞彙表:字型子集化 · CJK 涵蓋範圍 · 結構樹