News Archive
PhpRiot Newsletter
Your Email Address:

More information


Note: This article was originally published at Planet PHP on 17 December 2010.
Planet PHP

Many of us have had the pleasure of building a web application that requires the automated building of thumbnails from images that are uploaded at runtime. Thumbnails are hardly the stuff of Nobel laureates, but they're an uncommon enough annoyance that implementing code to produce them seems like a fresh experience each time.

The easiest way to produce thumbnails for a site is to use a pre-built library designed for that purpose. There are a few decent libraries for this, including the PHP Thumbnailer Class, which provides dead-simple ways to manipulate images. Whether used as library code, or as a plugin to other software, this type of library will often do even more than produce thumbnails; it may add watermarks and easily enable programmatic rotation of the output image.

Using the PHP Thumbnailer Class to create thumbnails is simple:

include_once('libs/'); $imagefile = dirname(__FILE__) . '/sample.jpg'; PhpThumbFactory::create($imagefile)-resize(100,100)-show();

This code creates a thumbnail object that contains the source image, resizes it to fit entirely inside a 100A100 area, and then dumps it to the browser with the correct headers.

There is another very handy method, adaptiveResize(), that will resize the image as closely as possible to the provided dimensions, then crop the image from the center so that it fills the entire requested size.

The difference in these two images, apart from the cropped area, is the result of choosing which edge of the image the algorithm uses to resize it. In the case of resize(), the source image is resized so that its height fits inside the output area. In the case of adaptiveResize(), the source image is resized so that its width fits inside the output area.

To simplify further examples, I'll show only the code that is like resize(), in that the output image is equal to or smaller than the provided dimensions, and doesn't need to be cropped. To create code like adaptiveResize(), you would simply resize the image by the opposite side and use a cropping method on the result.

Regardless of which style of thumbnail your application requires, which side you choose is ultimately determined using a comparison of aspect ratios.

Understanding aspect ratios

If you search for a function that produces thumbnails to add to your application, you'll likely encounter quite a few that simply do it wrong. They'll calculate the size of the thumbnail based only on one dimension of the original image, or base the output size solely on the orientation of the original image. This is incorrect, since it will often leave some thumbnail images incorrectly cropped.

To determine which dimension of the original image to use as the base for resizing, you need to compare the aspect ratio of the original to the aspect ratio of the thumbnail.

The aspect ratio of an image is the ratio of its width to its height. The actual value of the ratio is unimportant, but the comparison of the ratios of the original image to the thumbnail image yields the correct dimension to use for resizing.

Consider these two images:

The top source image has an aspect ratio of 2/3. This is easily expressed as a decimal by dividing the width in pixels by the height in pixels, (66 A 100) a... 0.66. The bottom source image has an aspect ratio of 3/2, or (100 A 66) a... 1.5.

For both images, the thumbnail output size is an atypical vertical strip. If you're anything like me, the atypical is usually how you end up writing custom thumbnail routines in the first place. Still, the aspect ratio of 1/2 can be computed the same way, (50 A 100) = 0.5.

The surprise is that in both cases, the aspect ratio of the source image is larger than the aspect ratio of the thumbnail, therefore they should both be resized so that their width matches the width of the thumbnail, with the height reduced in equal proportion:

// Original values obtained from the top image // can come from getimagesize(), imagesx()/imagesy(), or similar $source_width = 66; $source_height = 100; $thumbnail_width = 50; $thumbnail_height = 100; // Compute aspect ratios $source_ar = $source_width / $source_height; $thumbnail_ar = $thumbnail_width / $thumbnail_height; // Compute the output width and height based on the // comparison of aspect ratios if ($source_ar $thumbnail_ar) { // Use the thumbnail width $output_width = $thumbnail_width; $output_height = round($original_height

Truncated by Planet PHP, read more at the original (another 3528 bytes)