Handling Images with PHP

by Scott MacVicar (2008-07-07)
 

If you want user interaction on your website then you probably accept the upload of some media, including images. Within PHP there are two different libraries available that provide functionality for handling images, GD and the Imagick extension. This article takes a brief look at each of these libraries.

If you want user interaction on your website then you probably accept the upload of some media, including images. Within PHP there are two different libraries available that provide functionality for handling images. The first is GD which is based on libgd and the second is the Imagick PECL extension.

Which should I use?

Both libraries have their strengths and weaknesses. GD is tightly bundled with PHP and has been enabled by default since 4.3.2, so there is a good chance that any version of PHP you are going to use already has this enabled. Imagick is based on the ImageMagick library and provides similar functionality as well as a few helper functions to make things easier.

If you have deployable code and can't guarantee what will be available, then you have little choice but to support both libraries. For the purpose of this article I'll show code samples for both and I'll also assume that the image file is already uploaded to the server so just the image related parts can be shown.

Installing Imagick

If you are on a Debian based system you can simply install the php5-imagick package, however if you don't get a version 2 version of Imagick then you should install directly from PECL. You will need the imagemagick package.

When installing from PECL the imagemagick library is first required. Please note that the package name differs slightly depending on your OS, as documented below. Once installed, the PECL imagick package can be installed by running the command pecl install imagick.

OS Package Name
Redhat ImageMagick
Debian imagemagick
FreeBSD graphics/ImageMagick
MacPorts graphics/ImageMagick

Identifying Image Types

The functionality to provide image identification and metadata within the standard PHP package is getimagesize(). With this we can find out the image type and image dimensions. This function looks at the image data and reads the header information in order to obtain the desired information.

  1. <?php
  2. $information = getimagesize($path_to_image);
  3. ?>

An array is returned indexes of 0 and 1 being width and height respectively, and index 2 being the IMAGETYPE constant.

The equivalent imagick code looks like the following and provides slightly more information than the standard PHP equivalent.

  1. <?php
  2. $image = new Imagick();
  3. $image->pingImage($path_to_image);
  4. $information = $image->identifyImage();
  5. ?>

If successful, $information will contain width, height, type and some other basic information about the image. We use the pingImage method here so that imagick doesn't do more processing than it needs to.

EXIF Data

EXIF is a form of metadata that can be embedded directly within JPEG and TIFF images providing extra information and statistics. If the image was taken by a digital camera it will contain a great amount of potentially useful data.

The image shown contains the following EXIF data (among others):

  • Model -> NIKON D300
  • DateTime -> 2008:03:14 23:48:14
  • ExposureTime -> 10/600
  • FNumber -> 28/10
  • ISOSpeedRatings -> 200
  • GPSLatitudeRef -> N
  • GPSLatitude -> 45/1 30/1 4122/125
  • GPSLongitudeRef -> W
  • GPSLongitude -> 73/1 33/1 567/125
  • One of the most useful pieces of information here is a GPS location that could be use to plot the location an image was taken. This is a concept known as geotagging but requires a GPS module to be present on the camera.

In order to access the EXIF information in a standard PHP build, the exif module is required. This is a standard module that has no external dependencies so is usually enabled by default.

  1. <?php
  2. $exif_information = exif_read_data($path_to_image, 'EXIF');
  3. ?>

If successful, $exif_information will contain an array of EXIF tags, as specified by the second parameter to the exif_read_data function. There are other types of data that can be read such as a thumbnail and comments if available. The PHP manual contains more information about their usage at http://php.net/manual/en/function.exif-read-data.php.

  1. <?php
  2. $im = new Imagick($path_to_image);
  3. $ exif_information = $im->getImageProperties('exif:*');
  4. ?>

The imagick code is very similar to that of the standard PHP code as can be seen and again provides an array of EXIF data.

Changing Image Format/Resizing

Assuming you've performed some basic checks on an image there are a few things you might have to do to get it ready for use on your web site. This next section will cover changing an image format and resizing and the code to do both of these is very similar, as we will see.

