|
 |
imagettfbbox (PHP 3 >= 3.0.1, PHP 4, PHP 5) imagettfbbox -- Give the bounding box of a text using TrueType fonts Descriptionarray imagettfbbox ( float size, float angle, string fontfile, string text )
This function calculates and returns the bounding box in pixels
for a TrueType text.
- size
The font size in pixels. - angle
Angle in degrees in which text will be
measured.
- fontfile
The name of the TrueType font file (can be a URL). Depending on
which version of the GD library that PHP is using, it may attempt to
search for files that do not begin with a leading '/' by appending
'.ttf' to the filename and searching along a library-defined font path.
- text
The string to be measured.
imagettfbbox() returns an array with 8
elements representing four points making the bounding box of the
text:
The points are relative to the text
regardless of the angle, so "upper left" means in the top
left-hand corner seeing the text horizontally.
This function requires both the GD library and the FreeType
library.
See also imagettftext().
imagettfbbox
Nimja
08-May-2006 01:09
Warning:
james.logsdon's function has a few flaws in copying my own function. Though he did a great job in making an overall nicer looking function it does have a few flaws.
His function does not allow for long words (longer then the width) linebreaks (harder then it looks) and has a non-pixel perfect location.
The problem with the imagettfbbox function is that different letters give a different x/y top-left coordinate. At least it looks that way for the eye. I 'solved' this by putting a space in front of every line and then offset the text by the width of that space.
So, although some things of my function seem useless they do serve an important purpose.
james.logsdon at firesidemedia dot net
05-May-2006 01:32
I've modified Nimja's function a little. It doesn't support line-breaks (didn't need it in my script), but it's easy enough to add in.
<?php
function imageWordWrapBBox ( $Text, $Width = 650, $FontSize = 10, $Font = './fonts/arial.ttf' )
{
$Words = split ( ' ', $Text );
$Lines = array ( );
$Line = '';
foreach ( $Words as $Word )
{
$Box = imagettfbbox ( $FontSize, 0, $Font, $Line . $Word );
$Size = $Box[4] - $Box[0];
if ( $Size > $Width )
{
$Lines[] = trim ( $Line );
$Line = '';
}
$Line .= $Word . ' ';
}
$Lines[] = trim ( $Line );
$Dimensions = imagettfbbox ( $FontSize, 0, $Font, 'AJLMYabdfghjklpqry019`@$^&*(,' );
$lineHeight = $Dimensions[1] - $Dimensions[5];
return array ( $lineHeight, $Lines, $lineHeight * count ( $Lines ) );
}
function imageWordWrap ( $Text, $Width, $Color, $X = 0, $Y = 0, $FontSize = 10, $Font = './fonts/arial.ttf' )
{
$Data = $this->imageWordWrapBBox ( $Text, $Width, $FontSize, $Font );
foreach ( $Data[1] as $Key => $Line )
{
$locX = $X;
$locY = $Y + ( $Key * $Data[0] );
imagettftext ( $this->Image, $FontSize, 0, $locX, $locY, $Color, $Font, $Line );
}
return $Data;
}
?>
toe dot cutter at telia dot com
28-Feb-2006 07:41
Neither Greg's or Henrik N's code worked for me.
I figured out that imagettfbbox gives the size (coordinates) of the whole letter (ie. with the hang on 'g' or 'j'). So it was only a matter of finding the correct index of coordinates in the array.
Note: This doesn't work on Times New Roman Italic's 'f' for some reason.
<?php
$size = imagettfbbox($fontsize, 0, $font, $text);
$dx = abs($size[2]-$size[0]);
$dy = abs($size[5]-$size[3]);
ImageTTFText($im, $fontsize, 0, abs($size[6]), abs($size[5]), $txtcolor, $font, $text);
?>
Henrik N
26-Feb-2006 01:48
Tried Greg's code below, but it didn't quite work for me. This did, however:
<?php
$size = imagettfbbox($fontSize, 0, $font, $text);
$width = $size[2] + $size[0];
$height = abs($size[1]) + abs($size[7]);
$image = imagecreatetruecolor($width, $height);
imagettftext($image, $fontSize, 0, 0, abs($size[5]), $black, $font, $text);
?>
greg at gregoryfenton dot be
11-Feb-2006 02:23
Have a problem with imagettfbbox cutting off the hang of letters such as 'g' or 'j'??
After days trying to figure this thing out, I finally cracked it:
$size = imagettfbbox($s,0,$font,$text);
$dx=abs($size[0])+abs($size[2]);
$dy=abs($size[1])+abs($size[7]);
ImageTTFText($im, $s, 0, $dx-abs($size[0]), $dy-abs($size[1]), $black, $font, $text);
The key is the abs commands - you must account for the negative numbers in the original imagettfbbox, and if you have any, take them away from the location at the end when the text is displayed:
you need to start the x and y at a (possibly) negative number, not 0,0 as I had thought.
Hope that helps someone..
Nimja
13-Jan-2006 08:32
My previous function had 2 bugs which are now fixed:
* Align is now pixel perfect, no longer dependant on the first character. Solved by putting a space " " in front of every rendered line, making the basepoint at the exact same place every time.
* X Y Coordinates are no longer the base-point, but the perfect top/left coordinates. This made my life designing a LOT easier.
Features:
* Newline support! (both Windows and Linux)
* Paragraph support, no newlines are ignored, not even empty ones. So empty lines are properly supported.
* True top/left x/y coordinates instead of TTF basepoint.(at least as close as possible).
* Align function for Left, Center and Right
* Support for words that are longer then the supported width.
<?php
function imageTextWrapped(&$img, $x, $y, $width, $font, $color, $text, $textSize, $align="l") {
$y += $textSize;
$dimensions = imagettfbbox($textSize, 0, $font, " "); $x -= $dimensions[4]-$dimensions[0];
$text = str_replace ("\r", '', $text); $srcLines = split ("\n", $text); $dstLines = Array(); foreach ($srcLines as $currentL) {
$line = '';
$words = split (" ", $currentL); foreach ($words as $word) {
$dimensions = imagettfbbox($textSize, 0, $font, $line.$word);
$lineWidth = $dimensions[4] - $dimensions[0]; if ($lineWidth > $width && !empty($line) ) { $dstLines[] = ' '.trim($line); $line = '';
}
$line .= $word.' ';
}
$dstLines[] = ' '.trim($line); }
$dimensions = imagettfbbox($textSize, 0, $font, "MXQJPmxqjp123"); $lineHeight = $dimensions[1] - $dimensions[5]; $align = strtolower(substr($align,0,1)); foreach ($dstLines as $nr => $line) {
if ($align != "l") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[4] - $dimensions[0]; if ($align == "r") { $locX = $x + $width - $lineWidth;
} else { $locX = $x + ($width/2) - ($lineWidth/2);
}
} else { $locX = $x;
}
$locY = $y + ($nr * $lineHeight);
imagettftext($img, $textSize, 0, $locX, $locY, $color, $font, $line);
}
}
?>
Nimja
13-Jan-2006 06:01
This is a completely rewritten function of "printWordWrapped" because it lacked a few important features. First of all, it started too high with it's text, which was easily fixed. And it has the annoying 'feature' of adding a space in front of every line. Not ideal.
But secondly, and more importantly, it didn't support long words or linebreaks. This is all fixed. And I rewrote it for cleaner code.
Please note that with the current code you could easily make a vertical align as well if you wanted to. I have not done this myself since it did not fit my own needs (and I'm slightly lazy)
Enjoy:
<?php
function imageTextWrapped(&$img, $x, $y, $width, $font, $color, $text, $textSize, $align="l") {
$y += $fontSize; $text = str_replace ("\\r", '', $text); $srcLines = split ("\\n", $text); $dstLines = Array(); foreach ($srcLines as $currentL) {
$line = '';
$words = split (" ", $currentL); foreach ($words as $word) {
$dimensions = imagettfbbox($textSize, 0, $font, $line.' '.$word);
$lineWidth = $dimensions[4] - $dimensions[0]; if ($lineWidth > $width && !empty($line) ) { $dstLines[] = trim($line); $line = '';
}
$line .= $word.' ';
}
$dstLines[] = trim($line); }
$dimensions = imagettfbbox($textSize, 0, $font, "MXQJPmxqjp123"); $lineHeight = $dimensions[1] - $dimensions[5]; $align = strtolower(substr($align,0,1)); foreach ($dstLines as $nr => $line) {
if ($align != "l") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[4] - $dimensions[0]; if ($align == "r") { $locX = $x + $width - $lineWidth;
} else { $locX = $x + ($width/2) - ($lineWidth/2);
}
} else { $locX = $x;
}
$locY = $y + ($nr * $lineHeight);
imagettftext($img, $textSize, 0, $locX, $locY, $color, $font, $line);
}
}
?>
peisenmann at gmail dot com
28-Dec-2005 06:41
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
$text = $_GET['text'];
$border = $_GET['border'];
$font = "fontpath"; $fontsize = font size; $box = imagettfbbox ($fontsize, 0, $font, $text);
$textW = $box[2] - $box[0];
$textH= $box[3]-$box[5];
$paddingx = 10;
$paddingy = 10;
$width = $textW+$paddingx;
$height= $textH+$paddingy;
$textx = $paddingx/2;
$texty = $height - $paddingy/2;
$shadoffx = 1;
$shadoffy = 1;
$img = imagecreatetruecolor($width,$height);
$white = imagecolorallocate($img,255,255,255);
$black = imagecolorallocate($img,0,0,0);
$lightgrey = imagecolorallocate($img,200,200,200);
$grey = imagecolorallocate($img,100,100,100);
$bgcol = imagecolorallocate($img,192,213,196); $fgcol = imagecolorallocate($img,243,104,88); imagefill($img,0,0,$bgcol);
imagettftext($img, $fontsize, 0, $textx+$shadoffx, $texty+$shadoffy, $grey, $font, $text);
imagettftext($img, $fontsize, 0, $textx, $texty, $fgcol, $font, $text);
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);
}
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);
}
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("Content-type: image/png");
imagepng($img);
imagedestroy($img);
?>
Hope this helps someone!
-Patrick-
Mickey9801 at ComicParty dot com
11-Dec-2005 09:31
I have revised my mb_wordwrap function to fix 2 major bugs: cannot handle line break and infinite loop while handling very very long long long single byte word.
<?php
function mb_wordwrap($txt,$font,$size,$width) {
$pointer = 0; $this_line_start = 0; $this_line_strlen = 1; $single_byte_stack = ""; $sbs_line_width = 0; $this_is_cr = FALSE; $result_lines = array(); while ($pointer < mb_strlen($txt)) {
$this_char = mb_substr($txt,$pointer,1);
if (ord($this_char[0])==10) $this_is_cr = TRUE; $tmp_line = mb_substr($txt, $this_line_start, $this_line_strlen);
$tmp_line_bbox = imagettfbbox($size,0,$font,$tmp_line);
$this_line_width = $tmp_line_bbox[2]-$tmp_line_bbox[0];
if (is_alphanumeric($this_char, $single_byte_stack)) $single_byte_stack .= $this_char;
if ($single_byte_stack != "") {
$tmp_line_bbox = imagettfbbox($size,0,$font,$single_byte_stack);
$sbs_line_width = $tmp_line_bbox[2]-$tmp_line_bbox[0];
}
if ($this_is_cr || $this_line_width > $width || $sbs_line_width >= $width) {
if ($single_byte_stack != "" && is_alphanumeric($this_char, $single_byte_stack) && $sbs_line_width < $width) {
$stack_len = mb_strlen($single_byte_stack);
$this_line_strlen = $this_line_strlen - $stack_len + 1;
$pointer = $pointer - $stack_len + 1;
}
$result_lines[] = mb_substr($txt, $this_line_start, $this_line_strlen-1);
if ($this_is_cr) { $pointer++; $this_is_cr=FALSE; }
if ($sbs_line_width >= $width) $sbs_line_width = 0;
$this_line_start = $pointer;
$this_line_strlen = 1;
$single_byte_stack = "";
} else {
if (!is_alphanumeric($this_char, $single_byte_stack)) {
$single_byte_stack = ""; }
$this_line_strlen++;
$pointer++;
}
}
$result_lines[] = mb_substr($txt, $this_line_start);
return $result_lines;
}
function is_alphanumeric($character, $stack) {
if (
(ord($character)>=48 && ord($character)<=57) ||
(ord($character)>=65 && ord($character)<=91) ||
(ord($character)>=97 && ord($character)<=123) ||
ord($character)==40 ||
ord($character)==60 ||
($stack=="" && (ord($character)==34 || ord($character)==39))
) return TRUE;
else return FALSE;
}
?>
Nashev
11-Dec-2005 05:38
see http://php.rinet.ru/manual/ru/function.imagettftext.php#57416
function ByteCount($s) {
$has_mbstring = extension_loaded('mbstring') ||@dl(PHP_SHLIB_PREFIX.'mbstring.'.PHP_SHLIB_SUFFIX);
$has_mb_shadow = (int) ini_get('mbstring.func_overload');
if ($has_mbstring && ($has_mb_shadow & 2) ) {
$size = mb_strlen($s,'latin1');
} else {
$size = strlen($s);
}
return $size;
}
function foxy_utf8_to_nce($s) {
$utf = "$s";
$max_count = 5; // flag-bits in $max_mark ( 1111 1000 == 5 times 1)
$max_mark = 248; // marker for a (theoretical ;-)) 5-byte-char and mask for a 4-byte-char;
$html = '';
$ByteCount = ByteCount($utf);
for($str_pos = 0; $str_pos < $ByteCount; $str_pos++) {
$old_chr = $utf{$str_pos};
$old_val = ord($old_chr);
$new_val = 0;
$utf8_marker = 0;
// skip non-utf-8-chars
if ($old_val > 127) {
$mark = $max_mark;
for ($byte_ctr = $max_count; $byte_ctr > 2; $byte_ctr--) {
// actual byte is utf-8-marker?
if (($old_val & $mark) == (($mark << 1) & 255)) {
$utf8_marker = $byte_ctr - 1;
break;
}
$mark = ($mark << 1) & 255;
}
}
// marker found: collect following bytes
if ($utf8_marker > 1 and isset($utf{$str_pos + 1})) {
$str_off = 0;
$new_val = $old_val & (127 >> $utf8_marker);
for($byte_ctr = $utf8_marker; $byte_ctr > 1; $byte_ctr--) {
// check if following chars are UTF8 additional data blocks
// UTF8 and ord() > 127
if( (ord($utf{$str_pos + 1}) & 192) == 128 ) {
$new_val = $new_val << 6;
$str_off++;
// no need for Addition, bitwise OR is sufficient
// 63: more UTF8-bytes; 0011 1111
$new_val = $new_val | ( ord( $utf{$str_pos + $str_off} ) & 63 );
}
// no UTF8, but ord() > 127
// nevertheless convert first char to NCE
else {
$new_val = $old_val;
}
}
// build NCE-Code
$html .= '&#'.$new_val.';';
// Skip additional UTF-8-Bytes
$str_pos = $str_pos + $str_off;
} else {
$html .= chr($old_val);
//$new_val = $old_val;
}
}
return $html;
}
Mickey9801 at ComicParty dot com
22-Nov-2005 12:49
Most of functions shared here seems only work with western language and is not suitable for multibyte characters (like Chinese). I have written a function using mb_string functions to match the need of multibyte character word wrapping.
I also added some machanism so that English word won't be cut off at the end of line. Of couse you must use unicode string on GD.
function mb_wordwrap($txt,$font,$size,$width) {
$pointer = 0;
$this_line_start = 0;
$this_line_strlen = 1;
$single_byte_stack = "";
$result_lines = array();
while ($pointer <= mb_strlen($txt)) {
$this_char = mb_substr($txt,$pointer,1);
$tmp_line = mb_substr($txt, $this_line_start, $this_line_strlen);
$tmp_line_bbox = imagettfbbox($size,0,$font,$tmp_line);
$this_line_width = $tmp_line_bbox[2]-$tmp_line_bbox[0];
if ($this_line_width > $width) {
// If last word is alphanumeric, put it to next line rather then cut it off
if ($single_byte_stack != "") {
$stack_len = mb_strlen($single_byte_stack);
$this_line_strlen -= $stack_len;
$pointer -= $stack_len;
}
$result_lines[] = mb_substr($txt, $this_line_start, $this_line_strlen-1);
$this_line_start = $pointer;
$this_line_strlen = 1;
$single_byte_stack = "";
} else {
// Prevent to cut off english word at the end of line
// if this character is a alphanumeric character or open bracket, put it into stack
if (
(ord($this_char)>=48 && ord($this_char)<=57) ||
(ord($this_char)>=65 && ord($this_char)<=91) ||
(ord($this_char)>=97 && ord($this_char)<=123) ||
ord($this_char)==40 ||
ord($this_char)==60 ||
($single_byte_stack=="" && (ord($this_char)==34 || ord($this_char)==39))
) $single_byte_stack .= $this_char;
else $single_byte_stack = ""; // Clear stack if met multibyte character and not line end
$this_line_strlen++;
$pointer++;
}
}
// Move remained word to result
$result_lines[] = mb_substr($txt, $this_line_start);
return $result_lines;
}
c.scheffers [gmail]
14-Aug-2005 01:15
I would like to post a small modification to the imageprintWordWrapped() posted below also.
The following code causes each line to start with a space, which results in the incorrect alignment of text:
$line .= ' '.$words[0]; // add the word to the current sentence
A (quick) fix for this problem:
$line .= ($line != '' ? ' ' : '').$words[0]; // add the word to the current sentence
fernandez_marce at yahoo dot com
03-Aug-2005 10:53
I would modify the last function imageprintWordWrapped() posted below. When it says:
// do the actual printing
$i = 0;
$i should be equal to 1, because if $top is greater than 0, the imagettftext() call will not work for the first element in the $lines array ($top + lineHeight*$i) == $top when $i=0!
imagettftext($image, $textSize, 0, $leftStart, $top + $lineHeight * $i, $color, $font, $line);
$i++;
To sum up, replace
// do the actual printing
$i = 0;
with:
// do the actual printing
$i = 1;
Cheers,
Marcelo
thetorpedodog [gmail]
28-Jul-2005 09:09
Just for the sake of consistency, I turned Miles' function into one that takes a $right value rather than a $maxWidth value. This makes it like all the other image* functions.
<?php
function imageprintWordWrapped(&$image, $top, $left, $right, $font, $color, $text, $textSize, $halign="left") {
$maxWidth = $right - $left ; $words = explode(' ', strip_tags($text)); $line = '';
while (count($words) > 0) {
$dimensions = imagettfbbox($textSize, 0, $font, $line.' '.$words[0]);
$lineWidth = $dimensions[2] - $dimensions[0]; if ($lineWidth > $maxWidth) { $lines[] = $line; $line = ''; }
$line .= ' '.$words[0]; $words = array_slice($words, 1); }
if ($line != '') { $lines[] = $line; } $lineHeight = $dimensions[1] - $dimensions[7]; $height = count($lines) * $lineHeight; $i = 0;
foreach ($lines as $line) {
if($halign=="center") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[2] - $dimensions[0];
$center=floor($maxWidth/2 + $left);
$leftStart=$center-$lineWidth/2;
} else if ($halign=="right") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[2] - $dimensions[0];
$leftStart=$left+$maxWidth-$lineWidth;
} else {
$leftStart=$left;
}
imagettftext($image, $textSize, 0, $leftStart, $top + $lineHeight * $i, $color, $font, $line);
$i++;
}
return $height;
}
?>
miles at dinewilmingtononline dot com
12-Jul-2005 06:29
Here is a slight modification to the function posted below that vegard posted that allows for left, right or center alignment within the text boxes.
$halign has a default of left. center, and right can also be put in.
<?php
function printWordWrapped(&$image, $top, $left, $maxWidth, $font, $color, $text, $textSize, $halign="left") {
$words = explode(' ', strip_tags($text)); $line = '';
while (count($words) > 0) {
$dimensions = imagettfbbox($textSize, 0, $font, $line.' '.$words[0]);
$lineWidth = $dimensions[2] - $dimensions[0]; if ($lineWidth > $maxWidth) { $lines[] = $line; $line = ''; }
$line .= ' '.$words[0]; $words = array_slice($words, 1); }
if ($line != '') { $lines[] = $line; } $lineHeight = $dimensions[1] - $dimensions[7]; $height = count($lines) * $lineHeight; $i = 0;
foreach ($lines as $line) {
if($halign=="center") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[2] - $dimensions[0];
$center=floor($maxWidth/2 + $left);
$leftStart=$center-$lineWidth/2;
} else if ($halign=="right") {
$dimensions = imagettfbbox($textSize, 0, $font, $line);
$lineWidth = $dimensions[2] - $dimensions[0];
$leftStart=$left+$maxWidth-$lineWidth;
} else {
$leftStart=$left;
}
imagettftext($image, $textSize, 0, $leftStart, $top + $lineHeight * $i, $color, $font, $line);
$i++;
}
return $height;
}
?>
info at rainer-schuetze dot de
10-Jun-2005 09:32
according function by jtopland at hive dot no
08-Feb-2004 03:26
soukhinov at mail dot ru was right, the function doesn't work with 180. By the way it was a intresting way to trasform the angle to radian. Change the calculation of the angle to the following: $angle = $angle/ 180 * pi();
The function to calc. the points is correct. Sorry to say this, but the cal. of the height and width is incorrect. I used the version from LB (11-Feb-2004 08:55)
/**
* return width and height, offset [left, top] of a ttf character
* @param string $font : the font file
* @param string $text : the character
* @param int $size : the font size
* @param int $angle : the angle
* @access private
* @return array of the width and height, left and top.
**/
function _getCharacterSize($font, $text, $size, $angle)
{
// Get the boundingbox from imagettfbbox(), which is correct when angle is 0
$bbox = imagettfbbox($size, 0, $font, $text);
// Rotate the boundingbox
$angle = $angle/ 180 * pi();
for ($i=0; $i<4; $i++)
{
$x = $bbox[$i * 2];
$y = $bbox[$i * 2 + 1];
$bbox[$i * 2] = cos($angle) * $x - sin($angle) * $y; // X
$bbox[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y; // Y
}
// Variables which tells the correct width and height
$bbox["left"] = 0- min($bbox[0],$bbox[2],$bbox[4],$bbox[6]);
$bbox["top"] = 0- min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
$bbox["width"] = max($bbox[0],$bbox[2],$bbox[4],$bbox[6]) - min($bbox[0],$bbox[2],$bbox[4],$bbox[6]);
$bbox["height"] = max($bbox[1],$bbox[3],$bbox[5],$bbox[7]) - min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
return $bbox;
}
php@da dot mcbf dot net
30-Apr-2005 07:37
Pretty trivial, but still might save someone some trouble: on my system (Debian Linux), the absolute path to the font file had to be specified. I tried it relative to the current webpage and that did not work.
vegard at I dot DONT dot WANT dot SPAM dot programmer dot no
04-Apr-2005 06:37
Here is a function that wordwraps text you want to print, allows to specify where the text should be printed, what the maximum width should be, and returns the height used.
<?php
function printWordWrapped(&$image, $top, $left, $maxWidth, $font, $color, $text, $textSize) {
$words = explode(' ', strip_tags($text)); $line = '';
while (count($words) > 0) {
$dimensions = imagettfbbox($textSize, 0, $font, $line.' '.$words[0]);
$lineWidth = $dimensions[2] - $dimensions[0]; if ($lineWidth > $maxWidth) { $lines[] = $line; $line = ''; }
$line .= ' '.$words[0]; $words = array_slice($words, 1); }
if ($line != '') { $lines[] = $line; } $lineHeight = $dimensions[1] - $dimensions[7]; $height = count($lines) * $lineHeight; $i = 0;
foreach ($lines as $line) {
imagettftext($image, $textSize, 0, $left, $top + $lineHeight * $i, $color, $font, $line);
$i++;
}
return $height;
}
?>
ryan at retronetworks dot com
28-Mar-2005 07:46
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++) {
$char[$i] = substr($text, $i, 1);
imagettftext($im, $size, $angle, ($x + $w + ($i * $t)), $y, $color, $font, $char[$i]);
$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).
soukhinov at mail dot ru
15-Mar-2005 04:00
I have tryed all of fixes
The David Eder's fix is the only working fix.
The "jtopland at hive dot no"s fix is good enough, but it not working with angle = 180 degrees.
webmaster at funfragforce dot de
10-Mar-2005 06:50
Here a little code snippet to align the text to horizontally center:
<?php
$insert = imagecreatefromgif("test.gif");
$text="TEST";
$font="arial.ttf";
$col=ImageColorAllocate ($insert, 0, 0, 0);
$bbox=imagettfbbox (12, 0, $font, $text);
$xcorr=0-$bbox[6];
$mase=$bbox[2]+$xcorr;
$width=imagesx($insert);
$new=($width-$mase)/2;
imagettftext ($insert, 12, 0, $new, 50, $col, $font, $text);
imagegif($insert,"",100);
?>
helloktk at naver dot com
24-Jun-2004 06:55
Here is a function which moves the center of text's bounding
box to a given pivot point (px,py) and rotates text about
that point.
<?php
$width=500;
$height=400;
$fontpath = 'c:/windows/fonts/arial.ttf';
$text = 'Finally, I have a roated text box';
$fontsize = 20;
$angle = 30.0;
$image = imagecreatetruecolor($width,$height);
imagefill($image, 0, 0, 0xDDDDDD);
$bbox = imagettfbbox($fontsize, 0, $fontpath, $text);
$x0= $bbox[6];
$y0=-$bbox[7];
$bbox[5]=-$bbox[5]+$bbox[1];
$bbox[7]=-$bbox[7]+$bbox[3];
$bbox[1]=0;
$bbox[3]=0;
$sx=imagesx($image);
$sy=imagesy($image);
$xc=($bbox[0]+$bbox[2])/2.0;
$yc=($bbox[1]+$bbox[7])/2.0;
$rad=$angle*pi()/180.0;
$sa=sin($rad);
$ca=cos($rad);
$x1=$x0-$xc;
$y1=$y0-$yc;
$px=$sx/2.0;
$py=$sy/2.0;
$x2= intval( $x1*$ca+$y1*$sa+$px+0.5);
$y2= intval(-$x1*$sa+$y1*$ca+$py+0.5);
imagettftext($image,$fontsize,$angle,$x2,$y2,0xFF,$fontpath,$text);
rotbbox($bbox,$angle,$px,$py);
for($i=0;$i<4;$i++){
$x0=$bbox[2*$i+0];
$y0=$bbox[2*$i+1];
$j=$i+1;
if($j==4) $j=0;
$x1=$bbox[2*$j+0];
$y1=$bbox[2*$j+1];
imageline($image,$x0,$y0,$x1,$y1,0xFF0000);
}
imagepng($image);
function rotbbox(&$bbox,$angle,$px,$py){
$xc=($bbox[0]+$bbox[2])/2.0;
$yc=($bbox[1]+$bbox[7])/2.0;
$rad=$angle*pi()/180.0;
$sa=sin($rad);
$ca=cos($rad);
for ($i=0;$i<4;$i++){
$x=$bbox[$i*2+0]-$xc;
$y=$bbox[$i*2+1]-$yc;
$bbox[$i*2+0]= intval( $ca*$x+$sa*$y+$px+0.5);
$bbox[$i*2+1]= intval(-$sa*$x+$ca*$y+$py+0.5);
}
}
?>
jrisken at mn dot rr dot com
09-Mar-2004 02:12
I took Magicaltux's word wrap procedure and modified it in two ways. I changed the order of processing so that the string plotting function is called only once for each word instead of for every character. And I wrote the results to a string scalar instead of a string array, with embedded breaks <br> at line ends. It should run pretty fast. Mine breaks only on spaces, but hyphens could easily be added.
I'm new to PHP so I apologize for my idiosyncratic formatting conventions.
<?
function myWordWrap($txt,$font,$size,$width)
{
$txt.=" "; $spaces=array();
$wids=array();
$i=0;
while(true)
{
$j=strpos(substr($txt,$i)," ");
if(!($j===false))
{
$spaces[]=$j+$i;
$bbox=imagettfbbox($size,0,$font,substr($txt,$i,$j+1));
$left=($bbox[0]>$bbox[6])?$bbox[6]:$bbox[0];
$right=($bbox[2]>$bbox[4])?$bbox[2]:$bbox[4];
$wids[]=$right-$left;
$i=$j+$i+1;
}
else break;
}
$lastspace=-1;
$cum=0;
$t2="";
for($i=0;$i<count($spaces);$i++)
{
if((($cum>0)&&($cum+$wids[$i])>$width)) {
$t2.="<br>";
$cum=0;
$i--;
}
else
{
$t2.=substr($txt,$lastspace+1,$spaces[$i]-$lastspace);
$cum+=$wids[$i];
$lastspace=$spaces[$i];
}
}
return $t2;
}
?>
LB
11-Feb-2004 07:55
the oliver dot martin at onemail dot fixbbox function is just lacking a small thing:
the coordonates for top and left have to be the opposite, because the imagettftext x and y coordonates are calculated from the top left of the image and set the bottom left of the first character.
The correct function is:
function fixbbox($bbox)
{
$tmp_bbox["left"] = min($bbox[0],$bbox[2],$bbox[4],$bbox[6]);
$tmp_bbox["top"] = min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
$tmp_bbox["width"] = max($bbox[0],$bbox[2],$bbox[4],$bbox[6]) -
min($bbox[0],$bbox[2],$bbox[4],$bbox[6]) + 1;
$tmp_bbox["height"] = max($bbox[1],$bbox[3],$bbox[5],$bbox[7]) - min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
$tmp_bbox["left"] = 0 - $tmp_bbox["left"];
$tmp_bbox["top"] = 0 - $tmp_bbox["top"];
return $tmp_bbox;
}
And it works for any rotated text.
David Eder
10-Feb-2004 09:46
As "oliver dot martin at onemail dot at" noted above, imagettfbbox() does not work correctly in php 4.3.4. To remedy this, I've written a short function that uses trig to calculate the bounding box from rotating a non-rotated piece of text.
Hopefully, this comment will be obsolete soon, but for now, ...
function imagettfbbox_t($size, $angle, $fontfile, $text)
{
// compute size with a zero angle
$coords = imagettfbbox($size, 0, $fontfile, $text);
// convert angle to radians
$a = $angle * M_PI / 180;
// compute some usefull values
$ca = cos($a);
$sa = sin($a);
$ret = array();
// perform transformations
for($i = 0; $i < 7; $i += 2)
{
$ret[$i] = round($coords[$i] * $ca + $coords[$i+1] * $sa);
$ret[$i+1] = round($coords[$i+1] * $ca - $coords[$i] * $sa);
}
return $ret;
}
jtopland at hive dot no
08-Feb-2004 02:26
Finally managed to make a fixed version of imagettfbbox().
All angles returns correct values.
Except that imagettftext() returns different trackings (space between each character) when rotating.
<?php
$font = "d://www//tahoma.ttf";
$text = "Finally, I can center rotated text!";
$size = 20;
$angle = 20;
$image = imagecreatetruecolor(500, 400);
imagefill($image, 0, 0, hexdec("dddddd"));
imageline($image, 0, 0, imagesx($image), imagesy($image), hexdec("000000"));
imageline($image, imagesx($image), 0, 0, imagesy($image), hexdec("000000"));
$bbox = imagettfbbox_fixed($size, $angle, $font, $text);
imagettftext($image, $size, $angle, imagesx($image) / 2 - $bbox['width'] / 2, imagesy($image) / 2 + $bbox['height'] / 2, hexdec("0000ff"), $font, $text);
imagepng($image);
function imagettfbbox_fixed($size, $angle, $font, $text)
{
$bbox = imagettfbbox($size, 0, $font, $text);
$angle = pi() * 2 - $angle * pi() * 2 / 360;
for ($i=0; $i<4; $i++)
{
$x = $bbox[$i * 2];
$y = $bbox[$i * 2 + 1];
$bbox[$i * 2] = cos($angle) * $x - sin($angle) * $y;
$bbox[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y;
}
$bbox['width'] = $bbox[0] + $bbox[4];
$bbox['height'] = $bbox[1] - $bbox[5];
return $bbox;
}
?>
oliver dot martin at onemail dot at
09-Jan-2004 01:13
The original fixbox function by <php at deathz0rz dot homeunix dot net> doesn't work when the text is rotated, as it assumes that the upper left corner of the text is also the upper left corner of the bounding box. Same goes for the lower right corner. Here is my corrected version of it:
<?
function fixbbox($bbox)
{
$tmp_bbox["left"] = min($bbox[0],$bbox[2],$bbox[4],$bbox[6]);
$tmp_bbox["top"] = min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
$tmp_bbox["width"] = max($bbox[0],$bbox[2],$bbox[4],$bbox[6]) - min($bbox[0],$bbox[2],$bbox[4],$bbox[6]);
$tmp_bbox["height"] = max($bbox[1],$bbox[3],$bbox[5],$bbox[7]) - min($bbox[1],$bbox[3],$bbox[5],$bbox[7]);
return $tmp_bbox;
}
?>
However, be aware that this might not be very useful, as gd-2.0.8 introduces a bug which renders the results of imagettfbbox() useless when the text is rotated. This is still not fixed in the the php-4.3.4 bundled version (2.0.15 compatible).
MagicalTux at FF.ST
22-Dec-2003 12:09
One use of this function is to do some WordWrap =p
I wrote a little function to make a basic wordwrap : it returns an array with each line in a row.
You just have to display each row on a different line (calling many times imagettftext) to get a good result.
The character ^ is assumed as a linebreak.
<?php
function im_wordwrap($txt,$font,$size,$width) {
$sep=array(' ','-'); $res=array();
$buf='';
for($i=0;$i<strlen($txt);$i++) {
$l=$txt{$i};
if ($l=='^') {
$res[]=$buf;
$buf='';
continue;
}
$t=$buf.$l;
$bbox=imagettfbbox($size,0,$font,$t);
$left=($bbox[0]>$bbox[6])?$bbox[6]:$bbox[0]; $right=($bbox[2]>$bbox[4])?$bbox[2]:$bbox[4]; $w=$right-$left; if ($w>$width) {
if ($buf=='') return false; $fp=false;
foreach($sep as $s) {
$p=strrpos($buf,$s);
if (($p!==false) and ($p>$fp)) $fp=$p;
}
if ($fp===false) {
$res[]=$buf;
$buf='';
$i--; continue;
}
$res[]=substr($buf,0,$fp+1);
$buf=substr($buf,$fp+1);
$i--;
continue;
}
$buf.=$l;
}
if ($buf!='') $res[]=$buf;
return $res;
}
?>
php at deathz0rz dot homeunix dot net
14-Dec-2003 06:38
The array this function returns is very strange, at least, i think so... So i created this function that 'fixes' the bounding box array into some human-understandable format
<?php
function fixbbox($bbox)
{
$xcorr=0-$bbox[6]; $ycorr=0-$bbox[7]; $tmp_bbox['left']=$bbox[6]+$xcorr;
$tmp_bbox['top']=$bbox[7]+$ycorr;
$tmp_bbox['width']=$bbox[2]+$xcorr;
$tmp_bbox['height']=$bbox[3]+$ycorr;
return $tmp_bbox;
}
?>
Brian at NOSPAM at PrintsMadeEasy dot com
04-Sep-2002 01:12
There seems to be a little confusion regarding the font coordinate system. PHP's TTF functions will make more sense after you understand the principals of font creation. This guy wrote a really good overview...
http://pfaedit.sourceforge.net/overview.html
| |