GD and Image º¯Êý
ÔÚÏßÊֲ᣺ÖÐÎÄ Ó¢ÎÄ
PHPÊÖ²á

imagettftext

(PHP 4, PHP 5)

imagettftextÓà TrueType ×ÖÌåÏòͼÏñдÈëÎı¾

˵Ã÷

array imagettftext ( resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text )

image
ͼÏñ×ÊÔ´¡£¼û imagecreatetruecolor()¡£
size
×ÖÌå´óС¡£¸ù¾Ý GD °æ±¾²»Í¬£¬Ó¦¸ÃÒÔÏñËØ´óСָ¶¨£¨GD1£©»òµã´óС£¨GD2£©¡£
angle
½Ç¶ÈÖƱíʾµÄ½Ç¶È£¬0 ¶ÈΪ´Ó×óÏòÓÒ¶ÁµÄÎı¾¡£¸ü¸ßÊýÖµ±íʾÄæʱÕëÐýת¡£ÀýÈç 90 ¶È±íʾ´ÓÏÂÏòÉ϶ÁµÄÎı¾¡£
x
ÓÉ x£¬y Ëù±íʾµÄ×ø±ê¶¨ÒåÁ˵ÚÒ»¸ö×Ö·ûµÄ»ù±¾µã£¨´ó¸ÅÊÇ×Ö·ûµÄ×óϽǣ©¡£ÕâºÍ imagestring() ²»Í¬£¬Æä x£¬y ¶¨ÒåÁ˵ÚÒ»¸ö×Ö·ûµÄ×óÉϽǡ£ÀýÈç "top left" Ϊ 0, 0¡£
y
Y ×ø±ê¡£ËüÉ趨ÁË×ÖÌå»ùÏßµÄλÖ㬲»ÊÇ×Ö·ûµÄ×îµ×¶Ë¡£
color
ÑÕÉ«Ë÷Òý¡£Ê¹ÓøºµÄÑÕÉ«Ë÷ÒýÖµ¾ßÓйرշÀ¾â³ÝµÄЧ¹û¡£¼û imagecolorallocate()¡£
fontfile
ÊÇÏëҪʹÓÃµÄ TrueType ×ÖÌåµÄ·¾¶¡£ ¸ù¾Ý PHP ËùʹÓÃµÄ GD ¿âµÄ²»Í¬£¬µ± fontfile ûÓÐÒÔ / ¿ªÍ·Ê±Ôò .ttf ½«±»¼Óµ½ÎļþÃûÖ®ºó²¢ÇÒ»áÔڿⶨÒå×ÖÌå·¾¶Öг¢ÊÔËÑË÷¸ÃÎļþÃû¡£ µ±Ê¹ÓÃµÄ GD ¿â°æ±¾µÍÓÚ 2.0.18 ʱ£¬Ò»¸ö¿Õ¸ñ×Ö·û ¶ø²»ÊǷֺŽ«±»ÓÃÀ´×÷Ϊ²»Í¬×ÖÌåÎļþµÄ¡°Â·¾¶·Ö¸ô·û¡±¡£²»Ð¡ÐÄʹÓÃÁË´ËÌØÐÔ½«»áµ¼ÖÂÒ»Ìõ¾¯¸æÐÅÏ¢£ºWarning: Could not find/open font¡£¶ÔÊÜÓ°ÏìµÄ°æ±¾À´ËµÎ¨Ò»½â¾ö·½°¸¾ÍÊǽ«×ÖÌåÒƶ¯µ½²»°üº¬¿Õ¸ñµÄ·¾¶ÖÐÈ¥¡£

ºÜ¶àÇé¿öÏÂ×ÖÌ嶼·ÅÔڽű¾µÄͬһ¸öĿ¼Ï¡£ÏÂÃæµÄС¼¼ÇÉ¿ÉÒÔ¼õÇá°üº¬µÄÎÊÌâ¡£

<?php
// Set the enviroment variable for GD
putenv('GDFONTPATH=' realpath('.'));

// Name the font to be used (note the lack of the .ttf extension)
$font 'SomeFont';
?>

text
Îı¾×Ö·û´®¡£ ¿ÉÒÔ°üº¬Ê®½øÖÆÊý×Ö»¯×Ö·û±íʾ£¨ÐÎʽΪ£º&#8364;£©À´·ÃÎÊ×ÖÌåÖг¬¹ýλÖà 127 µÄ×Ö·û¡£UTF-8 ±àÂëµÄ×Ö·û´®¿ÉÒÔÖ±½Ó´«µÝ¡£ Èç¹û×Ö·û´®ÖÐʹÓõÄij¸ö×Ö·û²»±»×ÖÌåÖ§³Ö£¬Ò»¸ö¿ÕÐľØÐν«Ìæ»»¸Ã×Ö·û¡£

imagettftext() ·µ»ØÒ»¸öº¬ÓÐ 8 ¸öµ¥ÔªµÄÊý×é±íʾÁËÎı¾Íâ¿òµÄËĸö½Ç£¬Ë³ÐòΪ×øϽǣ¬ÓÒϽǣ¬ÓÒÉϽǣ¬×óÉϽǡ£ÕâЩµãÊÇÏà¶ÔÓÚÎı¾µÄ¶øºÍ½Ç¶ÈÎ޹أ¬Òò´Ë¡°×óÉϽǡ±Ö¸µÄÊÇÒÔˮƽ·½Ïò¿´ÎÄ×ÖʱÆä×óÉϽǡ£

Example #1 imagettftext() Àý×Ó

±¾ÀýÖеĽű¾½«Éú³ÉÒ»¸ö°×É«µÄ 400x30 ÏñËØ PNG ͼÏñ£¬ÆäÖÐÓкÚÉ«£¨´ø»ÒÉ«ÒõÓ°£©Arial ×ÖÌåдµÄ¡°Testing...¡±¡£

<?php
// Set the content-type
header("Content-type: image/png");

// Create the image
$im imagecreatetruecolor(40030);

// Create some colors
$white imagecolorallocate($im255255255);
$grey imagecolorallocate($im128128128);
$black imagecolorallocate($im000);
imagefilledrectangle($im0039929$white);

// The text to draw
$text 'Testing...';
// Replace path by your own font path
$font 'arial.ttf';

// Add some shadow to the text
imagettftext($im2001121$grey$font$text);

// Add the text
imagettftext($im2001020$black$font$text);

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
?>

±¾º¯ÊýͬʱÐèÒª GD ¿âºÍ » FreeType ¿â¡£

²Î¼û imagettfbbox()¡£

²ÎÊý

image

ÓÉͼÏó´´½¨º¯Êý(ÀýÈçimagecreatetruecolor())·µ»ØµÄͼÏó×ÊÔ´¡£

size

×ÖÌåµÄ³ß´ç. ¸ù¾ÝGDµÄ°æ±¾,ΪÏñËسߴç(GD1)»òµã(°õ)³ß´ç (GD2).

angle

The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.

x

The coordinates given by x and y will define the basepoint of the first character (roughly the lower-left corner of the character). This is different from the imagestring(), where x and y define the upper-left corner of the first character. For example, "top left" is 0, 0.

y

The y-ordinate. This sets the position of the fonts baseline, not the very bottom of the character.

color

The color index. Using the negative of a color index has the effect of turning off antialiasing. See imagecolorallocate().

fontfile

The path to the TrueType font you wish to use.

Depending on which version of the GD library PHP is using, when fontfile does not begin with a leading / then .ttf will be appended to the filename and the library will attempt to search for that filename along a library-defined font path.

When using versions of the GD library lower than 2.0.18, a space character, rather than a semicolon, was used as the 'path separator' for different font files. Unintentional use of this feature will result in the warning message: Warning: Could not find/open font. For these affected versions, the only solution is moving the font to a path which does not contain spaces.

In many cases where a font resides in the same directory as the script using it the following trick will alleviate any include problems.

<?php
// Set the enviroment variable for GD
putenv('GDFONTPATH=' realpath('.'));

// Name the font to be used (note the lack of the .ttf extension)
$font 'SomeFont';
?>

text

The text string in UTF-8 encoding.

May include decimal numeric character references (of the form: &#8364;) to access characters in a font beyond position 127. The hexadecimal format (like &#xA9;) is supported. Strings in UTF-8 encoding can be passed directly.

Named entities, such as &copy;, are not supported. Consider using html_entity_decode() to decode these named entities into UTF-8 strings (html_entity_decode() supports this as of PHP 5.0.0).

If a character is used in the string which is not supported by the font, a hollow rectangle will replace the character.

·µ»ØÖµ

Returns an array with 8 elements representing four points making the bounding box of the text. The order of the points is lower left, lower right, upper right, upper left. The points are relative to the text regardless of the angle, so "upper left" means in the top left-hand corner when you see the text horizontally. Returns FALSE on error.

¸üÐÂÈÕÖ¾

°æ±¾ ˵Ã÷
5.2.0 It is now possible to specify an hexadecimal entity in text.

·¶Àý

Example #2 imagettftext() example

This example script will produce a white PNG 400x30 pixels, with the words "Testing..." in black (with grey shadow), in the font Arial.

<?php
// Set the content-type
header('Content-Type: image/png');

// Create the image
$im imagecreatetruecolor(40030);

// Create some colors
$white imagecolorallocate($im255255255);
$grey imagecolorallocate($im128128128);
$black imagecolorallocate($im000);
imagefilledrectangle($im0039929$white);

// The text to draw
$text 'Testing...';
// Replace path by your own font path
$font 'arial.ttf';

// Add some shadow to the text
imagettftext($im2001121$grey$font$text);

// Add the text
imagettftext($im2001020$black$font$text);

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
?>

ÒÔÉÏÀý³ÌµÄÊä³öÀàËÆÓÚ£º

Output of example : imagettftext()

×¢ÊÍ

Note:

This function requires both the GD library and the » FreeType library.

²Î¼û


GD and Image º¯Êý
ÔÚÏßÊֲ᣺ÖÐÎÄ Ó¢ÎÄ
PHPÊÖ²á
PHPÊÖ²á - N: Óà TrueType ×ÖÌåÏòͼÏñдÈëÎı¾

Óû§ÆÀÂÛ:

john at jbwalker dot com (24-Jan-2012 04:37)

This function can be tricky. To begin with the example that omits the ".ttf" from the name of the font is incorrect. I've found that I have to include it (perhaps different in Windows?).

I have also found that odd things happen if you happen to pick a font size that doesn't match one of the known fonts.

See my comment under imagecolortransparent for trying to use a transparent background with text.

mirza_aqueel_qau at hotmail dot com (26-Jul-2011 12:49)

To make a font underline and bold without using the fonts file available in fonts directory of windows use this code. I hope this will help alot of you out there.

<?php
// Create the image
$im = imagecreatetruecolor(499, 330);

// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, 499, 329, $white);

// The text to draw

$text ="Muhammad Sarfraz";
$text ="Khurram Faraz";
$text ="Mohammad Imran";
$text ="Zulfiqar Ahmed Khan";
$text="Najam ul Hasnain Shah";
$text="Abdul Rehman Daniyal";
$text="Yasir Siddiqui";
$text="Sohail ur Rehman";
$text="Hamad Aziz Sheikh";
$text="Nauman Khalid";
$text="Saad Ahmed";
$text="Nasir Mehmood Butt";
$text="Mohammad Aqeel Mirza";

// Replace path by your own font path
$font = 'walt.ttf'; // Place this file in your code directory or if font is in font directory set its path with font name as $font=$path.'arial.ttf';

// Add the text
$x=10;
$y=120;
$font_size=40;
$angle=0;
$total_width=0;
$counter=0;

for(
$i=0; $i<strlen($text); $i++)
{
   
//$text_to_write=urldecode(substr($text,$i,1)."%0D_");
   
$dimensions = imagettfbbox($font_size, $angle, $font, substr($text,$i,1));
   
$total_width+=($dimensions[2]);
   
   
   
}
echo
"<pre>";
$dimensions = imagettfbbox($font_size, $angle, $font, $text);
echo
"Dimension of full string=".$dimensions[2]."<br/>";

echo
"Total width calcuated by algorithm=".$total_width."<br/>";
$difference=$dimensions[2]-$total_width;

echo
"Difference=".$difference;
imagettftext($im, $font_size, $angle, $x+1, $y+1, $black, $font, $text);
imagettftext($im, $font_size, $angle, $x, $y, $black, $font, $text);

$x2=$x+$total_width+$difference+2;
//echo $total_width;
echo "<pre/>";
//imageline( $im , $x , $y+4 , $x2 , $y+4 , $black );
imageBoldLine($im, $x, $y+4, $x2, $y+4, $black, $BoldNess=4, $func='imageLine');

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im,"underline.png");
echo
"<img src='underline.png'/>";
imagedestroy($im);
?>

