PHP 8.4.1 Released!

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
indraaaa34 at gmail dot com
9 years ago
The returned array order is like this:
-----------------------------
| X:4 Y:5 | X: Y:7 |
-----------------------------
| X:0 Y:1 | X:2 Y:3 |
-----------------------------

eg:
4 for the upper left X
5 for the upper left Y and so on.
up
2
a2hansolo at gmail dot com
13 years ago
measure bg image size, wrap text to fit image width

<?php
$mx
= imagesx($main_img);
$my = imagesy($main_img);

//TEXT VARS/////////
$main_text = ;
$main_text_size = ;
$main_text_x = ($mx/2);

$main_text_color = imagecolorallocate($main_img, $main_text_red, $main_text_green, $main_text_blue);
$words = explode(' ', $main_text);
$lines = array($words[0]);
$currentLine = 0;
for(
$i = 1; $i < count($words); $i++)
{
$lineSize = imagettfbbox($main_text_size, 0, $mt_f, $lines[$currentLine] . ' ' . $words[$i]);
if(
$lineSize[2] - $lineSize[0] < $mx)
{
$lines[$currentLine] .= ' ' . $words[$i];
}
else
{
$currentLine++;
$lines[$currentLine] = $words[$i];
}
}
$line_count = 1;
// Loop through the lines and place them on the image
foreach ($lines as $line)
{
$line_box = imagettfbbox($main_text_size, 0, $mt_f, "$line");
$line_width = $line_box[0]+$line_box[2];
$line_height = $line_box[1]-$line_box[7];
$line_margin = ($mx-$line_width)/2;
$line_y = (($line_height+12) * $line_count);
imagettftext($main_img, $main_t_s, 0, $line_margin, $line_y, $main_text_color, $mt_f, $line);

// Increment Y so the next line is below the previous line
$line_count ++;
}
?>
up
2
Somerset Ben
3 years ago
Pushing text around.

I wanted to put various bits of text in the corners of an image so I created a function to accept a location in the image and then put a corner of the text (eg right,top) at that location. Rotation is not supported.

Inputs to the function are fairly standard. The align parameter is two characters R|M|L (right, middle, top)for x alignment and T|M|B (top, middle, bottom) for y alignment; eg "LT" meaning left, top. Omitting the align parameter displays nothing.

The function returns the size of the text block or false indicating failure.

<?php
function imagettfalign (&$im,$size,$x,$y,$col,$font,$text,$align='')
{
$box = imagettfbbox ($size,0,$font,$text) ;
if (!
$box) return false ;
if (
$align)
{
switch (
strtoupper($align[0])) // X position
{
case
'L' : $tX = $x - $box[0] ; break ;
case
'R' : $tX = $x - $box[2] ; break ;
case
'M' : $tX = $x - $box[2]/2 ; break ;
default : return
false ;
}
switch (
strtoupper($align[1])) // Y position
{
case
'B' : $tY = $y - $box[1] ; break ;
case
'T' : $tY = $y - $box[7] ; break ;
case
'M' : $tY = $y - $box[7]/2 ; break ;
default : return
false ;
}
if (!
imagettftext ($im,$size,0,$tX,$tY,$col,$font,$text)) return false ;
}
$r[0]=abs($box[2]) ;
$r[1]=abs($box[7]) ;
return
$r ;
}
?>

An example (excluding font declarations, etc) would be:
<?php
$im
= @imagecreatetruecolor(400,200) ;
$colBlack = imagecolorallocate($im,0, 0, 0);
$xy = imagettfalign ($im,12,200,100,$colBlack,$ttFont,"The middle",'MM') ;
?>

This will show "The middle" smack in the centre of the image.

Finally, apologies for the non-standard indentation. It's just the way I've been doing it for years...
up
2
james dot heazlewood at crownbet com au
7 years ago
I found the bounding boxes a bit tricky to use when trying to rotate AND align text boxes. I wrote this function allows you to set left, right or center aligned text and also rotate it.

<?php
/**
* Renders rotate-able and align-able text of any font or colour
*
* @param resource $img Image resource
* @param string $text
* @param int $x
* @param int $y
* @param int $fontSize
* @param string $fontFile Full path to font file
* @param array $color Red, green, blue values in either int (255) or hex (0xFF)
* @param string $align Accept 'left', 'right', and defaults to center
* @return void
*/
function gd_text_aligned($img, $text, $x, $y, $fontSize, $fontFile, $color = [0, 0, 0], $align = 'left') {

// Create colour Resource
$textColor = imagecolorallocate($img, $color[0], $color[1], $color[2]);

// Create bounding box co-ordinates
$boundingBox = imagettfbbox($fontSize, $rotation, $fontFile, $text);
$textBox = imagettfbbox($fontSize, 0, $fontFile, $text);

// Bounding box array key meanings
//
// $bBox[0] = lower left X
// $bBox[1] = lower left Y
// $bBox[2] = lower right X
// $bBox[3] = lower right Y
// $bBox[4] = upper right X
// $bBox[5] = upper right Y
// $bBox[6] = upper left X
// $bBox[7] = upper left Y
//
// 6,7 | 4,5
// -----+-----
// 0,1 | 2,3
//
$boundingBoxWidth = $boundingBox[4] - $boundingBox[0];
$boundingBoxHeight = $boundingBox[5] - $boundingBox[1];
$flatHeight = $textBox[5] - $textBox[1];

// Align left right or centred?
if($align == 'left') {
$drawX = $x - sin($rotation * M_PI / 180) * ($flatHeight / 2);
$drawY = $y - cos($rotation * M_PI / 180) * ($flatHeight / 2);
} else if(
$align == 'right') {
$drawX = $x - $boundingBoxWidth + sin($rotation * M_PI / 180) * ($flatHeight / 2);
$drawY = $y - $boundingBoxHeight + cos($rotation * M_PI / 180) * ($flatHeight / 2);
} else {
// no alignment (centred)
$drawX = $x - $boundingBoxWidth / 2;
$drawY = $y - $boundingBoxHeight / 2;
}

// draw text
imagettftext(
$img,
$fontSize,
$rotation, $drawX, $drawY,
$textColor, $fontFile, $text
);

}
up
2
Andrey Zakharov
13 years ago
For mixed text drawing on image, height given by this function is useless and leads to text's hip-hops over the baseline .

I will use just this:
<?php
$size
= 12;//font height
$font = 'Arial';// your font
$char = 'Test';
$char = 'With W';
$char = 'without w but with p and y and q';

$rect = imagettfbbox($size, 0, $font, $char);

$image_height =abs( $rect[7] );//do no respect bottom margin
$imw = $rect[2] - $rect[0]; //as usual
$bx = abs( $rect[ 0 ] ); // X offset
$by = $size * 1.25; // Y offset - we will use const LINEHEIGHT
?>
up
1
tuxedobob
8 years ago
You might save yourself a lot of time and headache if you remember that the bold version of a font is NOT necessarily the same height as the regular version of that font!

(In fact, it can be shorter!)
up
0
dvladimirov77 at gmail dot com
4 years ago
if the line starts with a narrow character, for example: "1"

function new_imagettfbbox($size, $angle, $fontfile, $text)
{
$first = substr($text, 0, 1);
$sub = substr($text, 1);

switch ($first)
{
case '1':
$text = '0' . $sub;
break;
}

return imagettfbbox($size, $angle, $fontfile, $text);
}
up
1
hkc@taiwan
15 years ago
I want to output a bounding box of a text as an image straightly. I did like this:

<?php

$text
= "<?php echo \"hello, world\"; ?>";
$font = "./arial.ttf";
$size = "60";

$bbox = imagettfbbox($size, 0, $font, $text);

$width = abs($bbox[2] - $bbox[0]);
$height = abs($bbox[7] - $bbox[1]);

$image = imagecreatetruecolor($width, $height);

$bgcolor = imagecolorallocate($image, 255, 255, 255);
$color = imagecolorallocate($image, 0, 0, 0);

$x = $bbox[0] + ($width / 2) - ($bbox[4] / 2);
$y = $bbox[1] + ($height / 2) - ($bbox[5] / 2);

imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);

$last_pixel= imagecolorat($image, 0, 0);

for (
$j = 0; $j < $height; $j++)
{
for (
$i = 0; $i < $width; $i++)
{
if (isset(
$blank_left) && $i >= $blank_left)
{
break;
}

if (
imagecolorat($image, $i, $j) !== $last_pixel)
{
if (!isset(
$blank_top))
{
$blank_top = $j;
}
$blank_left = $i;
break;
}

$last_pixel = imagecolorat($image, $i, $j);
}
}

$x -= $blank_left;
$y -= $blank_top;

imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);

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

?>
up
1
bushj at rpi dot edu
17 years ago
Apparently the bounding box returned by imagettftext and imagettfbbox is not the same, and it appears as though imagettftext does a better job at calculating the actual bounding box (maybe because it has to render every character and it then finds out really everywhere it rendered).

So, you can create a dummy image render the text to it and get a better box. Here is an example function:
<?php
function better_imagettfbbox($size, $angle, $font, $text) {
$dummy = imagecreate(1, 1);
$black = imagecolorallocate($dummy, 0, 0, 0);
$bbox = imagettftext($dummy, $size, $angle, 0, 0, $black, $font, $text);
imagedestroy($dummy);
return
$bbox;
}
?>
If you use this a lot, it would be better to keep one dummy image instead of continually creating and destroying images.
up
0
user107
9 years ago
I found a simple solution that was working for me:

<?php
if(!isset($_GET['size'])) $_GET['size'] = 44;
if(!isset(
$_GET['text'])) $_GET['text'] = "Hello, world!";

$size = imagettfbbox($_GET['size'], 0, "ARIAL", $_GET['text']);
$xsize = abs($size[0]) + abs($size[2]);
$ysize = abs($size[5]) + abs($size[1]);

$image = imagecreate($xsize, $ysize);
$blue = imagecolorallocate($image, 0, 0, 255);
$white = ImageColorAllocate($image, 255,255,255);
imagettftext($image, $_GET['size'], 0, abs($size[0]), abs($size[5]), $white, "ARIAL", $_GET['text']);

header("content-type: image/png");
imagepng($image);
imagedestroy($image);
?>

Here is the link with a examples:
http://www.tuxradar.com/practicalphp/11/2/6#null
up
0
rasmus at mindplay dot dk
11 years ago
It should be noted that the bounding box coordinates returned by this function are inaccurate - bug reports about this have been open for 5 years, so expect this will likely never be fixed.

More information here:

https://gist.github.com/mindplay-dk/4429153
up
0
Dario
15 years ago
My solution to below-baseline characters is to simply apply a smaller angle and some padding when calculating your boundaries, so the function thinks your text goes below baseline. For example:

<?php
// GET BOUNDS OF TEXT
$bounds = imagettfbbox($size*1.05, $angle-3, $font, $text);
?>
up
0
Anonymous
16 years ago
SIMPLE OVERLOADED FUNCTION: Adds TTF Center and Right Alignment to co ordintate points.
Correctly demonstrates the use of the bouning box TTF function and the array of coordinates that it returns.

After obtaining values and adjusting based on a set of values [L, C, R], it uses simple math based of the length of the text to move it from the origin (x = 0 )

<?php
function imagettftextalign($image, $size, $angle, $x, $y, $color, $font, $text, $alignment='L')
{

//check width of the text
$bbox = imagettfbbox ($size, $angle, $font, $text);
$textWidth = $bbox[2] - $bbox[0];
switch (
$alignment) {
case
"R":
$x -= $textWidth;
break;
case
"C":
$x -= $textWidth / 2;
break;
}

//write text
imagettftext ($image, $size, $angle, $x, $y, $color, $font, $text);

}
?>
up
0
beosman at gmail dot com
16 years ago
I was viewing the code for calculate the box of a text for a given font but I do not found one that works fine with different angles from zero, so I have made a function simpler than above:

<?php

function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) {
$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),
"top" => abs($minY),
"width" => $maxX - $minX,
"height" => $maxY - $minY,
"box" => $rect
);
}

?>

With this function you can center an angled string in any image:

<?php

$mystring
= "Hello world!";

$imgWidth = 300;
$imgHeight = 150;

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

$box = calculateTextBox($mystring,"./Verdana.ttf",15,45);
$color = imagecolorallocate($image,0,0,0);
imagettftext($image,
15,
45,
$box["left"] + ($imgWidth / 2) - ($box["width"] / 2),
$box["top"] + ($imgHeight / 2) - ($box["height"] / 2),
$color,
"./Verdana.ttf",
$mystring);

header("Content-Type: image/x-png");
imagepng($im);
imagedestroy($im);

?>
up
0
mihai.draghicioiu at gmailcom
16 years ago
To get the height for a line of text, I've found it useful to do:

<?php

$bbox
= imagettfbbox($size, 0, $ttf, " \n "); // space, newline, space

$height = $bbox[3] - $bbox[5];

?>

I hope this helps. Before, I used the string "Tj", but that sometimes fell short, especially for crazy fonts.
up
0
heshan at sjtu dot edu dot cn
16 years ago
the imagettfbbox and imagettftext quirks are:

1. imagettfbbox and imagettftext have the same return value and both of them are wrong for angle not equal to zero.
2. imagettfbbox returns the correct bounding box when angle is zero.
3. the bounding box has a coordinate system that the x gets bigger from left to right and y gets bigger from top to bottom.
4. the "base point" used in imagettftext is the origin in the bounding box coordinate system.
5. when the angle is other than 0, it is actually rotated in the coordinate system with respect to the base point. so if we know the bounding box coordinate when angle is zero, we can get the new bounding box coordinate by doing the rotation by math equations manually.
6. to have pixel level accuracy, we should also be aware of another thing. suppose the axis is like this: |_|_|_|, the bounding box coordinate uses point on the vertical line while image function uses point on the horizontal line, so there is a 1 pixel difference you should take care of.

The following snippet creates minimal images containing a letter of different font and rotation angle. This is especially useful in captcha scripts.

<?php

function create_font_image( $size, $angle, $font, $char )
{
$rect = imagettfbbox( $size, 0, $font, $char );
if(
0 == $angle ) {
$imh = $rect[1] - $rect[7];
$imw = $rect[2] - $rect[0];
$bx = -1 - $rect[0];
$by = -1 - $rect[7];
} else {
$rad = deg2rad( $angle );
$sin = sin( $rad );
$cos = cos( $rad );
if(
$angle > 0 ) {
$tmp = $rect[6] * $cos + $rect[7] * $sin;
$bx = -1 - round( $tmp );
$imw = round( $rect[2] * $cos + $rect[3] * $sin - $tmp );
$tmp = $rect[5] * $cos - $rect[4] * $sin;
$by = -1 - round( $tmp );
$imh = round( $rect[1] * $cos - $rect[0] * $sin - $tmp );
} else {
$tmp = $rect[0] * $cos + $rect[1] * $sin;
$bx = -1 - round( $tmp );
$imw = round( $rect[4] * $cos + $rect[5] * $sin - $tmp );
$tmp = $rect[7] * $cos - $rect[6] * $sin;
$by = -1 - round( $tmp );
$imh = round( $rect[3] * $cos - $rect[2] * $sin - $tmp );
}
}
$im = imagecreatetruecolor( $imw, $imh );
imagefill( $im, 0, 0, imagecolorallocate( $im, 255, 0, 255 ) );
imagettftext( $im, $size, $angle, $bx, $by, imagecolorallocate( $im, 0, 0, 0 ), $font, $char );
imagegif( $im, trim( $font, './' ) . ord( $char ) . $angle . '.gif' );
imagedestroy( $im );
}

$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$angles = array( -30, -20, -10, 0, 10, 20, 30 );
$fonts = array( './latinwide.ttf', './verdana.ttf', './times.ttf', './broadway.ttf' );
foreach(
$angles as $angle )
foreach(
$fonts as $font )
for(
$i = 0; $i < strlen( $chars ); ++$i )
create_font_image( 100, $angle, $font, $chars[$i] );
?>
up
0
intuz et gmx dt de
17 years ago
I still got problems trying to rotate imagettftext using imagettfbbox.

