Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Automated Creation Of Thumbnails With Php

Rated 4.16 (Ratings: 10)

Want more?

 
Picture of gvtulder

Gijs van Tulder

Member info

User since: 05 Feb 2002

Articles written: 7

If you are using a Content Management System to manage the content your site, you will run into some problems very early. Publishing images with your articles will soon be the only task not fully automated. You still have to create thumbnails, convert them to the right file type or resize them manually. When, in a later redesign of your site, the requested image size changes, you will have to convert them all over again. Web developers are lazy, so it is time for an easy-to-use solution.

The Idea

The idea is simple, yet powerful: supply an image once; retrieve it in all possible formats, sizes and file types. We will build a PHP script that will automate these actions for us. We would like to use the URL of the image to supply our wishes to the script. A possible URL could be:

http://www.example.com/img.php?f(3cb7f702a5967)+w(300)

Using this URL, we would like to get the image identified by 3cb7f702a5967, resized to a width of 300 pixels and the corresponding height.

The possibilities of our newly created script will be:

  1. resize an image to a given width and/or height, possibly preserve the aspect ration;
  2. accept new image sizes as absolute values, and as percentages of the original size;
  3. resize an image when width or height exceed a given limit;
  4. return the image as a PNG or JPEG-file.

What We Need

To build and use this script, you will need PHP compiled with the GD library and JPEG-support.

The Syntax

For telling our script what to return, we will use the following syntax. The arguments are delimited by one or more +-es. An example URL could be: http://www.example.com/img.php?f(3cb7f702a5967)+w(300)

CodeMeaning
f(3cb7f702a5967)The 13-character filename of the requested image. The images are saved without an extension, with the name defined by the current value of uniqid();. That way, new uploaded files will automatically have an unique id.
w(123) or w(10%)The wanted width of the returned image, either in absolute pixels or relative to the original size.
h(123) or h(10%)Same as above, but this is for the height of the image. When just one of the size-commands are given, the other size is automatically calculated, so that de aspect ratio of the image stays the same.
x(123)Defines the maximum width of the returned image. Resizing only takes place if the original width exceeds the given maximum. Only absolute values are accepted.
y(123)Same but for height.
t(png jpg)Defines the requested file type of the image. If no type is given, the image is returned as the original saved type.
q(100)Only for JPEG. Asks for a specific quality of the returned image. Quality can vary from 0 to 100.

The Script

Now that we have defined the syntax of the script, it is time to take a closer look at the actual code.

Checking the arguments

First of all, the given arguments are read from the query string by a simple preg. The regular expression returns all possible tags. Then the tags have to be checked for incorrect values. Defining an array of possible tags and corresponding regular expressions, is an easy way to check the tags in a for-loop. The checked and correct tags are saved in an associative array for later use. As a last check, the script verifies that a filename is given and that that file really does exist.

// define the base image dir

$base_img_dir = "./img/";

// find tags

preg_match_all("/\+*(([a-z])\(([^\)]+)\))\+*/", $QUERY_STRING,

$matches, PREG_SET_ORDER);

// empty array and set regular expressions for the check

$tags = array();

$check = array( "f" => "[0-9a-zA-Z]{13}",

"w" => "[0-9]+%?",

"h" => "[0-9]+%?",

"x" => "[0-9]+",

"y" => "[0-9]+",

"t" => "jpg png",

"q" => "1?[0-9]{1,2}" );

// check tags and save correct values in array

for ($i=0; $i < count($matches); $i++) {

if (isset($check[$matches[$i][2]])) {

if (preg_match('/^('.$check[$matches[$i][2]].')$/',

$matches[$i][3])) {

$tags[$matches[$i][2]] = $matches[$i][3];

}

}

}

function notfound() {

header("HTTP/1.0 404 Not Found");

exit;

}

// check that filename is given

if (!isset($tags["f"])) {

notfound();

}

// check if file exists

if (!file_exists($base_img_dir.$tags["f"])) {

notfound();

}

Loading the Image

The next step is the actual loading of the image. The getimagesize(); function is used to determine the file type, and then the correct method is used to load the image. In case the requested type of the returned image is not given, the file type of the original image is set as a default.

// retrieve file info

$imginfo = getimagesize($base_img_dir.$tags["f"]);

