PHPのお勉強!

PHP TOP

imagettfbbox

(PHP 4, PHP 5, PHP 7, PHP 8)

imagettfbboxTypeType フォントを使用したテキストの bounding box を生成する

説明

imagettfbbox(
    float $size,
    float $angle,
    string $font_filename,
    string $string,
    array $options = []
): array|false

この関数は TrueType テキストの bounding box をピクセル単位で計算して 返します。

注意:

PHP 8.0.0 より前のバージョンでは、 imageftbbox() は、 imagettfbbox() を拡張したものでした。 extrainfo を追加でサポートしています。 PHP 8.0.0 以降では、 imagettfbbox() は、 imageftbbox() のエイリアスになっています。

パラメータ

size

ポイント数単位のフォントサイズ。

angle

測定する string の角度(度単位)。

fontfile

使用したい TrueType フォントへのパス。

どの GDライブラリをPHPが使っているかによって、 いつ fontfile パラメータの先頭が / で始まらず、 .ttf がファイル名に付加されるかが違います。 そして、ライブラリは自らが定義したフォントパスに従ってそのファイル名を探そうとします。

GD ライブラリ 2.0.18 より前のバージョンを使っている場合、 セミコロンではなく、space 文字が 異なるフォントファイルの 'pathのセパレータ' として使われていました。 この機能を意図せず使ってしまうと、次のような警告が発生します: Warning: Could not find/open font. この事象の影響を受けてしまうバージョンでは、 唯一の解決策はフォントをスペースを含まないパスに移動させることだけです。

多くの場合、スクリプトが使っているフォントと同じディレクトリにある場合、 次のようなテクニックで問題を軽減できるでしょう。

<?php
// GD の環境変数を設定
putenv('GDFONTPATH=' . realpath('.'));

// 使用されるフォント名 ( .ttf 拡張子の欠落に注意)
$font = 'SomeFont';
?>

注意:

open_basedirfontfile には適用され ない ことに注意してください。

string

測定する文字列。

戻り値

imagettfbbox() は、テキストの bounding box を 作成するための 4 点を表現する 8 個の要素からなる配列を返します。 エラー時には false を返します。

キー 内容
0 左下角の X 座標
1 左下角の Y 座標
2 右下角の X 座標
3 右下角の Y 座標
4 右上角の X 座標
5 右上角の Y 座標
6 左上角の X 座標
7 左上角の Y 座標

各点の位置は、 angle にかかわらず text からの相対位置で表されます。 つまり、"左上"はテキストを水平に見た場合の左上の角を意味します。

変更履歴

バージョン 説明
8.0.0 options が追加されました。

例1 imagettfbbox() の例

<?php
// 300x150 の画像を作成します
$im = imagecreatetruecolor(300, 150);
$black = imagecolorallocate($im, 0, 0, 0);
$white = imagecolorallocate($im, 255, 255, 255);

// 背景を白に設定します
imagefilledrectangle($im, 0, 0, 299, 299, $white);

// フォントファイルへのパス
$font = './arial.ttf';

// まず最初のテキスト用のバウンディングボックスを作成します
$bbox = imagettfbbox(10, 45, $font, 'Powered by PHP ' . phpversion());

// X 座標と Y 座標
$x = $bbox[0] + (imagesx($im) / 2) - ($bbox[4] / 2) - 25;
$y = $bbox[1] + (imagesy($im) / 2) - ($bbox[5] / 2) - 5;

// 書き込みます
imagettftext($im, 10, 45, $x, $y, $black, $font, 'Powered by PHP ' . phpversion());

// 次に 2 番目のテキスト用のバウンディングボックスを作成します
$bbox = imagettfbbox(10, 45, $font, 'and Zend Engine ' . zend_version());

// 最初のテキストに続ける座標を設定します
$x = $bbox[0] + (imagesx($im) / 2) - ($bbox[4] / 2) + 10;
$y = $bbox[1] + (imagesy($im) / 2) - ($bbox[5] / 2) - 5;

// 書き込みます
imagettftext($im, 10, 45, $x, $y, $black, $font, 'and Zend Engine ' . zend_version());

// ブラウザに出力します
header('Content-Type: image/png');

imagepng($im);
imagedestroy($im);
?>

注意

注意: この関数は、PHP が FreeType サポート (--with-freetype-dir=DIR) を有効にしてコンパイルされている場合のみ使用可能です。