Anonymous (02-Jun-2011 09:40)

If you need to render text to an exact sized image that then you will run into problems depending on the font you use.

Use the code below to render text to an image that is exactly sized to fit.

This code will also take into consideration the baseline. You can safely render seperate pieces of text and place them side by side without annoying pixel discrepencies.

<?php
   
   
//vars
   
$font = 'QuatroUltraBlack.ttf';
   
$text = 'hello world!';
   
$size = 40;//pt
   
$color = '#ffffff';
   
   
//over compensate dimensions!
   
$cropPadding = 6;
   
$fontRange = 'xgypqXi';
   
$bounds = imagettfbbox($size,0,$font,$fontRange);
   
$height = abs($bounds[1]-$bounds[5])+$cropPadding;
   
$y = abs($bounds[7])-1;
   
$bounds = imagettfbbox($size,0,$font,$text);
   
$width = abs($bounds[0]-$bounds[2])+$cropPadding+$cropPadding;
   
$x = ($bounds[0] * -1)+$cropPadding;
   
   
//create transparent image
   
$image = imagecreatetruecolor($width,$height);
   
imagesavealpha($image, true);
   
imagealphablending($image, false);
   
$background = imagecolorallocatealpha($image, 255, 255, 255, 127);
   
imagefilledrectangle($image, 0, 0, $width, $height, $background);
   
imagealphablending($image, true);
   
   
//make color
   
$rgb = str_split(ltrim($color,'#'),2);
   
$color = imagecolorallocatealpha($image,hexdec($rgb[0]),hexdec($rgb[1]),hexdec($rgb[2]),0);
   
   
//render text to image
   
imagettftext($image,$size,0,$x,$y,$color,$font,$text.'     '.$fontRange);
   
   
//calculate crop
   
$trim_bottom = 0;
   
$trim_left = 0;
   
$trim_right = 0;
   
   
//bottom
   
for($trim_y = $height-1;$trim_y >= 0; $trim_y--) {
        for(
$trim_x = 0; $trim_x < $width; $trim_x++) {
           
$alpha = (imagecolorat($image, $trim_x, $trim_y) >> 24) & 0xFF;
            if(
$alpha != 127) { break 2; }
        }
       
$trim_bottom++;
    }
       
   
//left
   
for($trim_x = 0;$trim_x < $width; $trim_x++) {
        for(
$trim_y = 0; $trim_y < $height; $trim_y++) {
           
$alpha = (imagecolorat($image, $trim_x, $trim_y) >> 24) & 0xFF;
            if(
$alpha != 127) { break 2; }
        }
       
$trim_left++;
    }
   
   
//right
   
for($trim_x = $width-1;$trim_x >= 0; $trim_x--) {
        for(
$trim_y = 0; $trim_y < $height; $trim_y++) {
           
$alpha = (imagecolorat($image, $trim_x, $trim_y) >> 24) & 0xFF;
            if(
$alpha != 127) { break 2; }
        }
       
$trim_right++;
    }
   
   
//do crop
   
if ($trim_left || $trim_right || $trim_bottom) {
       
//create new image
       
$newWidth = $width-$trim_left-$trim_right;
       
$newHeight = $height-$trim_bottom;
       
$newImage = imagecreatetruecolor($newWidth,$newHeight);
       
imagesavealpha($newImage,true);
       
imagealphablending($newImage, false);
       
$background = imagecolorallocatealpha($newImage,255,255,255,127);
       
imagefilledrectangle($newImage,0,0,$newWidth,$newHeight,$background);
       
imagealphablending($newImage,true);
       
imagecopyresampled($newImage,$image,$trim_left,0,0,0,$imageWidth,$imageHeight,$imageWidth,$imageHeight);
       
       
//swap the new image
       
imagedestroy($image);
       
$image = $newImage;
    }
   
   
//do something with image
   
imagepng($image);
   
   
//free image
   
imagedestroy($image);
   
?>

contact at pointhunter dot net (28-Nov-2010 06:35)

Print username on the picture from a sent variable. (u)

<?php
$USERNAME
=$_REQUEST['u'];
// Set the content-type
header('Content-type: image/png');

// Create the image
$im = imagecreatetruecolor(350, 30);

// Create some colors
$white = imagecolorallocate($im, 0, 0, 0);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 255, 255, 255);
imagefilledrectangle($im, 0, 0, 399, 29, $white);

// The text to draw
$text = 'Welcome, '.$USERNAME;
// Replace path by your own font path
$font = 'cour.ttf';

// Add some shadow to the text
imagettftext($im, 20, 0, 11, 21, $grey, $font, $text);

// Add the text
imagettftext($im, 20, 0, 10, 20, $black, $font, $text);

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
?>

John Conde (01-Nov-2010 06:17)

If you want to create a paragraph you will need to break your text up into lines and then place each line individually one below the next.

Here's a basic example of how to do that:

<?php
// Basic font settings
$font ='./times.ttf';
$font_size = 15;
$font_color 0x000000

// Text to be placed as a paragraph
$text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer non nunc lectus. Curabitur hendrerit bibendum enim dignissim tempus. Suspendisse non ipsum auctor metus consectetur eleifend. Fusce cursus ullamcorper sem nec ultricies. Aliquam erat volutpat. Vivamus massa justo, pharetra et sodales quis, rhoncus in ligula. Integer dolor velit, ultrices in iaculis nec, viverra ut nunc.';

// Break it up into pieces 125 characters long
$lines = explode('|', wordwrap($text, 115, '|'));

// Starting Y position
$y = 513;

// Loop through the lines and place them on the image
foreach ($lines as $line)
{
   
imagettftext($image, $font_size, 0, 50, $y, $font_color, $font, $line);

   
// Increment Y so the next line is below the previous line
   
$y += 23;
}

?>

eboyjr (30-Sep-2010 09:12)

You may want to be able to extract the name of the font with the font file. If so you can use this class I've developed. It only works with TTF fonts, not OpenType fonts. It has worked with all fonts that I have tested so far. Not extensively tested. There may be some character set issues but that is up to someone else to fix :) And sorry I had to strip a lot of the comments so that I could post it.

<?php
/**
 * TTFReader
 * Gives you name information of TTF font files.
 * Thanks to Apple, for their TTF specification.
 *
 * @name TTFReader
 * @author Devin Samarin <eboyjr14@gmail.com>
 */
class TTFReader {

    private
$handle;
    private
$is_parsed = false;

    private
$info = false;

    private
$name_ids = array(
       
0 => "copyright",
       
1 => "font_family",
       
2 => "font_subfamily",
       
3 => "unique_id",
       
4 => "full_name",
       
5 => "version",
       
6 => "postscript_name",
       
7 => "trademark",
       
8 => "manufacturer",
       
9 => "designer",
       
10 => "description",
       
11 => "vendor_url",
       
12 => "designer_url",
       
13 => "license",
       
14 => "license_url",
       
16 => "preferred_family",
       
17 => "preferred_subfamily",
       
18 => "compatible_full",
       
19 => "sample_text"
   
);

    private function
translate_name_id($id) {
        if( isset(
$this->name_ids[$id]) ) return $this->name_ids[$id];
        return
$id;
    }

    public function
open($filename) {
       
$this->handle = fopen($filename, "r");
    }

    public function
close() {
        if( !
$this->handle ) return false;
       
fclose($this->handle);
    }

    public function
info() {
        if(
$this->is_parsed ) { return $this->info; }
       
$this->is_parsed = true;
        if( !
$this->handle ) return false;
       
$info = array();
       
$ttf_header = unpack(
           
"nmajor_version/" .
           
"nminor_version/" .
           
"nnumber_of_tables/" .
           
"nsearch_range/" .
           
"nentry_selector/" .
           
"nrange_shift", fread($this->handle, 12));
        if(
$ttf_header['major_version'] != 1 || $ttf_header['minor_version'] != 0 ) {
            return
false;
        }
       
$ttf_found = false;
        for(
$i = 0; $i < $ttf_header['number_of_tables']; $i++ ) {
           
$ttf_table_name = fread($this->handle, 4);
           
$ttf_table = unpack("Nchecksum/" .
               
"Noffset/" .
               
"Nlength", fread($this->handle, 12));
            if(
$ttf_table_name == 'name' ) {
               
$ttf_found = true;
                break;
            }
        }
        if(
$ttf_found ) {
           
fseek($this->handle, $ttf_table['offset']);
           
$ttf_table['header'] =
               
unpack("nformat_selector/" .
                   
"nname_records_count/" .
                   
"nstorage_offset", fread($this->handle, 6));
           
$ttf_name_records = array();
            for(
$i = 0; $i < $ttf_table['header']['name_records_count']; $i++ ) {
               
$ttf_record =
                   
unpack("nplatform_id/" .
                       
"nencoding_id/" .
                       
"nlanguage_id/" .
                       
"nname_id/" .
                       
"nlength/" .
                       
"noffset", fread($this->handle, 12));
                if(
$ttf_record['length'] <= 0 ) continue;
               
$ttf_record_offset = ftell($this->handle);
               
fseek($this->handle,
                   
$ttf_table['offset'] +
                   
$ttf_table['header']['storage_offset'] +
                   
$ttf_record['offset']);
               
$ttf_value = fread($this->handle, $ttf_record['length']);
                if(
$ttf_record['platform_id'] != 1 ) $ttf_value = @iconv('UTF-16be', 'UTF-8//TRANSLIT', $ttf_value);
               
$info[$this->translate_name_id($ttf_record['name_id'])] = $ttf_value;
               
fseek($this->handle, $ttf_record_offset);
            }
        } else {
            return
false;
        }
        return
$this->info = $info;
    }
}
?>