GD currently supports 5 image types that can be both read and written; these are GIF, JPEG, PNG, WBMP and XBM. With PHP 5.3 and GD 2.1 there will also be support for five additional formats, TIFF, TGA, BMP, EXR and J2K (though some are read-only.)

With GD, images are read into a buffer and from this buffer format it can be written into any other format supported. Note that we have to pick the correct function to use, so getimagesize is useful in this case.

  1. <?php
  2. $image_information = getimagesize($path_to_image);
  3. /* Load image into buffer */
  4. switch ($image_information[2])
  5. {
  6.   case IMAGETYPE_GIF:
  7.     $image = imagecreatefromgif($path_to_image);
  8.     break;
  9.   case IMAGETYPE_JPEG:
  10.     $image = imagecreatefromjpeg($path_to_image);
  11.     break;
  12.  
  13.   case IMAGETYPE_PNG
  14.     $image = imagecreatefrompng($path_to_image);
  15.     break;
  16.   default:
  17.     echo “Unsupported Image Type”;
  18.     exit;
  19. }
  20. imagejpeg($image, $path_to_destination_image);
  21. imagedestroy($image);
  22. ?>

The above code would convert an image into a jpeg and save it back to the file system. If an image is to be resized then, a second smaller buffer would be required to copy the newly resized image to; assuming the image is now a jpeg we would use the following code.

  1. <?php
  2. $image = imagecreatefromjpeg($path_to_image);
  3. $max_width = 100;
  4. $ratio = $max_width / imagesx($image);
  5. $max_height = imagesy($image) * $ratio;
  6. $thumbnail = imagecreatetruecolor($max_width, $max_height);
  7. imagecopyresampled($thumbnail, $ image, 0, 0, 0, 0,
  8. $max_width, $max_height, imagesx($image), imagesy($image));
  9. imagejpeg($thumbnail, $path_to_thumbnail);
  10. imagedestroy($thumbnail);
  11. ?>

As we can see, there are some calculations involved to maintain the aspect ration of the current image. Once calculated, a new buffer image is created with these dimensions before the larger image is copied to this buffer. The function imagecopyresampled is used here as it tries to maintain as much of the detail as possible as it is resized. To do this, sacrifices performance unlike its cousin imagecopyresized.

The imagick equivalent of the previous two code samples is much smaller. This can be mainly attributed to the fact that the underlying ImageMagick library will automatically determine what sort of image it has. Although this is slightly slower than just “telling it,” it makes it easier when a new image format is added or removed from the library.

  1. <?php
  2. $imagick = new Imagick($path_to_image);
  3. $imagick->setImageFomat(‘jpeg');
  4. $imagick->writeImage($path_to_destination_image);
  5. ?>

Similarly the code for resizing an image is short and simple; there is a helper method called thumbnailImage that does resizing for you. It also does the calculation of the aspect ratio when one of the parameters passed in is null.

  1. <?php
  2. $imagick = new Imagick($path_to_image);
  3. $imagick->thumbnailImage(100, null);
  4. $imagick->writeImage($path_to_thumbnail);
  5. ?>

Exceptions

It should be noted that Imagick will throw an exception on errors; therefore you should wrap either particular methods or potentially all of the code in a “try /catch” block to handle this.

In a following article I'll cover some more image functions and some of the new features coming with GD 2.1 in PHP 5.3 and the forthcoming Imagick 2.2 release.

Scott is the lead developer of the SQLite3 extension and the ImageMagick PHP wrapper. He also helps with LibGD and the core in between.

Currently he is a developer at Jelsoft Enterprises in England, UK. Topics of interest at the moment are image manipulation and web application scalability with databases.

File under: art  gd  homepage  images  imagick  pecl  php 
 

Comments

Re: Handling Images with PHP by noman (2008-07-08 09:01:36 (America/Toronto))
You have some syntax errors with your code examples.  Specifically the Exif data with Image magick and later another one with Image Magick and a single-quote ;)

Good article though.
Visit the forum