It's position calculation is mostly wrong. So i tried to rotate ttftext with IMAGEROTATE.

As a special the result is in black fontcolor and transparent background.

Hope it helps sombody (thanks for function convertBoundingBox, reading below)

<?
function ImgText($text,$fontsize,$font,$angle){
$im = '';
if($text){
if(!$fontsize || $fontsize < 1) $fontsize = 12;
if(!$font) $font = "fonts/arial.ttf";
$bbox = imagettfbbox($fontsize, 0, $font, $text);
$size=convertBoundingBox($bbox);
$im = ImageCreatetruecolor($size['width'],$size['height']);

$white = ImageColorAllocate($im, 255, 255, 255);
$black = ImageColorAllocate($im, 0,0,0);

imagefill ($im, 0, 0, $white );
imagettftext($im, $fontsize, 0, $size['xOffset'], $size['yOffset'], $black, $font, $text);
$im = imagerotate( $im,$angle, $white);
imagecolortransparent ($im,$white);
}else{
// No text
}
}
?>
up
0
Ruquay
17 years ago
Several comments show that the output of this function is often not what is expected, especially when the text is rotated.

For those of you who'd like a visual representation of what is happening to the bounding box as the text is rotated, take a look here:

http://ruquay.com/sandbox/imagettf/
up
0
Nate Sweet
17 years ago
An improvement to the convertBoundingBox function. The previous function was completely wrong. My confusion came from characters like "1" and "_" that are rendered to the right or below the basepoint (in the font I'm using). I ended up using mike at mikeleigh dot com's function with a fix for these characters, and a "belowBasepoint" value.
<?php
function convertBoundingBox ($bbox) {
if (
$bbox[0] >= -1)
$xOffset = -abs($bbox[0] + 1);
else
$xOffset = abs($bbox[0] + 2);
$width = abs($bbox[2] - $bbox[0]);
if (
$bbox[0] < -1) $width = abs($bbox[2]) + abs($bbox[0]) - 1;
$yOffset = abs($bbox[5] + 1);
if (
$bbox[5] >= -1) $yOffset = -$yOffset; // Fixed characters below the baseline.
$height = abs($bbox[7]) - abs($bbox[1]);
if (
$bbox[3] > 0) $height = abs($bbox[7] - $bbox[1]) - 1;
return array(
'width' => $width,
'height' => $height,
'xOffset' => $xOffset, // Using xCoord + xOffset with imagettftext puts the left most pixel of the text at xCoord.
'yOffset' => $yOffset, // Using yCoord + yOffset with imagettftext puts the top most pixel of the text at yCoord.
'belowBasepoint' => max(0, $bbox[1])
);
}
?>
up
0
Nate Sweet
17 years ago
It took me some time to make full use of imagettfbbox. Hopefully the following function makes it much easier to use for others.

<?php
function convertBoundingBox ($bbox) {
if (
$bbox[0] >= -1)
$leftOfBasepoint = -abs($bbox[0] + 1);
else
$leftOfBasepoint = abs($bbox[0] + 2);
$rightOfBasepoint = abs($bbox[2] - $bbox[0]);
if (
$bbox[0] < -1) $rightOfBasepoint = abs($bbox[2]) + abs($bbox[0]) - 1;
$aboveBasepoint = abs($bbox[5] + 1);
$height = abs($bbox[7]) - abs($bbox[1]);
if (
$bbox[3] > 0) $height = abs($bbox[7] - $bbox[1]) - 1;
$width = $leftOfBasepoint + $rightOfBasepoint;
$belowBasepoint = $height - $aboveBasepoint;
return array(
'width' => $width,
'height' => $height,
'leftOfBasepoint' => $leftOfBasepoint,
'rightOfBasepoint' => $rightOfBasepoint,
'aboveBasepoint' => $aboveBasepoint,
'belowBasepoint' => $belowBasepoint
);
}
?>

Thanks goes to mike at mikeleigh dot com for providing the core of this function.

Remember, the basepoint is the x, y coords you use to draw text with imagettftext. A useful thing to do is take a string like...
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890
...and use the "aboveBasepoint" value for the height of your font. Now you can draw lines and use "the height of your font * leading" as the distance between lines of text, where leading is a number like 1.45 (for 45% leading).
up
0
Nate Sweet
17 years ago
This script shows you side by side the difference between a font rendered at a certain size and the same font rendered at some multiple of that size and then scaled down by the same multiple. It seems to help small sizes and affects large ones less. This script lets you see if it is worth implementing for your situation. Included is the great "imagettfbboxextended" function by mike at mikeleigh dot com below.

$size = 30;
$factor = 16;

$smallSize = imagettfbboxextended($size, 0, "fonts/MPlantin.ttf", "The quick brown fox jumps over the lazy dog.");
$smallWidth = $smallSize['width'];
$smallHeight = $smallSize['height'];
$canvas = imagecreatetruecolor($smallWidth + 20, $smallHeight * 2 + 20);
imagefill($canvas, 0, 0, imagecolorallocate($canvas, 255, 255, 255));
imagettftext($canvas, $size, 0, 10 + $smallSize['x'], 10 + $smallSize['y'], imagecolorallocate($canvas, 0, 0, 0), "fonts/MPlantin.ttf", "The quick brown fox jumps over the lazy dog.");

$largeSize = imagettfbboxextended($size * $factor, 0, "fonts/MPlantin.ttf", "The quick brown fox jumps over the lazy dog.");
$largeWidth = $largeSize['width'];
$largeHeight = $largeSize['height'];
$temp = imagecreatetruecolor($largeWidth, $largeHeight);
imagefill($temp, 0, 0, imagecolorallocate($canvas, 255, 255, 255));
imagettftext($temp, $size * $factor, 0, $largeSize['x'], $largeSize['y'], imagecolorallocate($temp, 0, 0, 0), "fonts/MPlantin.ttf", "The quick brown fox jumps over the lazy dog.");
imagecopyresampled($canvas, $temp, 10 + $smallSize['x'], 10 + $smallSize['y'] + 10, 0, 0, $smallWidth, $smallHeight, $largeWidth, $largeHeight);
imagepng($temp, "temp.png");

imagepng($canvas, "test.png");

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;
}
up
0
lassial dot gmail dot com
17 years ago
Ralph Bolton commented about the difference in calculating the bounding box size vs. aligning text base line.

