画像処理

【PHP】ImageTTFText()で左上を起点として文字を描画する方法

更新日:2023/09/12

PHPのImageTTFText()は文字列を描画する関数ですが、ベースラインの左端を描画位置として指定します。
しかしベースラインの位置はフォントの種類やサイズなどで変化するため、狙った位置に描画するのが困難です。

そこで、ImageTTFText()で左上を起点として文字を描画する方法をお伝えします。


2023/9/12 内容を整理しました。

 

考え方

ImageTTFText()は、文字列のベースラインを基準として描画します。

ベースラインは、文字列の下側になることが多いです。
ベースラインを赤い線で可視化してみると、次のようになります。

abc gjpq あいうえお

そのため座標(x,y)に描画すると、次のようなイメージで描画されます。

ベースラインに描画される

そこで高さ分を考慮して描画座標を指定すれば、想定した位置に描画できます。

高さ分移動する

なお、横方向(x座標)もズレている可能性があるので、考慮する必要があります。

 

PHPコード

考え方を元にして作成した関数imagettftextLeftTop()です。

// 左上を基準として文字列を描画する関数
function imagettftextLeftTop($image,$size,$left,$top,$color,$font_filename,$text){
    $boundingBox = imagettfbbox($size ,0 ,$font_filename,$text);
    $baseTop = $top - $boundingBox[7]; // ベースラインの左端y座標を取得
    $baseLeft = $left - $boundingBox[6]; // ベースラインの左端x座標を取得
      // 文字列を描画
    ImageTTFText($image, $size, 0, $baseLeft, $baseTop, $color, $font_filename,$text);
}

引数は文字列を描画する関数ImageTTFText()とほぼ同じ(角度指定が無い)です。

やっていることは単純ですね。

imagettfbbox()で描画後の矩形座標を算出します。
算出した座標配列から左上座標(インデックス6と7)取得して、描画位置の補正を行い描画します。

次のコードは、この関数を使って文字列を描画します。

$top = 50;
$left = 50;

$image = imagecreatetruecolor(500, 200);
$white = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $white);
$red = imagecolorallocate($image, 255, 0, 0);
imageLine( $image , $left , $top-10 , $left , $top+10 , $red );
imageLine( $image , $left-10 , $top , $left+10 , $top , $red );

$fontFile = './ZenMaruGothic-Bold.ttf';
$text = 'abcde あいうえお';
$fontSize = 20;
$black = imagecolorallocate($image, 0, 0, 0);

imagettftextLeftTop($image,$fontSize,$left,$top,$black,$fontFile,$text);

header("Content-type: image/png");
imagepng($image);

適当な名前で保存してブラウザから呼び出すと、次のような画像が表示されます。

角度0の時の実行結果

 

角度を指定する場合

前項は角度0を想定していたので、次は角度指定するケースを考えてみます。

imagettfbbox()が返す配列は角度0の時の4角の移動先がセットされるので、配列のインデックス6と7を左上とみなすことができません。

imagettfbboxで回転

そこで回転後の矩形座標から実質的な左上座標を算出します。
次にその座標を移動させて、指定された座標が左上に位置するように描画座標を調整します。

回転して位置調整

これを元に、次のような関数imagettftextLeftTopAngle()を作成しました。

// 左上を基準として文字列を描画する関数(角度指定あり)
function imagettftextLeftTopAngle($image,$size,$angle,$left,$top,$color,$font_filename,$text){
    $b = imagettfbbox($size ,$angle ,$font_filename,$text);
    [$bTop,$bleft] = $angle === 0 ? [$b[7],$b[6]] : [min($b[1],$b[3],$b[5],$b[7]),min($b[0],$b[2],$b[4],$b[6])];
    $baseTop = $top -$bTop;
    $baseLeft = $left - $bleft;
    ImageTTFText($image, $size, $angle, $baseLeft, $baseTop, $color, $font_filename,$text);
}
// 左上を基準として文字列を描画する関数
function imagettftextLeftTop($image,$size,$left,$top,$color,$font_filename,$text){
    imagettftextLeftTopAngle($image,$size,0,$left,$top,$color,$font_filename,$text);
}

角度0のときはインデックス6と7をそのまま参照して、それ以外はmin()関数で最小値を求めています。
前項の関数imagettftextLeftTop()は今回の関数imagettftextLeftTopAngle()で吸収できるので、内容を変更しています。

この関数を使って、文字列を描画してみます。

$top = 50;
$left = 50;

$image = imagecreatetruecolor(500, 200);
$white = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $white);
$red = imagecolorallocate($image, 255, 0, 0);
imageLine( $image , $left , $top-10 , $left , $top+50 , $red );
imageLine( $image , $left-10 , $top , $left+300 , $top , $red );

$fontFile = './ZenMaruGothic-Bold.ttf';
$text = 'abcde あいうえお';
$fontSize = 20;
$black = imagecolorallocate($image, 0, 0, 0);

$angle = 90; // 回転角度

imagettftextLeftTopAngle($image,$fontSize,$angle,$left,$top,$black,$fontFile,$text);

header("Content-type: image/png");
imagepng($image);

上記コードを実行すると、次のように画像が表示されます。

角度0の時の実行結果

左上を起点として文字を描画できていますね。

角度を変えて描画してみます。

まずは $angle=90 です。

角度90の時の実行結果

下地画像の高さが足りないので文字の先頭が描画しきれていませんが、左上を起点として文字を描画できていますね。

次は $angle=180 です。

角度180の時の実行結果

文字が上下反転しました。
これも、左上を起点として文字を描画できていますね。

次は $angle=270 です。

角度270の時の実行結果

これも、上手く描画できています。

次は $angle=142 です。

角度142の時の実行結果

文字が斜めになっても、左上を起点として文字を描画できていますね。

次は $angle=222 です。

角度222の時の実行結果

少しおかしな印象を受けるかもしれませんが、これも文字列の左上を起点として文字を描画できていまます。

更新日:2023/09/12

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。