← Writing

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

前情提要 這次在工作上遇到中文字體無法解碼問題, 實際上的情況是:使用電腦可以讀取中文字體,但是在手機上卻不行的問題。 當時先思考到的是手機由於缺乏特定字型的支援,所以無法解讀, 因此,解決的辦法就是換掉字體。 不過,因為是承接別人寫的 code,在換之前,想先找出實際上被載入的字體是哪一個, 因此...

laravelmpdfphp

前情提要

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

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

不過,因為是承接別人寫的 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 可以額外設定!

  • font_path: 要給定絕對路徑,讓套件能抓取裡面的字體檔案

  • font_data: 會根據提供的字體作為讀取

    備註:依照以下的設定,我把下載好的 NotoSansTC-Regular.ttfNotoSansTC-Bold.ttf, 事先放入 resource/fonts 裡。(fonts 是我自己新增的資料夾)

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

:那是什麼??

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

return [
    // 新增以下兩種參數:
    'font_path'             => resource_path('fonts/'),
    'font_data'             => [
        'notosanstc' => [
            'R' => 'NotoSansTC-Regular.ttf',
            'B' => 'NotoSansTC-Bold.ttf',
            'useOTL' => 255,
        ],
    ]
];
最後,整理要設定的餐數:
  • 下載自己要的字體,我選用 Google - Noto Sans TC fonts
  • font_path 有事先在 resource 資料夾裡新增 fonts 資料夾,並把下載好的(.ttf)檔案放到裡面
  • font_data 把下載好的(.ttf)檔案名稱寫進去
  • useOTL 設定為 255 or 0xFF

小記

最終以 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 导出