参考

  • imagettftext() - TrueType フォントを使用してテキストを画像に書き込む
  • imageftbbox() - freetype2 によるフォントを用いたテキストを囲む箱を取得する
add a note

User Contributed Notes 37 notes

up
24
blackbart at simail dot it
14 years ago
I wrote a simple function that calculates the *exact* bounding box (single pixel precision).
The function returns an associative array with these keys:
left, top: coordinates you will pass to imagettftext
width, height: dimension of the image you have to create

<?php
function calculateTextBox($font_size, $font_angle, $font_file, $text) {
$box = imagettfbbox($font_size, $font_angle, $font_file, $text);
if( !
$box )
return
false;
$min_x = min( array($box[0], $box[2], $box[4], $box[6]) );
$max_x = max( array($box[0], $box[2], $box[4], $box[6]) );
$min_y = min( array($box[1], $box[3], $box[5], $box[7]) );
$max_y = max( array($box[1], $box[3], $box[5], $box[7]) );
$width = ( $max_x - $min_x );
$height = ( $max_y - $min_y );
$left = abs( $min_x ) + $width;
$top = abs( $min_y ) + $height;
// to calculate the exact bounding box i write the text in a large image
$img = @imagecreatetruecolor( $width << 2, $height << 2 );
$white = imagecolorallocate( $img, 255, 255, 255 );
$black = imagecolorallocate( $img, 0, 0, 0 );
imagefilledrectangle($img, 0, 0, imagesx($img), imagesy($img), $black);
// for sure the text is completely in the image!
imagettftext( $img, $font_size,
$font_angle, $left, $top,
$white, $font_file, $text);
// start scanning (0=> black => empty)
$rleft = $w4 = $width<<2;
$rright = 0;
$rbottom = 0;
$rtop = $h4 = $height<<2;
for(
$x = 0; $x < $w4; $x++ )
for(
$y = 0; $y < $h4; $y++ )
if(
imagecolorat( $img, $x, $y ) ){
$rleft = min( $rleft, $x );
$rright = max( $rright, $x );
$rtop = min( $rtop, $y );
$rbottom = max( $rbottom, $y );
}
// destroy img and serve the result
imagedestroy( $img );
return array(
"left" => $left - $rleft,
"top" => $top - $rtop,
"width" => $rright - $rleft + 1,
"height" => $rbottom - $rtop + 1 );
}
?>
up
11
jodybrabec at gmail dot com
13 years ago
Very CLEAR version of func., with example....

<?php

function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) {
/************
simple function that calculates the *exact* bounding box (single pixel precision).
The function returns an associative array with these keys:
left, top: coordinates you will pass to imagettftext
width, height: dimension of the image you have to create
*************/
$rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text);
$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6]));
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6]));
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7]));
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7]));

return array(
"left" => abs($minX) - 1,
"top" => abs($minY) - 1,
"width" => $maxX - $minX,
"height" => $maxY - $minY,
"box" => $rect
);
}

// Example usage - gif image output

$text_string = "Hullo World";
$font_ttf = "./fonts/arial.ttf";
$font_size = 22;
$text_angle = 0;
$text_padding = 10; // Img padding - around text

$the_box = calculateTextBox($text_string, $font_ttf, $font_size, $text_angle);

$imgWidth = $the_box["width"] + $text_padding;
$imgHeight = $the_box["height"] + $text_padding;

$image = imagecreate($imgWidth,$imgHeight);
imagefill($image, imagecolorallocate($image,200,200,200));

$color = imagecolorallocate($image,0,0,0);
imagettftext($image,
$font_size,
$text_angle,
$the_box["left"] + ($imgWidth / 2) - ($the_box["width"] / 2),
$the_box["top"] + ($imgHeight / 2) - ($the_box["height"] / 2),
$color,
$font_ttf,
$text_string);

header("Content-Type: image/gif");
imagegif($image);
imagedestroy($image);

?>

[ remember: No spaces before or after the <?php ... ?> tag, because of header() call, you Roast! ]
up
13
marclaz
18 years ago
Please note that as imageTTFBbox and imageTTFText functions return an array of coordinates which could be negative numbers care must be taken with height and width calculations.

The rigth way to do that is to use the abs() function:

for an horizontal text:

$box = @imageTTFBbox($size,0,$font,$text);
$width = abs($box[4] - $box[0]);
$height = abs($box[5] - $box[1]);

Then to center your text at ($x,$y) position the code should be like that:

