mPDF は、PHP で PDF ファイルを生成するためのライブラリです。うちの会社で導入している InvoicePlan も、PDF 出力の部分は mPDF で処理していて、案の定、中国語の文字化け問題にぶつかりました。
mPDF 中国語 文字化け というキーワードで Google を検索すると、出てくる情報の多くはかなりあっさりしていて、だいたいこんな感じです:
$mpdf = new \Mpdf\Mpdf([
"autoScriptToLang" => true,
"autoLangToFont" => true,
]);
言われたとおりに試すと、たしかに中国語は出力できます。ただ、フォントが僕の欲しいものではありません。フォント設定のほうは、Google で調べ続けても有用な情報があまり見つからない。そこで思いきって、公式ドキュメントと合わせてソースコードから、中で何が起きているのかを調べてみました。
lang と font-family
mPDF がやっていることは、基本的には HTML コードを解析して、一つの PDF ドキュメントに組み立てて出力することです。出力の過程で、mPDF は HTML の lang と CSS の font-family という 2 つの属性から、どのフォントを使うかを判断します。
ドキュメント Fonts & Languages / lang 6.x によると、lang は OTL のグリフセットの設定に影響し、CSS の lang selector としても使えます。font-family のほうは、HTML ブロックの内容をどのフォントで出力するかを指定します。対応している HTML タグの詳しい一覧は CSS & Stylesheets / Supported CSS を参照してください。
autoScriptToLang と autoLangToFont を有効にするというのは、この 2 つの設定を省いて、システムに中身を力ずくで分解させ、どの lang と font-family を使うかを判断させることです。具体的には Mpdf.php の markScriptToLang() や、Language/LanguageToFont.php、Language/ScriptToLang.php あたりのファイルを見てください……本当になかなか力ずくです。ふつう、本文に簡体字が含まれていれば言語は lang="und-Hans" と判定され、繁体字なら lang="und-Hant"、フォントは繁体・簡体を問わず自動で font-family: sun-exta が選ばれます。
Free Adobe CJK Asian fonts
古い情報の中には、中国語をちゃんと表示させるには useAdobeCJK を有効にしろ、と書いてあるものがあります。このオプションは、ある意味で完全に地雷です。useAdobeCJK の意味はこうです。もし PC に Adobe Acrobat か関連ソフトが入っていれば、理屈のうえでは Adobe の CJK Asian フォントも入っているはずです。このオプションを有効にすると、PC に入っているフォントをそのまま使って表示できるので、フォントを PDF に埋め込む必要がなくなり、その分ファイルサイズを効果的に減らせます。
PDF と Adobe Acrobat の普及率を考えれば、この発想は間違っていません。問題は、時代が進んでいることです。useAdobeCJK が使う Adobe 標準の繁体字フォントは MSungStd-Light-Acro —— AddBig5Font() を参照 —— で、これはもう骨董品のフォントです。最近の PC にはほとんど入っておらず、オプションを有効にすると、かえって表示の問題を引き起こします。
公式ドキュメント mPDF Variables / useAdobeCJK によると、useAdobeCJK は 5.0 版から対応しています。GitHub でたどれる最も古いバージョンは 2011 年 9 月 14 日リリースの v5.3.0 ……この機能がどれだけ古いか、想像がつきます。それに、公式は useAdobeCJK のデフォルトを有効と書いていますが、僕がいま使っている mPDF v8.0.1 では、デフォルトはすでに無効になっています。
カスタムフォントに戻る
というわけで、いちばん確実な中国語の表示方法は、mPDF 付属の sun-exta 以外だと、自分でフォントを追加することです。幸い、この作業は mPDF がとても簡単にしてくれていて、手順は次の 3 つだけです:
- フォントファイルを配置する
- フォントディレクトリを指定する
- font-family とフォントファイルをひもづける
以下では、いま人気の 台北黑體(Taipei Sans TC) を例に使います。
フォントファイルを配置する
かんたんに言えば、フォントファイルを mPDF がアクセスできるディレクトリに置くだけです。台北黑體 にはいま Light・Regular・Bold の 3 種類があり、必要なのは Regular と Bold です。ダウンロードしたら、そのまま mpdf/ttfonts/ ディレクトリに置きます。
フォントディレクトリを指定する
カスタムフォントのディレクトリが mpdf/ttfonts/ でない場合(たとえば mPDF が vendor として置かれているだけの場合)は、フォントディレクトリを別途指定する必要があります。公式の例 はこんな感じです:
// デフォルトのフォントディレクトリ
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig["fontDir"];
$mpdf = new \Mpdf\Mpdf([
"fontDir" => array_merge($fontDirs, [
__DIR__ . '/custom/font/directory',
])
]);
font-family とフォントファイルをひもづける
HTML では、フォントに少なくとも標準・太字・斜体・太字斜体の 4 つのバリエーションがあります。そのため font-family の設定でも、必要に応じてそれぞれのフォントファイルに対応づけます。以下が fontdata の設定です:
// font-family 名
'freesans' => [
// 標準(Regular)
'R' => 'FreeSans.ttf',
// 太字(Bold)
'B' => 'FreeSansBold.ttf',
// 斜体(Italic)
'I' => 'FreeSansOblique.ttf',
// 太字斜体(Bold Italic)
'BI' => 'FreeSansBoldOblique.ttf',
],
台北黑體なら、こうなります:
// font-family 名
'taipei' => [
// 標準(Regular)
'R' => 'TaipeiSansTCBeta-Regular.ttf',
// 太字(Bold)
'B' => 'TaipeiSansTCBeta-Bold.ttf',
],
上の R B I のほかにも、フォント設定には SIP-extension、useOTL など、たくさんのパラメータがあります。詳しくは Fonts & Languages / Fonts in mPDF v7+ を参照してください。
fontDir と fontdata の設定をまとめる
// デフォルトのフォントディレクトリ
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig["fontDir"];
// カスタムフォントディレクトリを追加
$fontDirs = array_merge($fontDirs, [__DIR__ . '/custom/font/directory']);
// デフォルトのフォント設定
$defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults();
$fontData = $defaultFontConfig["fontdata"];
// フォント(font-family)を追加
$fontData = [
'taipei' => [
// 標準(Regular)
'R' => 'TaipeiSansTCBeta-Regular.ttf',
// 太字(Bold)
'B' => 'TaipeiSansTCBeta-Bold.ttf'
]
] + $fontData; // 元の $fontData を必ず足すこと。でないと mPDF 内蔵のフォントが消えて使えなくなる
$mpdf = new \Mpdf\Mpdf([
"fontDir" => $fontDirs,
"fontdata" => $fontData
]);
テスト用の HTML:
<div style="font-size: 30px;">
<p style="font-family: taipei;">台北黑體 Regular:覺形創意有限公司</p>
<p style="font-family: taipei; font-weight: bold;">台北黑體 Bold:覺形創意有限公司</p>
<p style="font-family: sun-exta;">宋體 Sun-ExtA:覺形創意有限公司</p>
</div>
出力すると、台北黑體の標準と太字、それに内蔵の宋体 sun-exta も、どれも中国語をちゃんと表示できます。だいたい、こんなところです。


