Creating Image Thumbnails using PHP and ImageMagick

by Chadwick Wood
January 12th, 2009

Last month I wrote a post on using Photoshop and Javascript to generate thumbnails. That's useful if you have to process a bunch of images for a website you're making, but what if you want to have a function on your website that accepts image uploads and then dynamically generates thumbnails? There's a lot that goes into that, but today I'm going to provide a basic PHP function (using ImageMagick) that gets the image processing part of the job done. I'll give the code, then go through it:

define('THUMB_WIDTH', 60);
define('THUMB_HEIGHT', 80);
define('MAGICK_PATH','/usr/local/bin/');

function makeThumbnail($in, $out) {
    $width = THUMB_WIDTH;
    $height = THUMB_HEIGHT;
    list($w,$h) = getimagesize($in);

    $thumbRatio = $width/$height;
    $inRatio = $w/$h;
    $isLandscape = $inRatio > $thumbRatio;

    $size = ($isLandscape ? '1000x'.$height : $width.'x1000');
    $xoff = ($isLandscape ? floor((($inRatio*$height)-$width)/2) : 0);
    $command = MAGICK_PATH."convert $in -resize $size -crop {$width}x{$height}+{$xoff}+0 ".
        "-colorspace RGB -strip -quality 90 $out";

    exec($command);
}

Those first 3 define's are the configuration for this function. The first two define the width and height, in pixels, of the thumbnails that will be generated. The other define specifies the path to ImageMagick's convert program.

Now, on to the function itself. I've called it "makeThumbnail" (appropriately), and it takes two parameters. $in is the path to the image file that's going to be processed, and $out is the path we want to save our thumbnail to. Simple enough. Next, the first 3 lines of the function:

    $width = THUMB_WIDTH;
    $height = THUMB_HEIGHT;
    list($w,$h) = getimagesize($in);

Those first two lines are just saving our configuration parameters into variables named $width and $height. The third line stores the width and height of the input image in the variables $w and $h, respectively. Next, our first little bit of math:

    $thumbRatio = $width/$height;
    $inRatio = $w/$h;
    $isLandscape = $inRatio > $thumbRatio;

$thumbRatio is the aspect ratio that our thumbnail will have. $inRatio is the aspect ratio of the input image. We then compare these to figure out whether the input image is landscape or portrait oriented, with respect to the thumbnail we're going to generate. We want to figure this out because we're going to (most likely) do some cropping when generating our thumbnail, and how we crop the picture will depend on its orientation. And now here's where the magic(k) happens:

    $size = ($isLandscape ? '1000x'.$height : $width.'x1000');
    $xoff = ($isLandscape ? floor((($inRatio*$height)-$width)/2) : 0);
    $command = MAGICK_PATH."convert $in -resize $size -crop {$width}x{$height}+{$xoff}+0 ".
        "-colorspace RGB -strip -quality 90 $out";

The $size and $xoff variables hold the values that will be passed to convert to appropriately resize and crop the image. The logic is written such that portrait images will have their bottom cropped off to fit the proportions of the thumbnail. Landscape images will have equal amounts of left and right side cropped off. "-colorspace RGB" converts the image to the RGB colorspace, which is useful if you're using this function to process uploaded images from a web form... sometimes you'll get images that are using CMYK, and if you don't convert to RGB colorspace, you get larger, sometimes undisplayable, images. "-strip" strips out the color profile information, which most browsers don't pay attention to anyway (again, this function is web-oriented), so stripping it out just helps reduce your file size. "-quality 90" specifies the compression (quality) value for output. I find that using a value of 90 gives good-looking images that are still pretty small in file size. And to finish out:

    exec($command);

The last line executes the command we've constructed. Any questions? Use the comment form below.