PDFのフォント欠落

更新: 2026-10-04
PDFフォントpdf-libfontkitテスト

PDFに日本語を描くとき、使うフォントに字形がない文字を渡すと、エラーも警告も出ずに「☒」になる。 型検査も、単体テストも、lintも通る。PDFを開いて初めて気づく。

ここには、実際にこれが起きたときの再現と、置き換えの表、ソースの文字列をフォントと照合して再発を止めるテストの作り方を置く。

何が起きたか

PDFを作るコード(pdf-lib)で、埋め込んでいるフォントは @openfonts/noto-sans-jp_japanese の日本語サブセットだった。このフォントには、次の文字の字形がない。

文字例置き換え
丸数字① ② ③ ④ ⑤ ⑥数字(1、2、3)
三角△ ▲文字ではなく、三角形の図形で描く
米印※「注意:」または「*」
四角□「[ ]」
全角チルダ~(U+FF5E)波ダッシュ 〜(U+301C)。こちらはフォントにある

ASCIIの記号と、全角の数字・かな・漢字は、フォントにある。

描く文字列例: 欄の番号 ①フォントに字形がある?ある文字として出るない「☒」で出るエラーも警告も出ない。tsc・テスト・lintも通る気づけるのはPDFを開いたとき
字形がない文字は、描く時点では失敗にならない。出力されたPDFにだけ現れる。

見つかった場所

別表十四(決算書類のひとつ)の値出力PDFを実際に出力して開き、欄の番号が「☒」になっているのを見つけた。そこで、PDFを作るソース33ファイルの文字列を、フォントの字形と照合した。

  • 別表十四のPDF: 欄の番号(①〜⑥)。この出力で見つかった
  • 請求書PDF: 注記の印と凡例の「※」
  • 貸借対照表PDF: 警告の頭の「※」
  • 手入力確認PDF 2本: チェックリストの「□」

最初の1つ以外は、前からあったコードだった。新しく書いたコードの検査では、古いコードの同じ穴は見つからない。 出力を開いたことと、全ファイルを照合したことで、同じ原因をまとめて拾えた。

再発を止めるテスト

ソースの文字列を、実際に埋め込むフォントの字形表と照合して、1つでも欠けていればテストを落とす。

PDFを作るソースを集めるコメントを除いて非ASCIIを取り出すフォントの字形表と1文字ずつ照合欠けていればテストが失敗対象: ファイル名にpdfを含むもの、taxForms/ と pdf/ の配下(テストのファイルは除く)例外: 文字を図形で描くファイルは、理由とあわせて登録(例: 負の値の「△」を三角形で描く)空振り防止: 対象が20ファイル超あること、前提のフォントの状態も別のテストで確かめる
検査が空振りしていないことと、前提のフォントが変わっていないことも、テストで確かめる。

字形の有無は、@pdf-lib/fontkit の hasGlyphForCodePoint で引ける。フォントの読み込みは次の形だ。

import fontkit from "@pdf-lib/fontkit";

// woff を ttf へ変換してから渡している
const font = fontkit.create(woffToTtf(readFileSync(FONT_PATH)));
font.hasGlyphForCodePoint("①".codePointAt(0)!); // false
font.hasGlyphForCodePoint("法".codePointAt(0)!); // true

テストは3つに分けた。

  • 対象のファイルが見つかる(検査が空振りしていない)
  • フォントに丸数字・△・※・□がないことを前提にしている(フォントを替えたら、この検査を見直す)
  • 文字列に、フォントにない文字が入っていない

修正前のコードで、3つ目が失敗することを確かめてから、置き換えた。

注意

  • 置き換えで出力が変わる。 請求書の「※」を「*」に変えたように、利用者に見える印が変わる場合は、変えてよいかを先に確認する
  • コメントは描かないので、テストの対象から除いている。文字列の中に書いた文字だけが対象になる
  • 公式様式の背景画像に値を重ねる方式では、様式にもとから印刷された文字は画像なので影響を受けない。影響するのは、こちらが描く文字だけ
  • フォントを替えたら、「前提」のテストが落ちる。落ちたときは、置き換え表と例外の登録を見直す

この知見を得た日記

任せた実装が、型検査もテストも通っていたのに、PDFを開いたら欄の番号が「☒」だった。そこに至る経緯はminiに実装を任せた結果に書いた。同じ型の「通ったが、中身を見ていなかった」は、ガードが素通りする書き方にもある。この記事の対象になったPDF出力は、ちょうぼっちの機能のひとつだ。

WIKI一覧へ