The workaround for this issue is to calculate the difference in height between a character going below baseline and one above the baseline. This is likely going to vary from font to font, so I'd suggest something like this:

<?php

function fontBaselineOffset($font, $fontSize)
{
//this should be above baseline
$test2="H";
//some of these additional letters should go below it
$test3="Hjgqp";

//get the dimension for these two:

$box2 = imageTTFBbox($fontSize,0,$font,$test2);
$box3 = imageTTFBbox($fontSize,0,$font,$test3);

//return the offset value

return abs((abs($box2[5]) + abs($box2[1])) - (abs($box3[5]) + abs($box3[1])));

}
?>

This is not perfect yet. You should define a range of allowed characters that can go below baseline, compare them to the ones actually found in your string and use them instead of the string $test3 used in the example function above. This should avoid problems with letters that go further below baseline than the others (e.g. there could be a difference between 'g' and 'p')
up
-1
gw at example dot com
8 years ago
a little something to replace in blackbart tip :

// 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 );
}

with

// start scanning (0=> black => empty)
$break = false;
$rleft = $w4 = $width<<2;
$rright = 0;
$rbottom = 0;
$rtop = $h4 = $height<<2;
// scanning from left to right, breaking when a pixel is found, to scan from the other side : avoid scanning all pixels !
for($x=0; $x<$w4; $x++){
for($y=0; $y<$h4; $y++)
if(imagecolorat($img,$x,$y)){
$rtop = min($rtop, $y); $rleft = min($rleft, $x);
$break = true; break;
}
if($break) break;
}
// scanning from right to left, breaking when a pixel is found
for($x=($w4-1); $x>$rleft; $x--){
for($y=0; $y<$h4; $y++)
if(imagecolorat($img,$x,$y)){
$rright = max($rright, $x); $rbottom = max($rbottom, $y);
$break = true; break;
}
if($break) break;
}
//... //

it may be even better to check if the picture is portrait or landscape, to start the loops from left-right(landscape) or top-bottom (portrait)
up
0
peisenmann at gmail dot com
18 years ago
Another function for centered text string.
What it does: Generate a truecolor .png image of a text string. The image will be just large enough encompass the text and a 2 px border and the text will be centered in it.

It is called from any other page like so...
<img src="linkImg.php?text=php.net is great&border=out" /> // Text with #&+"'\<> will need to be escaped, but I've found spaces don't cause errors. I haven't tested this with any other languages.

The following code is the file named linkImg.php
The file was not designed to have anything else here with it, and the open and close php tags should the the very first and very last characters of the page respectively, as outside whitespace can be a little evil sometimes.
<?php
//Obtain text and border via GET
//Border can be out, in, or flat
$text = $_GET['text'];
$border = $_GET['border'];

$font = "fontpath"; //(str) "fonts/sasquatchlives.ttf"
$fontsize = font size; //(int) pixels in GD 1, or points in GD 2

//Register box
$box = imagettfbbox ($fontsize, 0, $font, $text);
//Find out the width and height of the text box
$textW = $box[2] - $box[0];
$textH= $box[3]-$box[5];
//Add padding
$paddingx = 10;
$paddingy = 10;
//Set image dimentions
$width = $textW+$paddingx;
$height= $textH+$paddingy;

//Bottom left corner of text
$textx = $paddingx/2;
$texty = $height - $paddingy/2;

//Shadow offset (pixels)
$shadoffx = 1;
$shadoffy = 1;

//Create the image
$img = imagecreatetruecolor($width,$height);
//Define some colors
$white = imagecolorallocate($img,255,255,255);
$black = imagecolorallocate($img,0,0,0);
$lightgrey = imagecolorallocate($img,200,200,200);
$grey = imagecolorallocate($img,100,100,100);
//Define Text (fg) and background (bg) colors
$bgcol = imagecolorallocate($img,192,213,196); //Celadon (light pastel green)
$fgcol = imagecolorallocate($img,243,104,88); //Peach
// Fill image with background color
imagefill($img,0,0,$bgcol);

//Write Shadow
imagettftext($img, $fontsize, 0, $textx+$shadoffx, $texty+$shadoffy, $grey, $font, $text);

//Write Text
imagettftext($img, $fontsize, 0, $textx, $texty, $fgcol, $font, $text);

//Bordering

//Embossed border (button-looking)
if ($border == "out")
{
imageline ($img,0,0,$width,0,$white);imageline ($img,0,0,0,$height,$white);
imageline ($img,1,1,$width,1,$lightgrey);imageline ($img,1,1,1,$height-1,$lightgrey);
imageline ($img,0,$height-1,$width-1,$height-1,$black);imageline ($img,$width-1,$height-1,$width-1,0,$black);
imageline ($img,2,$height-2,$width-2,$height-2,$grey);imageline ($img,$width-2,$height-2,$width-2,2,$grey);

}
//Flat border
if ($border == "flat")
{
imageline ($img,0,0,$width,0,$white);imageline ($img,0,0,0,$height,$white);
imageline ($img,1,1,$width,1,$grey);imageline ($img,1,1,1,$height-1,$grey);
imageline ($img,0,$height-1,$width-1,$height-1,$white);imageline ($img,$width-1,$height-1,$width-1,0,$white);
imageline ($img,2,$height-2,$width-2,$height-2,$grey);imageline ($img,$width-2,$height-2,$width-2,2,$grey);
}

//Engraved border (pushed button)
if ($border == "in")
{
imageline ($img,0,0,$width,0,$black);imageline ($img,0,0,0,$height,$black);
imageline ($img,1,1,$width,1,$grey);imageline ($img,1,1,1,$height-1,$grey);
imageline ($img,0,$height-1,$width-1,$height-1,$white);imageline ($img,$width-1,$height-1,$width-1,0,$white);
imageline ($img,2,$height-2,$width-2,$height-2,$lightgrey);imageline ($img,$width-2,$height-2,$width-2,2,$lightgrey);
}