// load image

switch ($imginfo[2]) {

case 2: // jpg

$img_in = imagecreatefromjpeg($base_img_dir.$tags["f"]) or notfound();

if (!isset($tags["t"])) {

$tags["t"] = "jpg";

}

break;

case 3: // png

$img_in = imagecreatefrompng($base_img_dir.$tags["f"]) or notfound();

if (!isset($tags["t"])) {

$tags["t"] = "png";

}

break;

default:

notfound();

}

Possible resize

The most important part of the script is, of course, the resize. First, we have to look whether or not a resize is needed. When width or height tags are given, the new width and height are calculated using the size of the original image. The new size is used to copy the original image to the new, resized instance.

// check for maximum width and height

if (isset($tags["x"])) {

if ($tags["x"] < imagesx($img_in)) {

$tags["w"] = $tags["x"];

}

}

if (isset($tags["y"])) {

if ($tags["y"] < imagesy($img_in)) {

$tags["h"] = $tags["y"];

}

}

// check for need to resize

if (isset($tags["h"]) or isset($tags["w"])) {

// convert relative to absolute

if (isset($tags["w"])) {

if (strstr($tags["w"], "%")) {

$tags["w"] = (intval(substr($tags["w"], 0, -1)) / 100) *

$imginfo[0];

}

}

if (isset($tags["h"])) {

if (strstr($tags["h"], "%")) {

$tags["h"] = (intval(substr($tags["h"], 0, -1)) / 100) *

$imginfo[1];

}

}

// resize

if (isset($tags["w"]) and isset($tags["h"])) {

$out_w = $tags["w"];

$out_h = $tags["h"];

} elseif (isset($tags["w"]) and !isset($tags["h"])) {

$out_w = $tags["w"];

$out_h = $imginfo[1] * ($tags["w"] / $imginfo[0]);

} elseif (!isset($tags["w"]) and isset($tags["h"])) {

$out_w = $imginfo[0] * ($tags["h"] / $imginfo[1]);

$out_h = $tags["h"];

} else {

$out_w = $tags["w"];

$out_h = $tags["h"];

}

// new image in $img_out

$img_out = imagecreate($out_w, $out_h);

imagecopyresized($img_out, $img_in, 0, 0, 0, 0, imagesx($img_out),

imagesy($img_out), imagesx($img_in), imagesy($img_in));

} else {

// no resize needed

$img_out = $img_in;

}

Returning the image

The last step in our script is the actual returning of the image. The image and corresponding headers are returned as set in the query string. If the wanted type is not given, the image is returned as the original type of the saved file.

// check for a given jpeg-quality, otherwise set to default

if (!isset($tags["q"])) {

$tags["q"] = 75;

}

// returning the image

switch ($tags["t"]) {

case "jpg":

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

imagejpeg($img_out, "", $tags["q"]);

exit;

case "png":

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

imagepng($img_out);

exit;

default:

notfound();

}

What We Did

Now we have a script that fulfils the tasks we described above. Images are uploaded once and can be resized to whatever you want, without manual action. For the editors, the users of your CMS, uploading images is very simple. They upload the file in the size and type they want, and the script takes care of the resizing and converting. Without more work, your site can show thumbnails in many different sizes. If you, in the near future, would like to redesign your site, it is easy to get a new image size, without having to resize your whole archive.

The complete script discussed above, is available for download here. A demo of the script is running here, change the arguments in the query string to try the different commands like w() and t().

Where to go from here

Some thoughts about possible extensions of this script:

  • Enabling GIF-output. Using the command-line pngtopnm and pmmtogif programs, you can convert PNG-images to GIF on the fly. That way, you do not have to worry about older browsers not supporting the PNG-format.
  • Uploading of files in more formats. For the users of your CMS, it would be very easy if they could upload images as GIF, Windows bitmaps and TIFF. Using open source conversion utilities, you can still save these images as PNG of JPEG after uploading.
  • Using normal filenames for the images. Filenames generated with uniqid(); are easy and unique, but not very descriptive.
  • Saving file information like default ALT-tags in a database. You can easily find images for use in articles.

Gijs van Tulder is a Dutch student. He likes to play with all things web related and fancies himself as a part-time amateur web developer.

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.org Evolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.