$x -= $width/2;
$y += $heigth/2;

imageTTFText($img,$size,0,$x,$y,$color,$font,$text);

this because (0,0) page origin is topleft page corner and (0,0) text origin is lower-left readable text corner.

Hope this help.
up
3
ryan at retronetworks dot com
19 years ago
Here is a function that lets you write a string with your own "font tracking" level (the amount of pixels separating each character). It uses imagettfbbox to determine the width of each character, so it doesn't discriminate against the skinnier of characters. For this example, let $t = the amount of distance in pixels you want to separate each character from its neighbors.

<?php
function ImageTTFTextWithTracking($im, $size, $angle, $t, $x, $y, $color, $font, $text) {
$numchar = strlen($text);
for(
$i = 0; $i < $numchar; $i++) {
# Assign character
$char[$i] = substr($text, $i, 1);

# Write character
imagettftext($im, $size, $angle, ($x + $w + ($i * $t)), $y, $color, $font, $char[$i]);

# Get width of character
$width = imagettfbbox($size, $angle, $font, $char[$i]);
$w = $w + $width[2];
}
}
?>

Be aware that it currently does not work for angles other than the 0 default (I have no need for that).
up
7
Anonymous
12 years ago
It seems to be worth pointing out that the "points" unit GD2 is using corresponds to 96 dpi, as defined in gd.h:
#define GD_RESOLUTION 96 /* pixels per inch */

So if you want to translate the bbox back to font points, you need to multiply all coordinates by 72/96 = 3/4.
up
5
Valentijn de Pagter
16 years ago
If you're looking for easy text alignment, you need to use the imagettfbbox() command. When given the correct parameters, it will return the boundaries of your to-be-made text field in an array, which will allow you to calculate the x and y coordinate that you need to use for centering or aligning your text.

A horizontal centering example:

<?php

$tb
= imagettfbbox(17, 0, 'airlock.ttf', 'Hello world!');

?>

$tb would contain:

Array
(
[0] => 0 // lower left X coordinate
[1] => -1 // lower left Y coordinate
[2] => 198 // lower right X coordinate
[3] => -1 // lower right Y coordinate
[4] => 198 // upper right X coordinate
[5] => -20 // upper right Y coordinate
[6] => 0 // upper left X coordinate
[7] => -20 // upper left Y coordinate
)

For horizontal alignment, we need to substract the "text box's" width { $tb[2] or $tb[4] } from the image's width and then substract by two.

Saying you have a 200px wide image, you could do something like this:

<?php

$x
= ceil((200 - $tb[2]) / 2); // lower left X coordinate for text
imagettftext($im, 17, 0, $x, $y, $tc, 'airlock.ttf', 'Hello world!'); // write text to image

?>

This'll give you perfect horizontal center alignment for your text, give or take 1 pixel. Have fun!
up
3
peterjwest3 at gmail dot com
14 years ago
As many of you know, this function is bugged in several versions of PHP. It should return the coordinates relative to the baseline of the font. So if your text includes characters like g and p then the bounding box should extend below zero on the Y axis, however it doesn't. This is a problem because imagettftext() positions text using the baseline, so all your text will be misaligned.

My solution is to create an image of the desired font and font-size using all ascii characters with imagettfbbox() and imagettftext(). The height of this image is used as the height for the real image.

I then analyse the image to get the vertical offset of the text (the background color should be $baseColor)
<?php
function getYOffset($image, $baseColor) {
for(
$y = 0; $y < $this->height(); $y++)
for(
$x = 0; $x < $this->width(); $x++)
if (
imagecolorat($image, $x, $y) !== $baseColor)
return
$y; }
?>

This offset can be used as the baseline for the font (for this font-size). You can use a similar trick for the horizontal offset, but that changes depending on the first character.
up
5
decimealgo at gmail dot com
16 years ago
This is a function which reformats a text string into a text block of a given width.
Usefull when you have a long single line string and want to fit it into a fixed width but don't care about it's height

<?php
function makeTextBlock($text, $fontfile, $fontsize, $width)
{
$words = explode(' ', $text);
$lines = array($words[0]);
$currentLine = 0;
for(
$i = 1; $i < count($words); $i++)
{
$lineSize = imagettfbbox($fontsize, 0, $fontfile, $lines[$currentLine] . ' ' . $words[$i]);
if(
$lineSize[2] - $lineSize[0] < $width)
{
$lines[$currentLine] .= ' ' . $words[$i];
}
else
{
$currentLine++;
$lines[$currentLine] = $words[$i];
}
}

return
implode("\n", $lines);
}
?>
up
1
go4christian at gmail dot com
12 years ago
Automatic line breaks: This simple function is able automatically create line breaks if you want to write a text on an image. All you have to specify is a maximum length.

