Create Dynamic Images with ImageMagick
By Michael Ross
This article was published by SitePoint on their homepage as a feature article, 2006-06-26, and in SitePoint Tech Times issue #142, 2006-06-28.
Digital images and graphics can make Websites more visually appealing and intuitive to navigate. They also can serve as far more concise ways to illustrate ideas, replacing the proverbial "thousand words" with a single picture. But almost all of the images on the Web suffer from a major weakness: they are static, i.e., limited to the size, resolution, colors, and other properties that they had when first loaded onto the Web server.
If your Website is like so many others, its images cannot be changed based upon the user's interaction with your site, regardless of how valuable that would be for your site's purposes. Even worse, the images can be changed by you only manually, requiring you to modify the images on your desktop computer and then re-upload them to your Web server.
Imagine the possibilities if you could make your Website change the appearance of its images, based upon input from you or any other authorized site visitor — not just an image's location on a Web page, but such properties as its size, resolution, borders, contrast, and dithering. Imagine being able to automatically rotate an image, flip it around, add tinting, or combine multiple images into a single one.
You could enlarge a street map, without having to store separate versions of that image on your server, one for every possible level of resolution that a user might request. You could shift the colors on an image for any site visitor who indicates that they have a particular form of color blindness. You could allow people to rotate aerial shots at will, or allow shoppers to change the tinting of art prints prior to purchase. You could even create an online image editor (e.g., GIFWorks.com).
Digital Image Magic
The key component for making this a reality on your site, is an image manipulation program controllable by code that can generate your Web pages. Even though this article uses PHP as the Web language, other languages — such as Perl and Ruby — can be used just as easily, provided that the image manipulation program being considered has an application programming interface (API) for the chosen language.
The image manipulation program used in this article is ImageMagick, for several reasons: It is more commonly supported by Web hosting services than any other; it is free; it runs on Windows and Linux platforms; it boasts two decades of continual enhancements and bug fixing; it is robust and powerful, offering extensive capabilities. Instructions for downloading and installing it can be found on the ImageMagick Website.
ImageMagick offers a wealth of powerful features; but all of them must be run on the command line. To gain access to that functionality from your PHP-powered Website, you will need to use an API (in the form of a PHP extension), such as MagickWand or imagick. Our examples here will utilize MagickWand.
Commands Other than "Abracadabra"
Regardless of what sort of operation you want to perform on an image, you first need to load that image into computer memory, and assign it to a MagickWand resource. The following PHP script loads a sample image file in the current directory, and then displays it in the Web browser:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 1: Original image
Once you have created that MagickWand resource and loaded an image, you can get information about the image, such as its dimensions:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); $width = MagickGetImageWidth( $resource ); $height = MagickGetImageHeight( $resource ); echo "Image size, in pixels, is: width $width x height $height" ?>
Figure 2: Image dimensions
Perhaps you would like to limit the physical dimensions of any image uploaded by a site visitor. This could be done by trimming all points of the image that lie outside of a rectangular sub-image, or by scaling the original image to fit inside of your specified bounding dimensions.
In the first case, let's say that your application needs to discard everything outside of the upper left 200x50 portion of the image. The upper left corner is considered offset (0,0). The following script will crop the sample image and then display it:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); MagickCropImage( $resource, 200, 50, 0, 0 ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 3: Cropped image
In the second case, let's say that your application calls for preserving the image as a whole, but scaling it down to a smaller size within a browser window, such as a maximum of 200x200, which this script will do:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); $resource = MagickTransformImage( $resource, '0x0', '200x200' ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 4: Scaled image
The image output above illustrates how the function MagickTransformImage() automatically preserves the image's aspect ratio when scaling.
Also note that MagickTransformImage() returns the transformed image as a new resource, which must be assigned to a variable to be preserved. In contrast, the previous function that we considered, MagickCropImage(), acted upon the resource variable passed to it, and returns a Boolean value. When writing your own MagickWand code, be sure to confirm the return type of each function, since any wrong assumption can waste time in debugging.
Perhaps an image has a border of 20 pixels on its left and right sides that you wish to eliminate, and you do not want to remove any pixels from the top or bottom. The following script will do just that:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); MagickShaveImage( $resource, 20, 0 ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 5: Trimmed image
Let's say you have an image in PNG format, and you would like to reformat it as a JPEG image. This script will work:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.png' ); MagickSetImageFormat( $resource, 'JPEG' ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 6: Image in PNG format
Images can also be rotated. Perhaps you would like to rotate the sample image above 45 degrees clockwise:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); MagickRotateImage( $resource, null, 45 ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 7: Image rotated
In the above script, we did not specify a color to be used for any newly exposed areas as a result of the rotation. But we can certainly do that:
<?php $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); MagickRotateImage( $resource, NewPixelWand( 'blue' ), 45 ); header( 'Content-Type: image/jpeg' ); MagickEchoImageBlob( $resource ); ?>
Figure 8: Image rotated, with blue background
Pull the Rabbit from the Hat
After you have made all of your desired changes to an image — or your PHP script has allowed your site visitor to do the same — you can display the finished image in your visitor's Web browser, as we have been doing above. Or, you can save the new image back to disk. Modifying our previous sample script:
<?php set_time_limit( 60 * 5 ); $resource = NewMagickWand(); MagickReadImage( $resource, 'image_1.jpg' ); MagickRotateImage( $resource, NewPixelWand( 'blue' ), 45 ); MagickWriteImage( $resource, 'new_image.jpg' ); ?>
You will notice an additional change to the above script: set_time_limit() sets the script timeout in seconds (in this case, to five minutes). This is a wise precaution if your script could be handling image files large enough to exceed the default script timeout for your Web server.
Learning the Tricks
If you wish to learn more about ImageMagick, the most promising resource is Michael Still's book The Definitive Guide to ImageMagick (ISBN 1590595904), published in December 2005, by Apress. It first explains how to install and configure ImageMagick, for several Linux distros, as well as Microsoft Windows. Most of the chapters cover basic image manipulation, compression, other metadata, ImageMagick tools, artistic transformations, other image transformations, and drawing commands. The book concludes with examples of utilizing ImageMagick from within programs written in Perl, C, Ruby, and PHP.
ImageMagick's Website offers some documentation: For each of the ten command-line tools within ImageMagick, the site has a page briefly explaining the tool's purpose, sample usage, and a list of all the command-line options. Each option is linked to its more detailed coverage on another page listing all of the options. In addition, there is a page devoted to the ImageMagick APIs available, for 11 different computer languages, including PHP, Perl, and Java.
To learn more about MagickWand and its commands, you can download the online manual, which is in HTML Help Compiled File format. If you elect to use imagick as your API instead, you will find fewer resources available, mainly comprising the sample code in the examples directory within the download package.
Programmers and Web developers usually find that looking at working code to be the most efficient way to learn a new technology. ImageMagick is no exception. The code snippets above illustrate all of the fundamental image operations. To see how to perform more sophisticated operations, take a look at Anthony Thyssen's examples of ImageMagick usage.
All Website owners and developers should already know that with PHP and other Web languages, their sites' pages can truly be made dynamic. Now they can do the same for their site's digital images and graphics.
Copyright © 2006 Michael J. Ross. All rights reserved.