0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPのGDで日本語が表示されない / could not find/open font の原因と解決(TTF配置と絶対パス)

0
Posted at

結論(先に解決策)

PHP の GD で OG 画像などを生成したとき、日本語が表示されない(空白・豆腐・文字化け)、または

imagettftext(): Could not find/open font
imagettfbbox(): Could not find/open font

が出る——原因はほぼ次の2つです。

  1. 日本語に対応した TTF/OTF フォントを指定していない(英語フォントだと日本語グリフが無く描画されない)
  2. フォントパスが相対パスになっている(GD のフォント指定は絶対パスが必要)

解決は 日本語フォント(例: IPAexGothic)を同梱し、__DIR__ 基準の絶対パスで渡すこと。

// ✅ __DIR__ 起点で絶対パスにする
$font = __DIR__ . '/assets/fonts/ipaexg.ttf';   // 日本語対応 TTF を同梱
imagettftext($img, 40, 0, 50, 100, $color, $font, '東京都の人口データ');

症状

  • 画像は生成されるが日本語部分だけ何も描かれない/英数字は出る
  • □□□(豆腐)になる
  • 次のエラーで生成が止まる
Warning: imagettftext(): Could not find/open font in ...
Warning: imagettfbbox(): Could not find/open font in ...

ローカルでは出たのに本番(別サーバー)に上げたら消える、CLI からは動くのにWeb から呼ぶと font が見つからない、というのも典型です。


原因

原因1: フォント自体が日本語を持っていない

GD は指定された TTF/OTF のグリフ(字形)しか描けません。Arial や DejaVu Sans のような欧文フォントには日本語のグリフが含まれないため、日本語は描画されません(エラーにならず「空白」になることが多く、気づきにくい)。

日本語対応フォント(IPAexGothic / Noto Sans JP / Migu など)を使う必要があります。

原因2: パスが相対で、解決に失敗している

imagettftext() / imagettfbbox()フォント引数は絶対パスが前提です。相対パスを渡すと「現在の作業ディレクトリ(CWD)」基準で解決されますが、この CWD は呼び出し経路で変わります

実行経路 CWD の例 相対パスの解決先
CLI でスクリプト直叩き スクリプトのある場所 たまたま当たる
Web(PHP-FPM)から docroot やサーバー既定 ずれる → not found
cron から ホームや / ずれる → not found

「ローカルの CLI では動くのに本番 Web で Could not find/open font」の正体はこれです。CWD に依存する相対パスをやめ、スクリプト位置を起点にした絶対パスにすれば経路によらず固定されます。

補足: 古い GD では先頭にスラッシュやドライブレターが無いパスを「システムフォントディレクトリ基準」と解釈する挙動もあり、ますます直感に反します。絶対パスで渡せば全部回避できます。


解決

1. 日本語フォントをプロジェクトに同梱する

サーバーに日本語フォントがある保証はありません。リポジトリに TTF を含めて配置するのが確実です(ライセンスは要確認。IPAex フォントは再配布可で OG 生成によく使われます)。

project/
├── lib/og.php
└── assets/fonts/ipaexg.ttf   ← 同梱

2. DIR 基準の絶対パスで渡す

function render_og(string $text): void {
    $img   = imagecreatetruecolor(1200, 630);
    $color = imagecolorallocate($img, 255, 255, 255);

    // __DIR__ で「このファイルの場所」を起点にする → CWD に依存しない
    $font = __DIR__ . '/../assets/fonts/ipaexg.ttf';

    if (!is_file($font)) {
        // 早期に気づけるようにしておく
        throw new RuntimeException("font not found: {$font}");
    }

    imagettftext($img, 40, 0, 50, 320, $color, $font, $text);
    // ...
}

ポイントは __DIR__imagettftext の前に is_file() で存在チェックを入れておくと、「空白で生成される」よりも早く・確実に原因に気づけます。

3. 文字幅の計算(imagettfbbox)も同じフォントを絶対パスで

中央寄せなどで imagettfbbox() を使う場合も、同じ絶対パスのフォントを渡します。ここだけ相対にして失敗するミスが多いです。

$bbox  = imagettfbbox(40, 0, $font, $text);   // $font は上と同じ絶対パス
$width = $bbox[2] - $bbox[0];
$x     = (int)((1200 - $width) / 2);
imagettftext($img, 40, 0, $x, 320, $color, $font, $text);

補足

  • そもそも imagettftext 自体が undefined の場合は、GD 拡張(と FreeType サポート)が無効です。php -m | grep -i gdphpinfo() の "FreeType Support => enabled" を確認してください。
  • 本番が共有ホスティングの場合、システムフォントの場所や有無に依存しない**「同梱 + __DIR__ 絶対パス」**が最も再現性が高いです。
  • 一言でいえば 「日本語フォントを自分で持ち、__DIR__ で絶対パス指定する」。これで CLI・Web・cron のどの経路から呼んでも同じ結果になります。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?