Here an example with Arial, since that's everyone's favorite font:
<?php
$ttf
= new TTFReader();
$ttf->open("arial.ttf");
$info = $ttf->info();
print_r($info); // $info["full_name"] will give you the name of the font, but check if it is set first!
$ttf->close();
?>

eee ess c p 9 9 AT yahoo DOT com (29-Sep-2010 11:46)

If you get letters cut off (clipped) by adjacent letters when using imagettftext with transparency (i.e., imagealphablending set to false), try setting imagealphablending back to TRUE before calling the imagettftext function.

<?php
$im
= imagecreatetruecolor(300, 300);

imagealphablending($im, false);
imagesavealpha($im, true);

// Create colors and draw transparent background
$trans = imagecolorallocatealpha($im, 255, 255, 255, 127);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, 299, 299, $trans);

// Bad text
imagettftext($im, 22, 0, 50, 100, $black, 'arial.ttf', 'Bad: Oj Pj wj');

// Good text
imagealphablending($im, true);
imagettftext($im, 22, 0, 50, 150, $black, 'arial.ttf', 'Good: Oj Pj wj');

/*** You'll need a copy of the arial.ttf font file in the same location as the PHP script ***/

// Output PNG
header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
?>

barnaby at waterpigs dot co dot uk (03-Aug-2010 12:46)

Just created a HTML5 Video Poster Image generator in PHP - code is below if anyone wants to use.  It's heavily commented, so you should be able to adjust it easily.  It puts a transparent black bar along the top of an image, and writes some text in white over it - easily readable and applicable to most images.

<?php

// PHP File used to quickly put some text over a poster image - for video or other.

// To use:  Use this file as the source file of an image.  Pass it two GET variables:  pat=path of image&text=text to overlay

header("Content-Type: image/jpeg");

// Open the image:

$image = imagecreatefromjpeg($_SERVER['DOCUMENT_ROOT'] . $_GET['path']);

$width = imagesx($image); // Gets the width - better to use imagesx here as we don't need to feed it a path, just a handle.

$rectCol = imagecolorallocatealpha($image, 0, 0, 0, 40); // Create a black colour, slightly transparent
$textCol = imagecolorallocate($image, 255, 255, 255); // Create a white colour

// Fill the top of the image with this rectangle...

imagefilledrectangle($image, 0, 0, $width, 50, $rectCol);

$textX = 10;
$textY = 32; // X and Y values for the text generation

$font = $_SERVER['DOCUMENT_ROOT'] . '/site/fonts/Verdana.ttf'; // Replace this with the path to your font file.

// Write Text:

imagettftext($image, 18, 0, $textX, $textY, $textCol, $font, $_GET['text']);

// Now we're done editing... output the final image:

imagejpeg($image);

// Free up some space:

imagedestroy($image);

?>

Endeer (12-Jun-2010 12:22)

If latin characters with accents don't work for you (blank characters or rectangles), then it may be perhaps caused by PHP being compiled with --enable-gd-jis-conv. Verified on PHP 5.2.13.

Amir (07-May-2010 02:09)

In order to pass text of RTL language to imagettftext function, I used this function.

<?php
   
function revUni($text) {
   
       
$wordsArray = explode(" ", $text);

       
$rtlCompleteText='';
        for (
$i = sizeOf($wordsArray); $i > -1; $i = $i-1) {

           
//$lettersArray = explode("|", str_replace(";|", ";", $wordsArray[$i]));
           
$lettersArray = explode(";", $wordsArray[$i]);
           
           
$rtlWord='';
            for (
$k = sizeOf($lettersArray); $k > -1; $k = $k-1) {
                if (
strlen($lettersArray[$k]) > 1) { // make sure its full unicode letter
                   
$rtlWord = $rtlWord."".$lettersArray[$k].";";
                }
            }
           
           
$rtlCompleteText = $rtlCompleteText." ".$rtlWord;
           
        }
       
        return
$rtlCompleteText;
    }
?>

mail at miikku dot de (22-Mar-2010 03:43)

Because the text generated this way is not the same quality in all resolutions, i thought about a method to make it best quality without high resolution. So i wrote this simple code wich should do something like multisampling... Here it is (the $iMultiSampling parameter is the quality - multiplicator of multisampling):
<?php
function imagettftextmultisampled(&$hImg, $iSize, $sAngle, $iX, $iY, $cColor, $sFont, $sText, $iMultiSampling){
 
$iWidth  = imagesx($hImg);
 
$iHeight = imagesy($hImg);
 
$hImgCpy = imagecreatetruecolor(ceil($iWidth*$iMultiSampling), ceil($iHeight*$iMultiSampling));
 
$cColor  = imagecolorsforindex($hImg, $cColor);
 
$cColor  = imagecolorallocatealpha($hImgCpy, $cColor['red'], $cColor['green'], $cColor['blue'], $cColor['alpha']);
 
imagesavealpha($hImgCpy, true);
 
imagealphablending($hImgCpy, false);
 
$cTransparent = imagecolortransparent($hImgCpy, imagecolorallocatealpha($hImgCpy, 0, 0, 0, 127));
 
imagefill($hImgCpy, 0, 0, $cTransparent);
 
$aBox = imagettftext($hImgCpy, $iSize*$iMultiSampling, $sAngle, ceil($iX*$iMultiSampling), ceil($iY*$iMultiSampling), $cColor, $sFont, $sText);
 
imagecopyresampled($hImg, $hImgCpy, 0, 0, 0, 0, $iWidth, $iHeight, ceil($iWidth*$iMultiSampling), ceil($iHeight*$iMultiSampling));
 
imagedestroy($hImgCpy);
 foreach(
$aBox as $iKey => $iCoordinate)
 
$aBox[$iKey] = $iCoordinate/$iMultiSampling;
 return(
$aBox);
}

function
imagettfbboxmultisampled($iSize, $iAngle, $sFont, $sText, $iMultiSampling){
 
$aBox = imagettfbbox($iSize*$iMultiSampling, $iAngle, $sFont, $sText);
 foreach(
$aBox as $iKey => $iCoordinate)
 
$aBox[$iKey] = $iCoordinate/$iMultiSampling;
 return(
$aBox);
}
?>

JohnB (01-Mar-2010 07:58)

Just in case you were--like me--unaware of this, in Windows, ttf fonts don't necessarily antialias at all font sizes. Arial appears to work at all sizes but Calibri, for example, only antialiases at a point size of 8 and then at all sizes 16 and up. Not only that but at fonts sizes like 10 and 12 characters don't print at the expected angle: the characters are all printed upright on an angled baseline.

adam at worldwrestlingmania dot cjb dot net (06-Dec-2009 04:35)

Here's a good number verification captcha i just made:

1. on the page/s it will be used on, enter:
<?php
$pageToGo
= "http://example.com/" #the page to go to if captcha correct
if ($_POST["captchaused"] == "true")
{
if (
$_POST["numcaptcha"] == $_POST["captcha"])
{
header('Location: ' . $pageToGo);
}
else
{
echo
'<form action="' . $_SERVER['php_self'] . '" method="post">';
$text = mt_rand();
echo
'<input type="hidden" name="captchaused" value="true" />';
echo
'<input type="hidden" name="numcaptcha" value="' . $text . '" />';
echo
'Enter the numbers you see: <br><input type="text" name="captcha" />';
require_once(
'numcaptcha.php');
echo
'<input type="submit" value="enter site" /></form>';
}
?>

2. create a page called numcaptcha.php and enter:
<?php
header
('Content-type: image/png');
$im = imagecreatetruecolor(400, 30);
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, 399, 29, $white);
imagettftext($im, 20, 0, 11, 21, $grey, $font, $text);
imagettftext($im, 20, 0, 10, 20, $black, $font, $text);
imagepng($im);
imagedestroy($im);
?>

it might have a few security issues but it still works fine.

web at evanreeves dot com (22-May-2009 08:50)

I was having trouble trying to render non antialiased text using a pixel font. The tips about setting a negative value for the color are valid, but I was still having trouble with the text I was trying to render because it was black. I discovered that if I changed the imagecolorallocate() function from:

$color = imagecolorallocate($base, 0, 0, 0);

to

$color = imagecolorallocate($base, 1, 1, 1); (near black)

and then used the negative value for the color in imagettftext(), it would work properly. The difference is that my first implementation set $color = 0. Obviously, you can't have $color = -0, it made no difference. When I switched to (1,1,1) it became $color = 1 which I could take a negative value for.

nadavkav at gmail dot com (21-May-2009 01:32)

for passing hebrew (and maybe other rtl language text) you can use the following code (as suggested by udi and which worked for me) :
<?php
$returnedtext
= iconv("ISO-8859-8", "UTF-8", hebrev(iconv("UTF-8", "ISO-8859-8", $originaltext)));
?>

philip at webdesco dot com (29-Apr-2009 01:51)

Hi,
for the dummies (like myself) if you are having problems including your font file, prefix the file name with ./

On my development server the following worked fine
$myfont = "coolfont.ttf";

on my hosting server the only way i could get the font to work was as follows
$myfont = "./coolfont.ttf";

hope this helps someone out!

ben at spooty dot net (11-Mar-2009 02:40)

Here's a simple function to wrap text going into an image. It'll wrap onto as many lines as it needs to, but $angle has to be zero. The $width parameter is the width of the image.

<?php
function wrap($fontSize, $angle, $fontFace, $string, $width){
   
   
$ret = "";
   
   
$arr = explode(' ', $string);
   
    foreach (
$arr as $word ){
   
       
$teststring = $ret.' '.$word;
       
$testbox = imagettfbbox($fontSize, $angle, $fontFace, $teststring);
        if (
$testbox[2] > $width ){
           
$ret.=($ret==""?"":"\n").$word;
        } else {
           
$ret.=($ret==""?"":' ').$word;
        }
    }
   
    return
$ret;
}
?>

roland dot hentschel at t-online dot de (21-Nov-2008 11:53)

Hi!

I played around with that multi-line-script "makeImageF".
Added some features, mainly: you can read text-files
or add text as parameter - eg :
imagettftext.php?file=test.txt
imagettftext.php?text=hello|world!

have fun!

======================================

