The random eclecticisms of loonytoons

Creating title images on the fly

I was recently working on a site where the main page headings where required to display in fluxfont (to match some images / icons, plus it looks prettier too). Now this is not a regular font that everyone has installed on their machines, so I needed to come up with some way to display the text in the right font without requiring anyone to download the font themselves.

There are font replacement options out there, such as sIFR and cufon, but these are not guaranteed 100% browser compatible and there is a bit of a grey area regarding the licensing of these fonts (Jon Tan talks a bit about this in his article about font-face). So rightly or wrongly I decided to stay clear of these methods for now and go for an alternative option.

Creating images on the fly using a text string

This method requires the gd and free type libraries to be installed. You can see whether they are or not by looking at phpinfo(), and if you can’t see them referenced then you’ll need to download and install them.

The idea here is to use a php file to manipulate a text string into an image which will then be output to the page.

So first I need to create the php file that will create my image:

<?php

$text = isset($_GET['text']) ? trim($_GET['text']) : 'test';  //set text to use
$font = './fluxrg_.ttf';  //set font, for ease in this example the font file is in the same folder as the php script

//find size of text

$bbox = imagettfbbox(40, 0, $font, $text); //returns array of the corner positions of the text bounding box, see php.net for more info

$width = ($bbox[4] - $bbox[6]) + 10; //You can then work out width of image you need to create

$image = imagecreatetruecolor($width, 50); //create the image. I've specified a fixed height

//setup colour definitions
$white = imagecolorallocate($image,255,255,255);  //for the string
$black = imagecolorallocate($image,0,0,0); // for the background

//change the background to transparent
imagecolortransparent($image, $black);  //imagecreatetruecolor creates an image with a black background whereas I require transparent
imagettftext($image,40,0,10,40,$white,$font,$text); //this sets the text in the image, along with size, angle, position, colour and font, see php.net for more info

//display image and then destroy it
imagepng($image);
imagedestroy($image);

header("Content-type: image/png"); // so browser knows the output is an image rather than html

?>

Then in the script where you want this image to actually display, add this:

<img src="image_create.php?text=description">

where image_create.php is the php file you have just created, and ‘description’ is the text that you want converting into an image.

Caching the images

(many thanks to Binary Kitten for pointing me in the right direction with the image caching).

You’ll also want to cache the images you create, to save on performance. Certainly in my case where I’m using them to create page headings, as these probably aren’t going to change very much so there is no point recreating them everytime you visit the page.

So you need to setup an image cache folder, such as images/my_cache.

Then change the php file you’ve just created as follows:

<?php

$regenerate = TRUE; //set the default action

$text = isset($_GET['text']) ? trim($_GET['text']) : 'test';
$filename = $text != '' ? md5($text).'.png' : 'null.png'; //set the filename based on the text required. 
/* I've used md5 to counter any problems with spaces and other characters (maybe not the best way, it does lead to unreadable filenames but it works).*/
$location = $_SERVER['DOCUMENT_ROOT']."images/my_cache/"; //set the location of your image cache folder

$font = './fluxrg_.ttf';

//if the filename already exists and has a modified date within the last 2 weeks then don't recreate the image.

if(file_exists($location.$filename) && filemtime($location.$filename) >= strtotime("-14 days"))
{
$regenerate = FALSE;
}

//if regeneration is required then recreate the image and save to the image cache folder

if($regenerate == TRUE)
{
//find size of text
$bbox = imagettfbbox(40, 0, $font, $text);
$width = ($bbox[4] - $bbox[6]) + 10;

//create image
$image = imagecreatetruecolor($width, 50);

//setup colour definitions
$white = imagecolorallocate($image,255,255,255);
$black = imagecolorallocate($image,0,0,0);

//change the background to transparent
imagecolortransparent($image, $black);

//set text
imagettftext($image,40,0,0,40,$white,$font,$text);

//display images and destroy
imagepng($image, $location.$filename); //the second parameter outputs the image to a file
imagedestroy($image);
}

//this function sets the modified date

function setModifiedDate($contentDate) {
$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;

if ($ifModifiedSince && strtotime($ifModifiedSince) >= $contentDate) {
header('HTTP/1.0 304 Not Modified');
exit; // stop processing
}

$lastModified = gmdate('D, d M Y H:i:s', $contentDate) . ' GMT';
header('Last-Modified: ' . $lastModified);
}

//set the headers

clearstatcache();
setModifiedDate(filemtime($location.$filename)); //use the files modification time to set the the last-modified header
header("Content-type: image/png");
header("Cache-Control: must-revalidate");
header("Expires: ".gmdate('D, d M Y H:i:s',strtotime("+14 days")) . ' GMT');
ob_clean();
flush();
readfile($location.$filename); //reads the file from the image cache folder
?>

You should now have a working image cache setup that’ll really help the performance of your page, while allowing you to use fancy fonts easily. This is only really recommended for small amounts of text, such as for page headings as otherwise it can be slow, but it does work well for this purpose.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *