画像に文字を書き込む時に不便な点が…
PHPには標準でimagettftextという関数が存在します。
これは、画像に指定した文字列を指定した位置に書き込む関数ですが、少し不便だと思う点があります。
例えば、
- CSSでいう「text-align」のような複数行の文字列を指定した位置に揃える方法
- 簡単に文字列を画像の中央や右端に配置する方法
- 右から位置を指定する方法
などがあります。そこで、今回はそれらを可能にする関数を作りました。
関数の解説
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
// 挿入文字サイズ取得時の添え字定義 define('TEXTPOSITION_BOTTOMLEFT_X' , 0); // 左下X define('TEXTPOSITION_BOTTOMLEFT_Y' , 1); // 左下Y define('TEXTPOSITION_BOTTOMRIGHT_X' , 2); // 右下X define('TEXTPOSITION_BOTTOMRIGHT_Y' , 3); // 右下Y define('TEXTPOSITION_TOPRIGHT_X' , 4); // 右上X define('TEXTPOSITION_TOPRIGHT_Y' , 5); // 右上Y define('TEXTPOSITION_TOPLEFT_X' , 6); // 左上X define('TEXTPOSITION_TOPLEFT_Y' , 7); // 左上Y // 画像に文字を挿入 function imagettftextposition($image, $filename, $size, $angle, $x, $y, $color, $fontfile, $text, $align = 'left', $offset = 'left'){ // 画像サイズの取得 $image_size = getimagesize($filename); if($image_size){ $image_width = $image_size[0]; $image_height = $image_size[1]; }else{ echo "ERROR: not found image\n"; return 1; } // 文字列の取得 $text_position = imagettfbbox($size, $angle, $fontfile, $text); $text_position_width = $text_position[TEXTPOSITION_BOTTOMRIGHT_X] - $text_position[TEXTPOSITION_BOTTOMLEFT_X]; $text_position_height = $text_position[TEXTPOSITION_BOTTOMRIGHT_Y] - $text_position[TEXTPOSITION_TOPRIGHT_Y]; // x軸の位置指定 if(gettype($x) == 'string'){ switch ($x){ case 'left': $x_position = 0; break; case 'right': $x_position = $image_width - $text_position_width; break; case 'center': $x_position = ($image_width - $text_position_width) / 2; break; default: return 1; } }else{ // 数値が入力されていた場合は格納 // オフセットが右側の場合は右側からの数値を if($offset == 'right') $x_position = $image_width - $text_position_width - $x; else $x_position = $x; } // y軸の位置指定 if(gettype($y) == 'string'){ switch ($y){ case 'top': $y_position = 0; break; case 'bottom': $y_position = $image_height; break; case 'center': $y_position = ($image_height - $text_position_height) / 2 + $text_position_height / (substr_count($text,"\n") + 1); break; default: return 1; } }else{ // 数値が入力されていた場合は格納 $y_position = $y; } // 文字列を合成 switch ($align) { case 'left': imagettftext($image, $size, $angle, $x_position, $y_position, $color, $fontfile, $text); break; case 'right': // 行ごとに文字列を分解 $line = explode("\n",$text); for ($i = 0; $i < substr_count($text, "\n") + 1; $i++) { $line_position = imagettfbbox($size, $angle, $fontfile, $line[$i]); $line_position_width = $line_position[TEXTPOSITION_BOTTOMRIGHT_X] - $line_position[TEXTPOSITION_BOTTOMLEFT_X]; imagettftext($image, $size, $angle, $x_position + $text_position_width - $line_position_width, $y_position + ($text_position_height / (substr_count($text, "\n") + 1) + $size) * $i, $color, $fontfile, $line[$i]); } break; case 'center': // 行ごとに文字列を分解 $line = explode("\n",$text); for ($i = 0; $i < substr_count($text, "\n") + 1; $i++) { $line_position = imagettfbbox($size, $angle, $fontfile, $line[$i]); $line_position_width = $line_position[TEXTPOSITION_BOTTOMRIGHT_X] - $line_position[TEXTPOSITION_BOTTOMLEFT_X]; imagettftext($image, $size, $angle, $x_position + ($text_position_width - $line_position_width) / 2, $y_position + ($text_position_height / (substr_count($text, "\n") + 1) + $size) * $i, $color, $fontfile, $line[$i]); } break; } return 0; } |
めっちゃ長いです…
引数
まずは引数から解説します。
12 |
function imagettftextposition($image, $filename, $size, $angle, $x, $y, $color, $fontfile, $text, $align = 'left', $offset = 'left'){ |
今回、全部で引数は10個あります。
前は元となっている「imagettftext」とほぼ同じ内容です。
第二引数としてファイルへのパスを追加しました。
これは、後に登場する「getimagesize」でファイルのフルパスが必要になるためです。
また、「$x」、「$y」は文字列を指定することも可能になりました。
- 「$x」の場合
- 指定可能な値:left(左端),center(中央),right(右端)
- 「$y」の場合
- 指定可能な値:top(上),center(中央),bottom(下)
後2個は任意の引数になります。
- 「$align」は複数行の文字列において揃える方向を指定します。
- 指定可能な値:left , center , right
- デフォルト値:left
- 「$offset」は指定された横方向の基準となる方向を指定します。
- 指定可能な値:left , right
- デフォルト値:left
続いて、今回使用する画像と文字それぞれのサイズを取得します。
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// 画像サイズの取得 $image_size = getimagesize($filename); if($image_size){ $image_width = $image_size[0]; $image_height = $image_size[1]; }else{ echo "ERROR: not found image\n"; return 1; } // 文字列の取得 $text_position = imagettfbbox($size, $angle, $fontfile, $text); $text_position_width = $text_position[TEXTPOSITION_BOTTOMRIGHT_X] - $text_position[TEXTPOSITION_BOTTOMLEFT_X]; $text_position_height = $text_position[TEXTPOSITION_BOTTOMRIGHT_Y] - $text_position[TEXTPOSITION_TOPRIGHT_Y]; |
26,27行目で配列の添え字として利用している値は冒頭で宣言していた部分です。
1 2 3 4 5 6 7 8 9 |
// 挿入文字サイズ取得時の添え字定義 define('TEXTPOSITION_BOTTOMLEFT_X' , 0); // 左下X define('TEXTPOSITION_BOTTOMLEFT_Y' , 1); // 左下Y define('TEXTPOSITION_BOTTOMRIGHT_X' , 2); // 右下X define('TEXTPOSITION_BOTTOMRIGHT_Y' , 3); // 右下Y define('TEXTPOSITION_TOPRIGHT_X' , 4); // 右上X define('TEXTPOSITION_TOPRIGHT_Y' , 5); // 右上Y define('TEXTPOSITION_TOPLEFT_X' , 6); // 左上X define('TEXTPOSITION_TOPLEFT_Y' , 7); // 左上Y |
これは、「imagettfbbox」で文字列の4隅のXY座標が配列として返され、配列に上記の添え字を与えると指定の箇所の座標を取得できます。
続いて、文字を配置するXY座標を決めます。
X座標は数値が入力された場合はオフセットが右の場合を除きそのまま格納しますが、文字列(left , center , right)が入力された場合はそれぞれ、左寄せ・中央寄せ・右寄せになるようにXの座標を計算します。
Y座標もほぼ同じなので省略します。
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
// x軸の位置指定 if(gettype($x) == 'string'){ switch ($x){ case 'left': $x_position = 0; break; case 'right': $x_position = $image_width - $text_position_width; break; case 'center': $x_position = ($image_width - $text_position_width) / 2; break; default: return 1; } }else{ // 数値が入力されていた場合は格納 // オフセットが右側の場合は右側からの数値を if($offset == 'right') $x_position = $image_width - $text_position_width - $x; else $x_position = $x; } |
最後は画像に文字列を書き込みます。
「$align」の値を元に処理を分岐します。
‘left’の場合は通常通りのため、そのまま「imagettftext」を使用して書き込みます。
‘right’の場合は行ごとに文字列を分解して、右側に揃うようにx座標を各行調整して1行ずつ書き込みます。
‘center’も’right’と同じく中央揃えになるように1行ずつ調整して出力します。
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
// 文字列を合成 switch ($align) { case 'left': imagettftext($image, $size, $angle, $x_position, $y_position, $color, $fontfile, $text); break; case 'right': // 行ごとに文字列を分解 $line = explode("\n",$text); for ($i = 0; $i < substr_count($text, "\n") + 1; $i++) { $line_position = imagettfbbox($size, $angle, $fontfile, $line[$i]); $line_position_width = $line_position[TEXTPOSITION_BOTTOMRIGHT_X] - $line_position[TEXTPOSITION_BOTTOMLEFT_X]; imagettftext($image, $size, $angle, $x_position + $text_position_width - $line_position_width, $y_position + ($text_position_height / (substr_count($text, "\n") + 1) + $size) * $i, $color, $fontfile, $line[$i]); } break; case 'center': // 行ごとに文字列を分解 $line = explode("\n",$text); for ($i = 0; $i < substr_count($text, "\n") + 1; $i++) { $line_position = imagettfbbox($size, $angle, $fontfile, $line[$i]); $line_position_width = $line_position[TEXTPOSITION_BOTTOMRIGHT_X] - $line_position[TEXTPOSITION_BOTTOMLEFT_X]; imagettftext($image, $size, $angle, $x_position + ($text_position_width - $line_position_width) / 2, $y_position + ($text_position_height / (substr_count($text, "\n") + 1) + $size) * $i, $color, $fontfile, $line[$i]); } break; } |
以上がOGPを自動生成するにあたって使いやすくした関数です。
今回のブログ曲
今回投稿中に聴いていた曲はこちら