<?php

/*
 * @name: makeImageF
 * http://de3.php.net/manual/en/function.imagettftext.php#77739
 *
 * @param String $file : Textfile.
 * @param String $text : Text (New Line : "|").
 * @param String $font : Font name.
 * @param int $fsize: Font size.
 * @param int $pos : Justify (0-Left, 1-Right, 2-Center).
 * @param int $Leading : Space between lines.
 * @param int $W: Width of the Image.
 * @param int $H: Hight of the Image.
 * @param int $X: x-coordinate of the text into the image.
 * @param int $Y: y-coordinate of the text into the image.
 * @param array $rgb: RGB color array for text & background color.
 *
 */

$type = $_REQUEST['type']  ? $_REQUEST['type'] : "png";
switch(
$type) {
 case
"gif" :
   
header("Content-type: image/gif");
   
imageGIF(imagettfpostext($text, $font,
   
$fsize, $pos, $rgb),"wm.gif", 9); break;
 case
"png" :
   
header("Content-type: image/png");
   
imagePNG(imagettfpostext($text, $font,
   
$fsize, $pos, $rgb),"wm.png", 9); break;
}


function
rgb2hex($rgb) {
 
$color = array("black"=>"#000", "grn"=>"#090",
 
"red"=>"#f00", "blu"=>"00f");
 
$trans = array("a"=>"10", "b"=>"11", "c"=>"12",
 
"d"=>"13", "e"=>"14", "f"=>"15");
 
$hex = array();
 
$rgb = str_replace("#","",
   
str_replace(array_keys($color), array_values($color), strtolower($rgb)));
  for (
$x=0; $x<strlen($rgb); $x++)
 
$hex[] = strtr($rgb[$x],$trans);
  if (
count($hex)==3) {
   
$hex[5] = $hex[2]; $hex[4] = $hex[2];
   
$hex[3] = $hex[1]; $hex[2] = $hex[1];
   
$hex[1] = $hex[0];
  };
 
$hex = ($hex[0]*16+$hex[1])
  .
"x".($hex[2]*16+$hex[3])
  .
"x".($hex[4]*16+$hex[5]);
  return
$hex;
}