<?php
function write_multiline_text($image, $font_size, $color, $font, $text, $start_x, $start_y, $max_width)
{
//split the string
//build new string word for word
//check everytime you add a word if string still fits
//otherwise, remove last word, post current string and start fresh on a new line
$words = explode(" ", $text);
$string = "";
$tmp_string = "";

for(
$i = 0; $i < count($words); $i++)
{
$tmp_string .= $words[$i]." ";

//check size of string
$dim = imagettfbbox($font_size, 0, $font, $tmp_string);

if(
$dim[4] < $max_width)
{
$string = $tmp_string;
} else {
$i--;
$tmp_string = "";
imagettftext($image, 11, 0, $start_x, $start_y, $color, $font, $string);

$string = "";
$start_y += 22; //change this to adjust line-height. Additionally you could use the information from the "dim" array to automatically figure out how much you have to "move down"
}
}

imagettftext($image, 11, 0, $start_x, $start_y, $color, $font, $string); //"draws" the rest of the string
?>
up
2
magnum dot tc dot mr at gmail dot com
12 years ago
Please note that the 3rd argument is really a "path".
<?php
imagettfbbox
(10, 0, 'arial.ttf', 'Hello, World!'); // will result in "Warning: imagettfbbox(): Could not find/open font in ...php on line ..."
?>

use instead something like this:
<?php imagettfbbox(10, 0, './arial.ttf', 'Hello, World!'); ?>
or
<?php imagettfbbox(10, 0, getcwd().'/arial.ttf', 'Hello, World!'); ?>
up
2
mike at mikeleigh dot com
17 years ago
I have been testing this function for a while now and have come up with many of the same issues that other people have touched upon. Not being able to calculate the width of the text correctly. Or if a solution is found then it won't work with a hanging letter or a negative start letter like 'j'.

Like Ralph I also wanted to draw a box around some text and this would require me being pixel perfect with the font. The trouble is I did not know which font would be used or which size. This led me to come up with a solution which I am sharing below.

<?php
function imagettfbboxextended($size, $angle, $fontfile, $text) {
/*this function extends imagettfbbox and includes within the returned array
the actual text width and height as well as the x and y coordinates the
text should be drawn from to render correctly. This currently only works
for an angle of zero and corrects the issue of hanging letters e.g. jpqg*/
$bbox = imagettfbbox($size, $angle, $fontfile, $text);

//calculate x baseline
if($bbox[0] >= -1) {
$bbox['x'] = abs($bbox[0] + 1) * -1;
} else {
//$bbox['x'] = 0;
$bbox['x'] = abs($bbox[0] + 2);
}

//calculate actual text width
$bbox['width'] = abs($bbox[2] - $bbox[0]);
if(
$bbox[0] < -1) {
$bbox['width'] = abs($bbox[2]) + abs($bbox[0]) - 1;
}

//calculate y baseline
$bbox['y'] = abs($bbox[5] + 1);

//calculate actual text height
$bbox['height'] = abs($bbox[7]) - abs($bbox[1]);
if(
$bbox[3] > 0) {
$bbox['height'] = abs($bbox[7] - $bbox[1]) - 1;
}

return
$bbox;
}
?>

The function above gives the correct x and y coordinates that the text should be drawn from and also gives the actual image width and height. This has been tested with various fonts and sizes ranging from 6 up to 144 points. Some of the output will appear to be incorrect and have an extra pixel on the right, using verdana at size 144 and outputting the character 'Q' for example. This is not an error as this is part of the anti-aliasing of the font output.

Example Usage:
<?php
$font
= 'c:\windows\fonts\verdana.ttf';
$font_size = 144;
$text = 'jÜyZgQ';
$bbox = imagettfbboxextended($font_size, 0, $font, $text);
?>

Return Values:
Array
(
[0] => -8
[1] => 40
[2] => 715
[3] => 40
[4] => 715
[5] => -177
[6] => -8
[7] => -177
[x] => 6
[width] => 722
[y] => 176
[height] => 216
)

Further notes can be found here along with images of the output of the function http://mikeleigh.com/links/imagettfbbox
up
1