Image:Magickで任意のサイズで折り返したテキストを画像化するコード

「特定商取引法に基づく表記」画像作成ジェネレーターを作り始めた時に、文章を画像化した時にテーブル枠からテキストがはみ出してしまうのに悩みました。

最初はユーザーが一度試しに画像出力してみて、改行して整えてから本番をとも思いましたが、自動でサイズに合わせて折り返しになったら楽だなと、作っていました。

2年程前に作っていたので、記憶の限りコメントをつけました。


//初期値
$img_width = 60;// 画像サイズ横幅60px
$font_size = 16;// フォントサイズ16px
$text = "とても長い文章で、改行も含み、複数のパラグラフで構成されるもの";
//
$dammy_array = array();// 器にするダミー配列をつくる
$text_array = explode( "\n", $text );// テキストを改行コードで区切り、配列に代入する。
for ( $i = 0; $i < count($text_array); $i++ ){
  // 元のテキストを1行ずつ取り出して、指定幅とフォントサイズから収まる文字数(バイト数)を計算しておりかえす(注)
  $dammy_array[$i] = trim( mb_wordwrap( $text_array[$i], floor( ( $img_width - 20 ) / $font_size ) * 2 ) );
}
$text = implode( "\n", $dammy_array );// 配列を改行を挟んだテキストに結合
$text_array = explode( "\n", $text );// 画像の高さを測るため。行数を計算するため後で使う。
$im    = new Imagick();// 画像準備
$idraw = new ImagickDraw();
//
$idraw->setFont("SourceHanCodeJP-Regular.otf");// フォントはphpと同じフォルダにあるものとする
$idraw->setFontSize($font_size);// font size
$idraw->setTextAlignment(imagick::ALIGN_CENTER);
$idraw->setFillColor("#000000");// 文字色塗り
$idraw->annotation(10, $font_size,$text);// 文字を描く
//
$im->newImage($img_width, count($text_array)*($font_size+10), "#ffffff");// 高さは(フォントサイズ+行高)*行数
$im->drawImage($idraw);
$im->setImageFormat("png");
$base64 = base64_encode($im);
$im->destroy();
$idraw->destroy();
//
echo '<img src="data:image/png;base64,'.$base64.'">';// base64で表示
//
function mb_wordwrap( $str, $width=50, $break="\n" ){
  $str = htmlentities($str,ENT_QUOTES,"UTF-8");
  $str = str_replace("|","/",$str);
  $w = mb_strwidth( $str  , "UTF-8" );
  $arr = array();
  if( $w < $width ){
    return $str;
  }
  while( $w > $width ){
    $trimStr = mb_strimwidth( $str , 0, $width , "" , "UTF-8" );
    $arr[] = $trimStr;
    $str = preg_replace("|^$trimStr|","",$str);
    $w = mb_strwidth( $str  , "UTF-8" );
  }
  $arr[] = $str;
  return implode( $break, $arr );
}

function mb_wordwrapは以下のサイトを参考にしました。

https://se.ykysd.com/2016/05/27/mb_wordwrap/

注:

round( ( $img_width - 20 ) / $font_size ) * 2 )

で画像サイズに合わせた文字数を計算します。

今回、画像化する際に左右10pxのpaddingを設定して作画したので、-20しました。

すべて全角文字ならこれではみ出しませんが、半角文字が多いと文字がはみ出します。
mb_wordwrapがそういう仕様なのだと諦めました。