$file  = $_GET['file'
?
$_GET['file'] : "logo.txt";
if (
$_GET['file']) {
 
$fp = @fopen($file, "r"); 
  while (!
feof($fp)) $text .= fgets($fp);  fclose($fp);
} else
$text = str_replace("|","\n",$_GET['text']);
$pos   = $_GET['pos']  
?
$_GET['pos'] : 0;
$font  = $_GET['font'
?
"./fonts/".$_GET['font'].".ttf" : "./fonts/verdana.ttf";
$fsize = $_GET['fsize']
?
$_GET['fsize'] : 12;
$rgb   = $_GET['rgb']  
?
$_GET['rgb'] : "#ff9,#393";

imagepng(imagettfpostext($text, $font, $fsize, $pos, $rgb));

function
imagettfpostext($text, $font, $fsize, $pos, $rgb,
   
$Leading=0, $W=0, $H=0, $X=0, $Y=0) {
 
$angle = 0;
 
$_bx = imageTTFBbox($fsize,0,$font,$text);
 
$str = split("[\n]+",$text);
 
$nL  = count($str);
 
$W   = ($W==0)
  ?
abs($_bx[2]-$_bx[0])
  :
$W;
 
$H = ($H==0)
  ?
abs($_bx[5]-$_bx[3])+($nL>1
 
? ($nL*$Leading)
  :
0)
  :
$H;
 
$im = @imagecreate($W, $H)
  or die(
"Cannot Initialize new GD image stream");
 
$rgb = explode(",",$rgb);
 
$tc  = explode("x",rgb2hex($rgb[1]));
 
$bc=explode("x",rgb2hex($rgb[0]));
 
$bc  = imagecolorallocate($im, $bc[0], $bc[1], $bc[2]);
 
$tc  = imagecolorallocate($im, $tc[0], $tc[1], $tc[2]);
  if (
$pos == 0) {
   
imagettftext($im, $fsize, $angle, $X,
   
$fsize, $tc, $font, $text);
  } else {
   
$alpha = range("a", "z");
   
$alpha = $alpha.strtoupper($alpha).range(0, 9);
   
$_b = imageTTFBbox($fsize, 0, $font, $alpha);
   
$_H = abs($_b[5]-$_b[3]);
   
$__H = 0;
    for (
$i=0; $i<$nL; $i++) {
     
$_b = imageTTFBbox($fsize, 0, $font, $str[$i]);
     
$_W = abs($_b[2]-$_b[0]);
      if (
$pos == 1) $_X = $W-$_W;    
      else
$_X = abs($W/2)-abs($_W/2);
     
$__H += $_H;
     
imagettftext($im, $fsize, $angle, $_X, $__H,
     
$tc, $font, $str[$i]);
     
$__H += $Leading;
    }
  }

  if (
$_REQUEST["trans"]) {
  
$bg_color = ImageColorAt($im,1,1);
  
ImageColorTransparent($im, $bg_color);
  }

  return
$im;
}

?>

cameron at prolifique dot com (03-Oct-2008 04:59)

"php at yvanrodrigues dot com" is right...this function is not reliable on extended characters. User beware.

In my case, it produced different results with OpenType vs. TrueType versions of the same font. (Converted my OT font to TT using FontForge as suggested. Strangely, the resulting TT font file was twice as big as the OT version and didn't look the same...heavier weight and slightly different spacing.) While the TT version was more accurate at displaying certain characters, neither was totally reliable, both yielding boxes in place of perfectly valid character glyphs that I could verify existed in the font. (Both fonts showed the same characters perfectly on an HTML page with UTF-8 charset.)

What's more, using this same function with the same font on our development vs. production server also produced different results: some chars worked on dev but not production. Stranger still, the font spacing and size were slightly different between the two. Font file is identical. Dev server is Linux, production server is Windows, but should that matter? Suspect it has more to do with differing versions of FreeType (2.1 vs. 1.9 respectively).

Anyway, careful with this function...best to stick within the rather small range of safe characters and avoid anything else.

php at yvanrodrigues dot com (05-Sep-2008 03:10)

After many hours of failure may I suggest:

This function will work on OpenType fonts with Postscript outlines, but from what I can tell, characters > ASCII 127 do not display correctly or at all, even if the text is correctly coded as UTF-8.

Converting the font to truetype or possibly OpenType with truetype outlines; or buying the font as such fixes the problem.

I used FontForge to open the otf and export as ttf and it works perfectly.

s.pynenburg _at_ gm ail dotcom (07-Aug-2008 03:31)

I had an image generator where the user could position where they wanted the text to begin - however it kept going off the side of an image. So I made this basic function: it measures if the inputted text and x-position will cause the string to go off the edge, and if so, it will fit as much as it can on the first line, then go down to the next one.
Limitations:
-It only performs this once (i.e. it won't split into three lines)
-I'm pretty sure it won't work with angled text.

<?PHP

function imagettftextwrap($im, $size, $angle, $x_pos, $y_pos, $color, $font, $instr)
{
   
$box = @imagettfbbox($size, 0, $font, $instr);
   
$width = abs($box[4] - $box[0]);
   
$height = abs($box[3] - $box[5]);
   
$overlap = (($x_pos + $width) - imagesx($im));
    if(
$overlap > 0) //if the text doesn't fit on the image
   
{
       
$chars = str_split($instr);
       
$str = "";
       
$pstr = "";
        for(
$m=0; $m < sizeof($chars); $m++)
        {
           
$bo = imagettfbbox($fsize1, 0, $font1, $str);
           
$wid = abs($bo[4] - $bo[0]);
            if((
$x_pos + $wid) < imagesx($im)) //add one char from the string as long as it's not overflowing
           
{
               
$pstr .= $chars[$m];
               
$bo2 = imagettfbbox($fsize1, 0, $font1, $pstr);
               
$wid2 = abs($bo2[4] - $bo2[0]);
                if((
$x_pos + $wid2) < imagesx($im))
                {
                   
$str .= $chars[$m];
                }   
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
       
$restof = "";
        for(
$l=$m; $l < sizeof($chars); $l++)
        {
           
$restof .= $chars[$l]; //add the rest of the string to a new line
       
}
       
imagettftext($im, $size, $angle, $x_pos, $y_pos, $color, $font, $str); // print out the smaller line
       
imagettftext($im, $size, $angle, 0, $y_pos + $height, $color, $font, $restof); //and the rest of it
   
}
    else
    {
       
imagettftext($im, $size, $angle, $x_pos, $y_pos, $color, $font, $instr); //otherwise just do normally
   
}

}

?>

sk89q (01-Aug-2008 09:03)

I updated my imagettftextbox function considerably. It fixes the problems of the older imagettftextbox code I uploaded a few months ago (that's now gone).

You can get it here:
http://sk89q.therisenrealm.com/2008/08/ttf-textbox-in-php/

It has both horizontal and vertical alignment, custom line spacing, borders, width, height, etc.

Stefan at colulus dot com (20-May-2008 06:40)

I worked out a script the 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);

?>

Valentijn de Pagter (16-May-2008 06:13)

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!

damititi at gmail dot com (22-Apr-2008 09:21)

First of all, thanks sk89q for the func! it was exactly I was looking for.

I made a change. Depending on the letter, the text were incorrect vertical aligned.
I replace the line:
                $line_height = $dimensions[1] - $dimensions[7];
for the following:
                $line_height = $size+4;

No matter if mama or jeje is written, the vertical position will be the same.

sk89q (14-Mar-2008 11:36)

Here is an update to my imagettftextwrapped function. I had posted the old version that cut off lines if it wordwrapped.

Here's a new version with the bug fixed, a list of arguments closer to imagettftext(), and partial angle support (the text is angled, but the left margins for each line are not adjusted for the angle).

It's a function I wrote a few years ago to do unjustified aligned text.

<?php
define
("ALIGN_LEFT", "left");
define("ALIGN_CENTER", "center");
define("ALIGN_RIGHT", "right");

function
imagettftextbox(&$image, $size, $angle, $left, $top, $color, $font, $text, $max_width)
{
       
$text_lines = explode("\n", $text); // Supports manual line breaks!
       
       
$lines = array();
       
$line_widths = array();
       
       
$largest_line_height = 0;
       
        foreach(
$text_lines as $block)
        {
           
$current_line = ''; // Reset current line
           
           
$words = explode(' ', $block); // Split the text into an array of single words
           
           
$first_word = TRUE;
           
           
$last_width = 0;
           
            for(
$i = 0; $i < count($words); $i++)
            {
               
$item = $words[$i];
               
$dimensions = imagettfbbox($size, $angle, $font, $current_line . ($first_word ? '' : ' ') . $item);
               
$line_width = $dimensions[2] - $dimensions[0];
               
$line_height = $dimensions[1] - $dimensions[7];
               
                if(
$line_height > $largest_line_height) $largest_line_height = $line_height;
               
                if(
$line_width > $max_width && !$first_word)
                {
                   
$lines[] = $current_line;
                   
                   
$line_widths[] = $last_width ? $last_width : $line_width;
                   
                   
/*if($i == count($words))
                    {
                        continue;
                    }*/
                   
                   
$current_line = $item;
                }
                else
                {
                   
$current_line .= ($first_word ? '' : ' ') . $item;
                }
               
                if(
$i == count($words) - 1)
                {
                   
$lines[] = $current_line;
                   
                   
$line_widths[] = $line_width;
                }
               
               
$last_width = $line_width;
                   
               
$first_word = FALSE;
            }
           
            if(
$current_line)
            {
               
$current_line = $item;
            }
        }
       
       
$i = 0;
        foreach(
$lines as $line)
        {
            if(
$align == ALIGN_CENTER)
            {
               
$left_offset = ($max_width - $line_widths[$i]) / 2;
            }
            elseif(
$align == ALIGN_RIGHT)
            {
               
$left_offset = ($max_width - $line_widths[$i]);
            }
           
imagettftext($image, $size, $angle, $left + $left_offset, $top + $largest_line_height + ($largest_line_height * $i), $color, $font, $line);
           
$i++;
        }
       
        return
$largest_line_height * count($lines);
}
?>

llewellyntd at gmail dot com (12-Mar-2008 11:27)

Hi All,

I struggled for moths to do a decent text warp with GD lib. Here is the code that I made use of:

<?php
//word wrap
$warpText = wordwrap($text, 30, "\n");
//display text
imagettftext($image, $fontSize, 0, $x, $y, $fontColor, $font, $warpText);
?>

Hope this helps somebody.

Cheers

m0r1arty at mail dot ru (13-Feb-2008 06:50)

Sorry my English.
I have trouble with using imagettftext under Windows.
I can't used short name of fonts(example "arial","arialbd.ttf" etc). PHP say what not find this font.
Manipulation with environment GDFONTPATH lost.
This is my solution
<?php
$dir
=opendir('./font/');//directory with fonts
if($dir)
    while(
$f=readdir($dir)){
        if(
preg_match('/\.ttf$/',$f)){
           
$font=explode('.',$f);
           
define($font[0],realpath('./font/'.$f));
        }
    }
if(
$dir)
   
closedir($dir);
?>
Directory "font" have two file: arial.ttf and arialbd.ttf
Now one can using constant font name by calling imagettftext:
imagettftext($img,12,0,25,28,$color,arialbd,'some text');

matt at mmkennedy dot net (18-Jan-2008 03:11)

For anyone attempting to print black barcodes, and trying to turn of anti-aliasing, remember that -1 * [0,0,0] is 0, not -0.

denis at reddodo dot com (24-Dec-2007 02:05)

Small but very dangerous bug in function ttfWordWrappedText, written by waage, just try ttfWordWrappedText("aaaaa\naa",4) and your script will run into endless loop.
You can fix it with code below:
<?php
   
function ttfWordWrappedText_fixed($text, $strlen = 8) {
   
$text = urldecode($text);
   
$text = explode("\n", $text);
   
$i = 0;
    foreach(
$text as $text)
    {
        while(
strlen($text) > $strlen  && strstr($text, ' ') !== FALSE) {
          
$startPoint = strpos($text, ' ');
          
$line[$i][] =substr($text,0,$startPoint); 
          
$text = trim(strstr($text, ' '));
        }
       
$line[$i][] = trim($text);
        }
       
$line[$i][] = trim($text);
       
$i++;
    }
  
    return
$line;
}
?>
better solutions is to check input text for lines longer than needed wrap point.

denis at reddodo dot com (24-Dec-2007 01:46)

Small but very dangerous bug in function ttfWordWrappedText, written by waage, just try ttfWordWrappedText("aaaaa\naa",4) and your script will run into endless loop.
You can fix it with code below:
<?php
   
function ttfWordWrappedText_fixed($text, $strlen = 8) {
   
$text = urldecode($text);
   
$text = explode("\n", $text);
  
   
$i = 0;
    foreach(
$text as $text)
    {
        while(
strlen($text) > $strlen && stristr($text, ' ') !== FALSE) {
          
$startPoint = $strlen - 1;
           while(
substr($text, $startPoint, 1) != " ") {
               
$startPoint--;
           }
          
$line[$i][] = trim(substr($text, 0, $startPoint));
          
$text = substr($text, $startPoint);
        }
       
$line[$i][] = trim($text);
       
$i++;
    }
  
    return
$line;
}
?>
better solutions is to check input text for lines longer than needed wrap point.

dotpointer (09-Dec-2007 12:40)

For those trying to disable the font smoothing or font cleartype:ing, take a look at the color parameter for this function. The correct word for what you're looking for is antialiasing.

Anonymous (16-Nov-2007 12:14)

Just to comment on Sohel Taslims great function...
if anyone needs to add BACKGROUND TRANSPARENCY to this kind of function (which almost does everyone one would want already) then add

$bg_color = imagecolorat($im,1,1);
imagecolortransparent($im, $bg_color);

ABOVE the "if($L_R_C == 0){ //Justify Left"  line

waage (07-Nov-2007 03:31)

I had some issues trying to get both word wrapping and new line detection but with some of the help from the comments below i got this. (thanks to jwe for the main part of the code here)

<?php
function ttfWordWrappedText($text, $strlen = 38) {
   
$text = urldecode($text);
   
$text = explode("\n", $text);
   
   
$i = 0;
    foreach(
$text as $text)
    {
        while(
strlen($text) > $strlen) {
          
$startPoint = $strlen - 1;
           while(
substr($text, $startPoint, 1) != " ") {
               
$startPoint--;
           }
          
$line[$i][] = trim(substr($text, 0, $startPoint));
          
$text = substr($text, $startPoint);
        }
       
$line[$i][] = trim($text);
       
$i++;
    }
   
    return
$line;
}
?>

This returns an array for each newline entered and subarray for each wordwrapped line to print.

ie.

Array
(
    [0] => Array
        (
            [0] => This is the first long line
            [1] => that i entered.
        )

    [1] => Array
        (
            [0] => And this is the new line after that.
        )
)

mitch at electricpulp dot com (20-Sep-2007 03:35)

If you're having issues with fonts not working... (Could not find/open font) check your permissions on the folder/font files and make sure they're 775, especially if you've just pulled them from a windows box. Hope this helps!

Ole Clausen (11-Sep-2007 05:11)

Comment to: Sohel Taslim (03-Aug-2007 06:19)

Thanks for the function which I have modified a bit. In the new version the lines have equal space between them (the g's in your example create bigger space between the lines) - set by the parameter '$Leading'.

I have used the for-loop for better performance and slimmed the rest a little  :)

    /**
     * @name                    : makeImageF
     *
     * Function for create image from text with selected font. Justify text in image (0-Left, 1-Right, 2-Center).
     *
     * @param String $text     : String to convert into the Image.
     * @param String $font     : Font name of the text. Kip font file in same folder.
     * @param int    $Justify  : Justify text in image (0-Left, 1-Right, 2-Center).
     * @param int    $Leading  : Space between lines.
     * @param int    $W        : Width of the Image.
     * @param int    $H        : Hight of the Image.
     * @param int    $X        : x-coordinate of the text into the image.
     * @param int    $Y        : y-coordinate of the text into the image.
     * @param int    $fsize    : Font size of text.
     * @param array  $color    : RGB color array for text color.
     * @param array  $bgcolor  : RGB color array for background.
     *
     */
    function imagettfJustifytext($text, $font="CENTURY.TTF", $Justify=2, $Leading=0, $W=0, $H=0, $X=0, $Y=0, $fsize=12, $color=array(0x0,0x0,0x0), $bgcolor=array(0xFF,0xFF,0xFF)){
       
        $angle = 0;
        $_bx = imageTTFBbox($fsize,0,$font,$text);
        $s = split("[\n]+", $text);  // Array of lines
        $nL = count($s);  // Number of lines
        $W = ($W==0)?abs($_bx[2]-$_bx[0]):$W;    // If Width not initialized by programmer then it will detect and assign perfect width.
        $H = ($H==0)?abs($_bx[5]-$_bx[3])+($nL>1?($nL*$Leading):0):$H;    // If Height not initialized by programmer then it will detect and assign perfect height.
       
        $im = @imagecreate($W, $H)
            or die("Cannot Initialize new GD image stream");
       
        $background_color = imagecolorallocate($im, $bgcolor[0], $bgcolor[1], $bgcolor[2]);  // RGB color background.
        $text_color = imagecolorallocate($im, $color[0], $color[1], $color[2]); // RGB color text.
       
        if ($Justify == 0){ //Justify Left
            imagettftext($im, $fsize, $angle, $X, $fsize, $text_color, $font, $text);
        } else {
            // Create alpha-nummeric string with all international characters - both upper- and lowercase
            $alpha = range("a", "z");
            $alpha = $alpha.strtoupper($alpha).range(0, 9);
            // Use the string to determine the height of a line
            $_b = imageTTFBbox($fsize,0,$font,$alpha);
            $_H = abs($_b[5]-$_b[3]);
            $__H=0;
            for ($i=0; $i<$nL; $i++) {
                $_b = imageTTFBbox($fsize,0,$font,$s[$i]);
                $_W = abs($_b[2]-$_b[0]);
                //Defining the X coordinate.
                if ($Justify == 1) $_X = $W-$_W;  // Justify Right
                else $_X = abs($W/2)-abs($_W/2);  // Justify Center
               
                //Defining the Y coordinate.
                $__H += $_H;
                imagettftext($im, $fsize, $angle, $_X, $__H, $text_color, $font, $s[$i]);
                $__H += $Leading;
            }
        }
       
        return $im;
    }

Sohel Taslim (03-Aug-2007 05:19)

Left Right Center align/justify of text in image. It is easy and simple to do in PHP.
Create an image from text and align them as you want. After that save or display image.

<?php
/**
 * Function for converting Text to Image.
 * Kip CENTURY.TTF file in same folder.
 *
 * @author Taslim Mazumder Sohel
 * @deprecated 1.0 - 2007/08/03
 *
 */
     //Example call.
   
$str = "New life in programming.\nNext Line of Image.\nLine Number 3\n" .
       
"This is line numbet 4\nLine number 5\nYou can write as you want.";   
   
header("Content-type: image/gif");   
   
imagegif(imagettfJustifytext($str,"CENTURY.TTF",2));
   
//End of example.
   
   
    /**
     * @name                    : makeImageF
     *
     * Function for create image from text with selected font. Justify text in image (0-Left, 1-Right, 2-Center).
     *
     * @param String $text     : String to convert into the Image.
     * @param String $font     : Font name of the text. Kip font file in same folder.
     * @param int    $W        : Width of the Image.
     * @param int    $H        : Hight of the Image.
     * @param int    $X        : x-coordinate of the text into the image.
     * @param int    $Y        : y-coordinate of the text into the image.
     * @param int    $fsize    : Font size of text.
     * @param array  $color       : RGB color array for text color.
     * @param array  $bgcolor  : RGB color array for background.
     *
     */
   
function imagettfJustifytext($text, $font="CENTURY.TTF", $Justify=2, $W=0, $H=0, $X=0, $Y=0, $fsize=12, $color=array(0x0,0x0,0x0), $bgcolor=array(0xFF,0xFF,0xFF)){
       
       
$angle = 0;
       
$L_R_C = $Justify;
       
$_bx = imageTTFBbox($fsize,0,$font,$text);

       
$W = ($W==0)?abs($_bx[2]-$_bx[0]):$W;    //If Height not initialized by programmer then it will detect and assign perfect height.
       
$H = ($H==0)?abs($_bx[5]-$_bx[3]):$H;    //If Width not initialized by programmer then it will detect and assign perfect width.

       
$im = @imagecreate($W, $H)
            or die(
"Cannot Initialize new GD image stream");
           
           
       
$background_color = imagecolorallocate($im, $bgcolor[0], $bgcolor[1], $bgcolor[2]);        //RGB color background.
       
$text_color = imagecolorallocate($im, $color[0], $color[1], $color[2]);            //RGB color text.
       
       
if($L_R_C == 0){ //Justify Left
           
           
imagettftext($im, $fsize, $angle, $X, $fsize, $text_color, $font, $text);
           
        }elseif(
$L_R_C == 1){ //Justify Right
           
$s = split("[\n]+", $text);
           
$__H=0;
           
            foreach(
$s as $key=>$val){
           
               
$_b = imageTTFBbox($fsize,0,$font,$val);
               
$_W = abs($_b[2]-$_b[0]);
               
//Defining the X coordinate.
               
$_X = $W-$_W;
               
//Defining the Y coordinate.
               
$_H = abs($_b[5]-$_b[3]); 
               
$__H += $_H;             
               
imagettftext($im, $fsize, $angle, $_X, $__H, $text_color, $font, $val);   
               
$__H += 6;
               
            }
           
        }
        elseif(
$L_R_C == 2){ //Justify Center
           
           
$s = split("[\n]+", $text);
           
$__H=0;
           
            foreach(
$s as $key=>$val){
           
               
$_b = imageTTFBbox($fsize,0,$font,$val);
               
$_W = abs($_b[2]-$_b[0]);
               
//Defining the X coordinate.
               
$_X = abs($W/2)-abs($_W/2);
               
//Defining the Y coordinate.
               
$_H = abs($_b[5]-$_b[3]); 
               
$__H += $_H;             
               
imagettftext($im, $fsize, $angle, $_X, $__H, $text_color, $font, $val);   
               
$__H += 6;
               
            }
           
        }       
                       
        return
$im;
       
    }
       
 
?>

Borgso (28-Jul-2007 12:30)

Right align out of "webmaster at higher-designs dot com" code
<?php
$color
= imagecolorallocate($im, 0, 0, 0);
$font = 'visitor.ttf';
$fontsize = "12";
$fontangle = "0";
$imagewidth = imagesx($im);
$imageheight = imagesy($im);

$text = "My right align text";

$box = @imageTTFBbox($fontsize,$fontangle,$font,$text);
$textwidth = abs($box[4] - $box[0]);
$textheight = abs($box[5] - $box[1]);
$xcord = $imagewidth - ($textwidth)-2; // 2 = some space from right side.
$ycord = ($imageheight/2)+($textheight/2);

ImageTTFText ($im, $fontsize, $fontangle, $xcord, $ycord, $black, $font, $text);
?>

Lassial at the google mail dot com (13-Jun-2007 08:42)

Creating multiline text with GD is bit complicated, one of the issues I've ran to is how to set line spacing, a normal feature in all type setting (even type writers). By default, line spacing with imagettftext seems to be 150 % or more, too much for me anyhow. Thus I've used the function below to get the lines closer to each other. By default, it appears to create 100 % linespacing, but it has not been tested thoroughly.

null imagettfmultilinetext
(resource $image, float $size, float $angle, int $x, int $y, int $color, string $fontfile, string $text , $spacing)

spacing is a coefficient, comparable to Line spacing in a word processors or graphics software, causing a shift relative to font size in the line spacing

<?php
function imagettfmultilinetext($image, $size, $angle, $x, $y, $color, $fontfile$text, $spacing=1)
{

$lines=explode("\n",$text);
for(
$i=0; $i< count($lines); $i++)
    {
   
$newY=$y+($i * $size * $spacing);
   
imagettftext($image, $size, $angle, $x, $newY, $color, $fontfile$lines[$i], $spacing);
    }
return
null;
}
?>

ken at smallbox software (11-Jun-2007 05:24)

Strangely this function seems to work with adobe post script files (tried .pfb) not sure why this isn't documented or why there is a separate set of functions for dealing with postscript.

php at gilbertson dot me dot uk (01-Jun-2007 09:52)

Users may note a problem trying to use this function to display the Euro symbol.

The reason is that it is a late addition. Although the operating systems generally recognise code 0x80 (128 decimal) as Euro, this is not where it necessarily appears in the font. Some have it there, but many just have it in the extended character set at position 0x20AC (8364 decimal).

I have yet to find a font with it only at 0x80, so here is the fix:

<?php
$image
=imagecreate(135,24);
$bg=imagecolorallocate($image,0,0,0);
$fg=imagecolorallocate($image,0,255,0);
$text = 'coffee - €3.50';
$friendly = eurofix($text);
imagettftext($image,16,0,5,20,$fg,"Papyrus.ttf",$friendly);
imagegif ($image);
imagedestroy ($image);

function
eurofix($str) {
$euro=utf8_encode('&#8364;');
$str = preg_replace('/\x80/',$euro,$str);
return (
$str);
}
?>

You should note, however, this won't help with fonts older than about 1999. It can only make sure the Euro is displayed where available.

lassial at gmail dot com (10-May-2007 02:56)

Roy van Arem suggested a neat code for listing TTFs on a machine. However, it has some problems (such as lower and upper case distinction of file extension and defective fonts) that I have corrected in the following script, which can be implemented as a single PHP script (name as you like):

<?php //make sure there are no blank lines above
       
$ffolder="/usr/local/bin/fonts"; //The directory where your fonts reside

if (empty($_GET['f']))
{
$folder=dir($ffolder); //open directory
echo "<HTML><BODY>\n";
   
while(
$font=$folder->read())
  if(
stristr($font,'.ttf')) //only ttf fonts
       
$fonts[]=$font;
       
$folder->close();

if (!empty(
$fonts))
        {
        echo
"<table><tr><th colspan='2'>Fonts available in $ffolder</th></tr>"
       
."\n<tr><th>Name</th><th>Appereance</th>";
       
sort($fonts);
        foreach (
$fonts as $font)
                echo
"<tr><td>$font</td><td> <IMG src='".$_SERVER['SCRIPT_NAME']
                        .
"?f=$font'></td></tr>\n";
        }
else echo
"No fonts found from $ffolder";
echo
"\n</HTML></BODY>";
}

else
{
$im=@imagecreatetruecolor(200,30)
        or die(
"Cannot Initialize new GD image stream");

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

imagefill($im,0,0,$white);
imagettftext($im,14,0,5,25,$black, "$ffolder/".$_GET['f'] , $_GET['f']);

header("Content-type: image/png");
header('Content-Length: ' . strlen($im));

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

ultraniblet at gmail dot com (05-May-2007 09:08)

I have found the kerning (spacing between letters) pretty poor with GD - it's not up to your average designer's standards. Here are some ways to improve it:
- Place the letters one by one using their bounding box instead of using one string
- adjust with a $kerning value
- For small text, sample it down from a larger size to adjust in increments less than 1px

Eg:

<?PHP

$STRING
= "NOTRE PHILOSOPHIE";

// ---- PRESETS
$FONT = "CantoriaMTStd-SemiBold.otf";
$FONT_SIZE = 10.5;
$WIDTH = 200;
$HEIGHT = 16;
$KERNING = 0;
$BASELINE = 12;
$BG_COLOR = array(
   
"R"=>5,
   
"G"=>45,
   
"B"=>53
);
$TXT_COLOR = array(
   
"R"=>188,
   
"G"=>189,
   
"B"=>0
);

// ---- CREATE CANVAS + PALETTE
$canvas = imageCreateTrueColor($WIDTH*4,$HEIGHT*4);

$bg_color = imageColorAllocate($canvas, $BG_COLOR["R"], $BG_COLOR["G"], $BG_COLOR["B"]);

$txt_color = imageColorAllocate($canvas, $TXT_COLOR["R"], $TXT_COLOR["G"], $TXT_COLOR["B"]);

imagefill ( $canvas, 0, 0, $bg_color );

// ---- DRAW

$array = str_split($STRING);
$hpos = 0;

for(
$i=0; $i<count($array); $i++)
{
   
$bbox = imagettftext( $canvas, $FONT_SIZE*4, 0, $hpos, $BASELINE*4, $txt_color, $FONT, $array[$i] );
   
   
$hpos = $bbox[2]+$KERNING;
}

// ---- SAMPLE DOWN & OUTPUT
$final = imageCreateTrueColor($WIDTH,$HEIGHT);

imageCopyResampled( $final, $canvas, 0,0,0,0, $WIDTH, $HEIGHT, $WIDTH*4, $HEIGHT*4 );

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

imagePNG($final);

imageDestroy($canvas);
imageDestroy($final);

?>

Roy van Arem (27-Nov-2006 04:01)

If you want to display a list of fonts in a directory and see what they look like, you could do something like this:

<HTML><BODY>

<?php

$folder
=dir("fonts/"); //The directory where your fonts reside

while($font=$folder->read())
  {

  if(
stristr($font,'.ttf'))echo '<IMG SRC="img.php?'.substr($font,0,strpos($font,'.')).'">'; //only ttf fonts

 
}

$folder->close();

?>

</BODY></HTML>

The file for 'img.php' should be something like this:

<?php

$font
=$_SERVER["QUERY_STRING"];

header("Content-type: image/png");
$im=@imagecreatetruecolor(200,30)or die("Cannot Initialize new GD image stream");

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

imagefill($im,0,0,$white);

imagettftext($im,18,0,5,25,$black,"fonts/".$font,$font);

imagepng($im);
imagedestroy($im);

?>

Something similar I implemented at http://font.beginstart.com

ben at evolutioncomputing co uk (05-Nov-2006 09:25)

A centralised text watermark - of  any length, that automatically sizes to about 70% of the width, and can be rotated to any angle.

<?php
/* Get image info */
$Image = @ImageCreateFromJPEG ("YourImage.jpg") ;
$sx = imagesx($Image) ;
$sy = imagesy($Image) ;
if (
$WatermarkNeeded)
    {
   
/* Set text info */
   
$Text="Copyright Ben Clay" ;
   
$Font="arial.ttf" ;
   
$FontColor = ImageColorAllocate ($Image,255,255,255) ;
   
$FontShadow = ImageColorAllocate ($Image,0,0,0) ;
   
$Rotation = 30 ;
   
/* Make a copy image */
   
$OriginalImage = ImageCreateTrueColor($sx,$sy) ;
   
ImageCopy ($OriginalImage,$Image,0,0,0,0,$sx,$sy) ;
   
/* Iterate to get the size up */
   
$FontSize=1 ;
    do
        {
       
$FontSize *= 1.1 ;
       
$Box = @ImageTTFBBox($FontSize,0,$Font,$Text);
       
$TextWidth = abs($Box[4] - $Box[0]) ;
       
$TextHeight = abs($Box[5] - $Box[1]) ;
        }
    while (
$TextWidth < $sx*0.7) ;
   
/*  Awkward maths to get the origin of the text in the right place */
   
$x = $sx/2 - cos(deg2rad($Rotation))*$TextWidth/2 ;
   
$y = $sy/2 + sin(deg2rad($Rotation))*$TextWidth/2 + cos(deg2rad($Rotation))*$TextHeight/2 ;
   
/* Make shadow text first followed by solid text */
   
ImageTTFText ($Image,$FontSize,$Rotation,$x+4,$y+4,$FontShadow,$Font,$Text);
   
ImageTTFText ($Image,$FontSize,$Rotation,$x,$y,$FontColor,$Font,$Text);
   
/* merge original image into version with text to show image through text */
   
ImageCopyMerge ($Image,$OriginalImage,0,0,0,0,$sx,$sy,50) ;
    }

ImageJPEG ($Image) ;
?>

Tom Pike (04-Oct-2006 04:48)

Ref: Craig at frostycoolslug dot com

"Using the negative of a color index has the effect of turning off antialiasing."

This is true, but only if the image has been created with imagecreate() (as opposed to imagecreatetruecolor())

Craig at frostycoolslug dot com (28-Sep-2006 03:54)

This one caught me out a little bit as confusing, so in an attempt to help others..

"Using the negative of a color index has the effect of turning off antialiasing."

Simply put:

<?php

$textColour
= ImageColorAllocate($image, 255, 255, 255);
ImageTTFText($image, 8, 0, 0, 0, -$textColour, $font, $text);

?>

Note the - (minus) before the $textColor in ImageTTFText, this creates the negative colour index, and switches off AA on text.

webmaster at higher-designs dot com (16-Aug-2006 06:16)

I spent days looking for this, couldn't find it, so just made it myself. This is an ultra simple text banner that keeps the text pretty much centered (not perfect when text is angled) vertically and horizontally. Size, font, colors are easy to edit and in HTML version for the colors.

Any additions (maybe for multi-line functionality) can be added if you desire.

<?php
### Declare this script will be displayed as a PNG image.
header("Content-type: image/png");

####################### BEGIN USER EDITS #######################
$imagewidth = 500;
$imageheight = 100;
$fontsize = "20";
$fontangle = "0";
$font = "arial.ttf";
$text = "123456789";
$backgroundcolor = "003366";
$textcolor = "FFCC66";
######################## END USER EDITS ########################

### Convert HTML backgound color to RGB
if( eregi( "([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})", $backgroundcolor, $bgrgb ) )
{
$bgred = hexdec( $bgrgb[1] );   $bggreen = hexdec( $bgrgb[2] );   $bgblue = hexdec( $bgrgb[3] );}

### Convert HTML text color to RGB
if( eregi( "([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})", $textcolor, $textrgb ) )
{
$textred = hexdec( $textrgb[1] );   $textgreen = hexdec( $textrgb[2] );   $textblue = hexdec( $textrgb[3] );}

### Create image
$im = imagecreate( $imagewidth, $imageheight );

### Declare image's background color
$bgcolor = imagecolorallocate($im, $bgred,$bggreen,$bgblue);

### Declare image's text color
$fontcolor = imagecolorallocate($im, $textred,$textgreen,$textblue);

### Get exact dimensions of text string
$box = @imageTTFBbox($fontsize,$fontangle,$font,$text);

### Get width of text from dimensions
$textwidth = abs($box[4] - $box[0]);

### Get height of text from dimensions
$textheight = abs($box[5] - $box[1]);

### Get x-coordinate of centered text horizontally using length of the image and length of the text
$xcord = ($imagewidth/2)-($textwidth/2)-2;

### Get y-coordinate of centered text vertically using height of the image and height of the text
$ycord = ($imageheight/2)+($textheight/2);

### Declare completed image with colors, font, text, and text location
imagettftext ( $im, $fontsize, $fontangle, $xcord, $ycord, $fontcolor, $font, $text );

### Display completed image as PNG
imagepng($im);

### Close the image
imagedestroy($im);
?>

jwe (24-Jul-2006 07:48)

I found this line a little confusing:

"May include decimal numeric character references (of the form: &#8364;) to access characters in a font beyond position 127."

I was using a font that had apostrophes and quotes stored in a non-standard position, and so they were being rendered as spaces by imagettftext.  This line seemed to suggest a solution, but it took a while to figure it out.

Turns out, a "decimal numeric character reference" is a decimal conversion of the hex value of the *unicode* position of the character you want.  For a while I was trying ASCII positions (I knew the ALT+ code for typing the character I needed in Windows).

In the Windows XP character map, the unicode positions are shown as U+2018 or U+201C, etc.  Ignore the U+ and convert that hex number to decimal, and then stick that in your text string with the &# on the front and ; on the end, and pass it to imagettftext.

--Julian

jwe (19-Jul-2006 04:48)

Quick tip for anyone who is receiving text like in the example in this page (ie: through $_GET['text'] or something similar) and needs to format the text into multiple lines.  The trick is finding the spaces...

<?php
$text
= $_GET['text'];
// for a maximum of 38 characters on a line...
while(strlen($text) > 38) {
  
$startPoint = 37;
  
// find a space to break the line on
  
while(substr($text, $startPoint, 1) != " ") {
       
$startPoint--;
   }
  
$line[] = trim(substr($text, 0, $startPoint));
  
$text = substr($text, $startPoint);
}
$line[] = trim($text);
?>

The result is an array called $line that contains all the lines of text you need to output in order.

The only tasks left are to determine the correct height of the image based on the font size you want to use.  Don't forget to leave some padding space for punctuation and descenders between lines (commas, g, q, p, y, etc).

imagettftext is unbelievably useful when you need to create header images using non-standard fonts.  Amazing.  Huge thanks to the devs.

--Julian

admin at sgssweb dot com (01-May-2006 12:08)

Another way of the bellow. After creating a child class of GMIPluggableSet class, which should override two method: getExpression() and getVariables(), throw it to a instance of FontImageGenerator class.
For example, the code follows:

<?php

require_once 'package.fig.php';

class
SampleFontImagePluggableSet
   
extends GMIPluggableSet
{
    var
$defaultVariables = array(
       
"text" => null,
       
"size" => null,
       
"font" => null,
       
"color" => "0x000000",
       
"alpha" => "100",
       
"padding" => 0,
       
"width" => null,
       
"height" => null,
       
"align" => "left",
       
"valign" => "middle",
       
"bgcolor" => "0xffffff",
       
"antialias" => 4
   
);
   
    function
SampleFontImagePluggableSet() {
       
parent::GMIPluggableSet();
    }
   
    function
getExpression() {
        return
"size {width}, {height};".
              
"autoresize none;".
              
"type gif, 256, {color: {bgcolor}};".
              
"padding {padding};".
              
"color {color: {bgcolor}};".
              
"fill;".
              
"color {color: {color}, {alpha}};".
              
"antialias {antialias};".
              
"font {font}, {size};".
              
"string {text}, 0, 0, {width}, {height}, {align}, {valign};";
    }
   
    function
getVariables() {
        return
array_merge($this->defaultVariables, $_GET);
    }
}

$pluggableSet = new SampleFontImagePluggableSet();
$fig = new FontImageGenerator();
$fig->setPluggableSet($pluggableSet);
$fig->execute();

?>

This output a image with the text defined in $_GET['text'], the font in $_GET['font'], the text color in $_GET['color'], the background in $_GET['bgcolor'], and so on.

The script file is available at: http://sgssweb.com/experiments/?file=PHPFontImageGenerator .

admin at sgssweb dot com (30-Apr-2006 07:17)

I wrote two classes: PHP Abstract Drawing Toolkit and PHP Graphics, the elements of PHP Font Image Generator2. An instance of the class Graphics can draw multi-sampling antialiased text, 7 horizontal alignment of text box (left, center, right, left-adjust, center-adjust, right-adjust, adjust), 3 vertical alignment (top, middle, bottom), and other Java-like methods.

<?php
require_once "package.graphics.php";

$canvas = new Canvas();
$canvas->setSize(400, 400);
$g =& $canvas->getGraphics();
$g->setColor(new Color(0xffffff));
$g->fill();
$g->setColor(new Color(0, 0, 0, 80));
$g->setFont(new Font($_POST['font'], 20));
$g->drawString($_POST['text'], 0, 0, 400, 400, 'center-adjust', 'middle');
$canvas->complete();
$canvas->output();

?>

The class script is here.
http://sgssweb.com/experiments/?file=PHPFontImageGenerator2

jpetsel at riverviewtech dot net (27-Apr-2006 08:06)

I was looking at ugo's center and it was great for left to right centering, but it wouldn't center up and down.  So with some changes to suit my needs this is what I came up with.  Some of the notations are just for my edifcation so may mean nothing for you all but you will see I added a $posy that helps with centering up and down.  I was also feeding my feilds from a form.

<?php
// Set the content-type
header("Content-type: image/png");

//1line per column
$text=array(0=>$_POST['linei'],1=>$_POST['lineii'],
2=>$_POST['lineiii'],3=>$_POST['lineiv'],4=>$_POST['linev']);

$Image_Width=400;
$Text_Size=$_POST['textsize'];
$Image_Height=400;

// Create the image
$im = imagecreatetruecolor ($Image_Width, $Image_Height); /* Create a blank image */

// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 1, 1, 398, 398, $white);

// Replace path by your own font path
$font = $_POST['font_name'];

for (
$i=0; $i < sizeof($text); $i++) {

   
//Center the text
   
$Text_Box_Size = imagettfbbox($Text_Size, 0, $font, $text[$i]);
   
$Text_Box_Width = abs($Text_Box_Size[2] + $Text_Box_Size[0]);
   
$Text_Box_Height = abs($Text_Box_Size[7] + $Text_Box_Size[1]);
   
$Text_Height = $Text_Height + $Text_Box_Height;
   
$posx = ($Image_Width - $Text_Box_Width) / 2;
   
$posy = ($Image_Height - $Text_Box_Height * sizeof($text)) / 2 + $Text_Height;

   
/*
    Add the text (***array imagettftext ( resource image, float size, float angle,
    int x, int y, int color, string fontfile, string text )***)
    */
   
   
imagettftext($im, $Text_Size, 0, $posx, $posy, $black, $font, $text[$i]);
}

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
?>

ugo dot quaisse at gmail dot com (19-Apr-2006 02:03)

This is a script that aim at center the (multi) lines :

<?php
header
("Content-type: image/png");

//1line per column
$text=array(0=>"line 1",1=>"line 2");

$largeur=500;
$line_height=30;
$hauteur=sizeof($text)*$line_height;

// Create the image
$im = imagecreatetruecolor($largeur, $hauteur);

// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 225, 225, 225);
$blue = imagecolorallocate($im, 0, 62, 126);
imagefilledrectangle($im, 0, 0, $largeur, $hauteur, $white);

// Replace path by your own font path
$font = 'font.ttf';

for(
$i=0;$i<=sizeof($text);$i++) {
//Center the text
$size = imagettfbbox(20, 0, $font, $text[$i]);
$long_text = $size[2]+$size[0];
$posx=($largeur-$long_text)/2;
// Add the text
imagettftext($im, 20, 0, $posx, $line_height+$line_height*$i, $blue, $font, $text[$i]);
}

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

mats dot engstrom at gmail dot com (28-Mar-2006 10:23)

I'll second the note from --colobri--. 

Just adding --with-ttf and --with-freetype-dir=/usr/lib/ on the ./configure and then doing a "make; make install" is not enough.

I had to do a "make clean" and then a "make install" in order to get the FreeType-support enabled.

Here are my relevant ./configure lines:
--with-gd \
--enable-gd-native-ttf \
--with-ttf \
--with-freetype-dir=/usr/lib/ \
--with-jpeg-dir=/usr/lib/libjpeg.so.62 \
--enable-exif \

admin at phpru dot com (28-Feb-2006 05:52)

On my conf: php5.1.2+apache 1.33
iconv() function works very well with all cyrillic encodings, so you needn't to write your function like win2uni

--Colibri-- (28-Jan-2006 08:53)

If you have configured and compiled PHP with all the necessary command-line options and still get the error:

Fatal error: Call to undefined function imagettftext()

Try doing a "make clean"  before building the php apache module:

./configure [...]
make clean
make
make install

This may solve your problem (and hopefully keep you from wasting hours trying different compile options!)

nospam at nospam dot nospam (22-Jan-2006 11:51)

I've found that upsampling your text by a factor of 8 or more can really improve the readability of generated text, especially in smaller font sizes (9 or less). I find it also helps with fonts that have kerning to reduce space between letters such as capital T and capital A (TA) where the top-right of the T will be cut off due to GD "features".

I can't tell you, the reader, exactly how to do this, as it will depend on how you are currently generating your text, but essentially what you want to try doing is upsize your font by a factor of 8 and then scale down the resulting image by the same factor.

So if you were using font size 10, use font size 80 and use imagecopyresampled() to divide the width/height down again by 8. The resulting image will be a few pixels different in width / height compared to direct text writing, so make sure to check your image sizes if you are using fixed dimensions.

Play around with other factors, 16 is a bit nicer but results in a higher CPU/RAM load when processing. Any higher is unnecessary I think. If possible you should also cache the image to a file instead of reprocessing it each request.

Mer`Zikain (10-Jan-2006 08:41)

I was looking for a way to add kerning to my text and finally just made this function to do it. Of course, if you're generating the size of the image based on the text you're putting in it, you'll have to figure out the new size to fit the new text width but I'm sure you can figure that out.

for($i=0;$i<strlen($text);$i++){
        // Get single character
    $value=substr($text,$i,1);
    if($pval){ // check for existing previous character
        list($lx,$ly,$rx,$ry) = imagettfbbox($fontsize,0,$font,$pval);
        $nxpos+=$rx+3;
    }else{
        $nxpos=0;
    }
        // Add the letter to the image
    imagettftext($im, $fontsize, 0, $nxpos, $ypos, $fontcolor, $font, $value);
    $pval=$value; // save current character for next loop
}

a4W (23-Oct-2005 08:28)

This function will make your text bold:
<?php
function drawboldtext($image, $size, $angle, $x_cord, $y_cord, $r, $g, $b, $fontfile, $text)
{
  
$color = ImageColorAllocate($image, $r, $g, $b);
  
$_x = array(1, 0, 1, 0, -1, -1, 1, 0, -1);
  
$_y = array(0, -1, -1, 0, 0, -1, 1, 1, 1);
   for(
$n=0;$n<=8;$n++)
   {
     
ImageTTFText($image, $size, $angle, $x_cord+$_x[$n], $y_cord+$_y[$n], $color, $fontfile, $text);
   }
}
?>

limalopex.eisfux.de (03-Oct-2005 05:17)

If you have problems displaying german umlauts or other chars with an ascii value > 127, try to convert the text-parameter first. The following function converts character-values > 127 (both: UTF-8 + ANSI) to HTML's numeric coded entities:

<?php
define
('EMPTY_STRING', '');

function
foxy_utf8_to_nce(
 
$utf = EMPTY_STRING
) {
  if(
$utf == EMPTY_STRING) return($utf);

 
$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 = EMPTY_STRING;
  for(
$str_pos = 0; $str_pos < strlen($utf); $str_pos++) {
   
$old_chr = $utf{$str_pos};
   
$old_val = ord( $utf{$str_pos} );
   
$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);
}
?>

alexey at NOSPAMPLS dot ozerov dot de (31-Aug-2005 08:30)

Notice that the path to the TrueType font has to be included in open_basedir list if open_basedir restriction is activated in php.ini.

gav-alex at bk dot ru (10-Aug-2005 05:05)

Hi all!
When my hoster updated his php's libs at first minutes i've got the same problem as some of you.
Php couldn't find the path to true type fonts.
The solution in my case was to make the path look like this
<?php
imagettftext
($im, 20, 0, 620, 260, $secondary_color, "./tahoma.ttf" , "NEWS");
?>
so as you can see i simply added "./"

another tip that i wanted to add here is how to write in RUssian on image using imagettftext
you simply have to change the function argument like this
<?php
imagettftext
($im, 15, 0, 575, 300, $secondary_color, "./tahoma.ttf" , win2uni("some word in russian"));
 
?>
where win2uni is the function that converts win1251 to unicode. here is the code of it
<?php

 
//  Windows 1251 -> Unicode
 
function win2uni($s)
  {
   
$s = convert_cyr_string($s,'w','i'); //  win1251 -> iso8859-5
    //  iso8859-5 -> unicode:
   
for ($result='', $i=0; $i<strlen($s); $i++) {
     
$charcode = ord($s[$i]);
     
$result .= ($charcode>175)?"&#".(1040+($charcode-176)).";":$s[$i];
    }
    return
$result;
  }
?>

That's all today! Thanks for your attention!
Alex

BuddyHacker (21-Jul-2005 10:55)

A correction to Paul Reinheimer's note above regarding this PHP error:

Fatal error: Call to undefined function imagettftext().

Paul states that you need XPM libraries to resolve this issue.  This is not true.  There is an error message that originates from "configure" which mistakenly shows itself when other components are missing.  For instance, if you tell "configure" to add JPEG support, and it can't find the libraries, it will tell you it can't find the JPEG libraries AND it will recommend adding --with-xpm to solve the problem.  This recommendation is ill-placed and misleading.

I received the same error message above, along with the recommendation to add XPM supprt.  However I resolved it by adding the --with-freetype-dir  AND --enable-gd-native-ttf  options  to the "configure" command line.  I did _not_ need XPM.

There are other variations to this error message, such as the script recommending adding JPEG support or PNG support to resolve it's own inability to locate other libraries.  The script needs some cleanup in order to fix these poorly placed recommendations.

FYI, imagettftext() is a call to one of the truetype fonts functions.  It is NOT related in any way to the XPM libraries, so it is not required unless you explicitly want XPM functionality.

nick (01-Apr-2005 09:18)

A trivial function to get right or centre aligned horizontal text:

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

}

erik[at]phpcastle.com (04-Mar-2005 12:46)

Remember!!!

When uploading a font to your website you have to set the transfer mode to binary. It took me some time to find out :P. Tried to download the font from my website and it was spoiled.

In your script, the path to your font, use realpath("arial.ttf") so there is no confusion about that.

pillepop2003 at nospam dot yahoo dot de (12-Jan-2005 01:14)

Hey guys,

check this function if you want to rotate the text around its center and not its "lower left" pivot-point:

<?php
       
// Put center-rotated ttf-text into image
        // Same signature as imagettftext();
       
function imagettftext_cr(&$im, $size, $angle, $x, $y, $color, $fontfile, $text)
        {
           
// retrieve boundingbox
           
$bbox = imagettfbbox($size, $angle, $fontfile, $text);
           
           
// calculate deviation
           
$dx = ($bbox[2]-$bbox[0])/2.0 - ($bbox[2]-$bbox[4])/2.0;         // deviation left-right
           
$dy = ($bbox[3]-$bbox[1])/2.0 + ($bbox[7]-$bbox[1])/2.0;        // deviation top-bottom
           
            // new pivotpoint
           
$px = $x-$dx;
           
$py = $y-$dy;
           
            return
imagettftext($im, $size, $angle, $px, $py, $color, $fontfile, $text);
        }

?>

Big up
Phil

Paul Reinheimer (20-Sep-2004 11:33)

If you compiled PHP yourself but get an error:
Fatal error: Call to undefined function imagettftext().

You need to compile PHP with more options.

--with-gd
--enable-gd-native-ttf
--with-png
--with-zlib-dir=/usr/local/lib/zlib-1.2.1
--with-ttf
--with-jpeg-dir=/usr/local/lib/jpeg-6b/
--with-freetype-dir=/usr/local/lib/freetype-2.1.9/
--with-xpm-dir=/usr/X11R6/

The next set deal with setting up GD, and the appropriate options. Just enabling GD, ttf, png & jpeg is NOT enough. You also need Freetype and XPM.

plusplus7 at hotmail dot com (15-Jul-2004 09:37)

If you are getting all rectangles instead of text, it may well mean that your ttf font is not opentype, particularly if it is an older freeware one. This requirement didn't exist in older versions so you may find that your font stops working after you upgrade. To fix this problem, try downloading the free MS Volt utility. From there, open your font file, and then click on Compile, and resave.

(02-Dec-2002 07:13)

If you have an older version of the GD library, but wish to use a font file which has spaces in the path, you should convert the path into DOS style names. This will only work on windows.

For example:
C:\reallylongpath\reallylongpath\font.ttf
Would become:
C:\really~1\really~1\font.ttf