March 21, 2024

Viiisit [Laravel] - niklasravnsborg/laravel-pdf with mPDF 套用客製化的字型

#laravel#php#mpdf

前情提要

這次在工作上遇到中文字體無法解碼問題,
實際上的情況是:使用電腦可以讀取中文字體,但是在手機上卻不行的問題。

當時先思考到的是手機由於缺乏特定字型的支援,所以無法解讀,
因此,解決的辦法就是換掉字體。

不過,因為是承接別人寫的 code,在換之前,想先找出實際上被載入的字體是哪一個,
因此花了不少時間在看 mpdf 文件、別人的解法與建議。

稍微 memo 一下當時的脈絡:
由於缺乏特定字型的支援 -> 必須換字體 -> 移除實際上無法解析的字體 ->
透過 Stack Overflow, Perplexity, mpdf docs 等等綜合意見找出最適合這次的解法


關於 niklasravnsborg/laravel-pdf

niklasravnsborg/laravel-pdf 這個 open source 的底層是使用 mPDF,
是一個用於從 HTML 生成 PDF 文件的 PHP library。

mPDF 支持 Unicode、UTF-8 和 CJK(Chinese, Japanese, Korean),
可以在 Laravel 中使用 niklasravnsborg/laravel-pdf 輕鬆生成 PDF。
但,niklasravnsborg/laravel-pdf 已於 2023年8月22日 被標記為不再維護。

因為已經沒有在維護,加上我先以不更換套件的前提下,
試著找出可以使手機用戶也能讀取中文字的解法。

當時在查找時,透過這篇講述漢字 Unicode 範圍 (Han unification)
整理 Unicode 經常會使用到的內碼區域並透過 Regex 自動比對文字

就想到,可以到 mPDF 去找有沒有以 Unicode 對應的字!

因此,對應到 mPDF 本身有一段講到通用的 fonts 有哪些:
Unicode coverage of Free Fonts
就找到 CJK UNIFIED IDEOGRAPHS (U+4E00-U+9FFF) 相對應的字體了!


客製化字體

所以要如何新增想要的字體?

在專案本身的 config 資料夾裡有一個叫做 pdf.php 的檔案,
這檔案就是當要生成 pdf 時,所需要的設定檔。

在查看這套件是如何抓取 pdf.php 的參數時,發現還有 font_path, font_data 可以額外設定!

仔細看會發現有一個 useOTL 參數

:那是什麼??

  • 在 mPDF 中,useOTL 代表 OpenType Layout 功能,
    用於進行高級的排版控制,如連字、音標和其他特定字型設置。
    useOTL 設置為 255 or 0xFF 可以啟用特定字型的 OpenType 佈局功能,
    實現更複雜的呈現和樣式設定。
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

return [
// 新增以下兩種參數:
'font_path' => resource_path('fonts/'),
'font_data' => [
'notosanstc' => [
'R' => 'NotoSansTC-Regular.ttf',
'B' => 'NotoSansTC-Bold.ttf',
'useOTL' => 255,
],
]
];
最後,整理要設定的餐數:

小記

最終以 custom fonts 解決,
其實也可以直接使用 CJK UNIFIED IDEOGRAPHS 也就是 Unicode 對應的 U+4E00 - U+9FFF。

mPDF 文件上提供的字體有:
bitstreamcyberbit, hannoma, sun-exta,用這三種不需額外加字體。

不過,有鑑於整體網站使用的字體(考量到 UX),
最後還是選用 Google - Noto Sans TC fonts 來作為要更換的字體。

P.S.
之前也有使用 TCPDF 作為生成 pdf 的套件,
有興趣可以參考:Viiisit [PHP] - TCPDF Library in Laravel!


參考資料:
mpdf
Laravel PDF 导出