// Header info
header("Content-type: image/png");
//Sends the image
imagepng($img);
imagedestroy($img);
?>

Hope this helps someone!
-Patrick-
up
-1
Stefan at colulus dot com
16 years ago
I worked out a script that allows the transfer of alphanumeric data to be placed on an image. The HTML feature is img src and the php feature is imagettftext. This simple code will increment from 1 to 3 on images.

code:

<?php
//ImageCall.php -- This script will call a script to produce the image.
for($next = 1;$next < 4; $next++){
print
"Image $next:<br>";
print
"<img src = 'Image.php?\$text=$next'>";
print
"<br><br>";
}
?>

<?php
//Image.php -- This script creates a square image and places the text on it.

// image size and color
$im = ImageCreate(77,77);
$color1 = ImageColorAllocate($im,0x66,0xCC,0x00);
$color2 = ImageColorAllocate($im,0x33,0x66,0x00);
$color3 = ImageColorAllocate($im,0x00,0x99,0x00);
$color4 = ImageColorAllocate($im,0x3D,0x3D,0x3D);

// image creation
ImageFilledRectangle($im,1,1,76,76,$color1);
ImageFilledpolygon($im, array (76,1,1,76,76,76),3,$color2);
ImageFilledRectangle($im,5,5,72,72,$color3);

// determine numeric center of image
$size = ImageTTFBBox(45,0,'impact',$_GET['$text']);
$X = (77 - (abs($size[2]- $size[0])))/2;
$Y = ((77 - (abs($size[5] - $size[3])))/2 + (abs($size[5] - $size[3])));

//places numeric information on image
ImageTTFText($im,45,0,($X-1),$Y,$color4,'impact',$_GET['$text']);

//returns completed image to calling script
Header('Content-Type: image/png');
Imagepng($im);

?>
up
-1
ralphbolton at mail2sexy dot com
17 years ago
There's a bit of an annoyance with measuring font sizes and drawing boxes around text. When fonts are measured using ImageTTFbbox, the correct vertical height is returned. That is, the measurement of the phrase "Hanging" will be from the top of the "H" to the bottom of the "g".

The problem is that functions like imageTTFtext align with the "line" of the text - that is, in the phrase "Hanging", the alignment is below the "H", not the bottom of the "g". That means that if you draw a rectangle behind your text, it'll be incorrectly aligned because the hanging "g" will be outside the box.

For example, this doesn't work as you might expect (because the "g" hangs below the box):
<?php
// Get the size of the font box
$textbox = imageTTFBbox($size, 0, $font, 'Hanging');
$textwidth = abs($textbox[4] - $textbox[0]);
$textheight = abs($textbox[5] - $textbox[1]);

// Now draw a rectangle on the image
$colour = ImageColorAllocate($im, 100, 100, 100);
imagefilledrectangle($im, $x, $y - $textheight, $x + $textwidth, $y, $colour );

// Now draw the text
$black = ImageColorAllocate($im, 0, 0, 0);
ImageTTFText($image['resource'], $size, 0, $x, $y, $black, $font, 'Hanging');
?>
It also seems that the rectangle in the above example is located 1 pixel to the left of the text.

I haven't found a way to resolve this problem correctly. Instead, I have enlarged the rectangle and then put the text into it. I don't think this will work absolutely correctly for all fonts, so it's not exactly a perfect solution. However, it's better than nothing! Here is a snippet of it:
<?php
$enlargex
= $textwidth * 0.08;
$enlargey = $textheight * 0.1;
$enlargey2 = $textheight * 0.5;

// Now draw a rectangle on the image
$colour = ImageColorAllocate($im, 100, 100, 100);
imagefilledrectangle($im, $x - $enlargex, $y - $textheight - $enlargey, $x + $textwidth + $enlargex, $y + $enlarge2, $colour );
?>
To Top