Introduction
This is part of the Image resizing in PHP tutorial, in which we learn how to create thumbnails in PHP: Image Resizing in PHP (Thumbnail creation) . See this tutorial to find out about other ways to resize images.
If you're developing a content management for your website users and you want to rescale photos, here's how you can do it using only the basic gd2 extension.
To go through this tutorial, you should have PHP with the gd2 extension installed on your machine. If you're not sure you have it, here's Checking if your system has a PHP extension installed .
The whole source code
Let's begin by seeing the entire source code that takes care of this resizing an existing file:
<?php $originalFileName = 'source.jpg'; $targetFileName = 'source_thumbnail.jpg'; // We begin by defining a few constants which // impose some limits. define(MAX_ORIGINAL_FILE_SIZE, 1000000); define(MAX_ORIGINAL_FILE_WIDTH, 1600); define(MAX_ORIGINAL_FILE_HEIGHT, 1200); // Define the thumbnail constraints. The thumbnail will // be a rectangle included in these limits. define(MAX_TARGET_FILE_WIDTH, 160); define(MAX_TARGET_FILE_HEIGHT, 120); // The quality of the target filename. define(TARGET_QUALITY, 90); // Make sure it's a regular file, and that it's readable: if (!(is_file($originalFileName) && is_readable($originalFileName))) exit(sprintf('Not a readable file: %s', $originalFileName) . PHP_EOL); // Check for maximum file size if (filesize($originalFileName) > MAX_ORIGINAL_FILE_SIZE) exit(sprintf('File too large: %s', $originalFileName) . PHP_EOL); // Extract the file extension // Find out the file type depending on the extension: $fileExtension = null; $info = pathinfo($originalFileName); if (isset($info['extension'])) $fileExtension = $info['extension']; if (empty($fileExtension)) exit(sprintf('Could not determine file extension: %s', $originalFileName) . PHP_EOL); // Compute the type depending on the extension $type = strtolower($fileExtension); if ($type == 'jpg') $type = 'jpeg'; // $func is the gd2 function we will use $func = 'imagecreatefrom' . $type; // Check if the function exists if (!function_exists($func)) exit(sprintf('Unsuported image type: %s', $type) . PHP_EOL); // Create a new gd2 resource $gd2Original = $func($originalFileName); if (empty($gd2Original)) exit(sprintf('Invalid %s format in %s', $type, $originalFileName) . PHP_EOL); // Check the width and height $originalWidth = imagesx($gd2Original); $originalHeight = imagesy($gd2Original); if ($originalWidth > MAX_ORIGINAL_FILE_WIDTH || $originalHeight > MAX_ORIGINAL_FILE_HEIGHT) exit(sprintf('Image dimensions too large: %s width, ' . 'and %s height. Maximum supported are: ' . '%s width, and %s height', $originalWidth, $originalHeight, MAX_ORIGINAL_FILE_WIDTH, MAX_ORIGINAL_FILE_HEIGHT) . PHP_EOL); // Determine the scale ratio, a number between 0 and 1. // This is a value by which we will multiply the // original width and height to obtain the thumbnail // dimensions. $scale = null; // We define here the width and height we want the // thumbnail to have. It's possible to define either // the target width, the target height, or both of them. // In each case, the thumbnail will conform to the given // constraints. $boundWidth = MAX_TARGET_FILE_WIDTH; $boundHeight = MAX_TARGET_FILE_HEIGHT; if (empty($boundWidth) && empty($boundHeight)) exit('Neither one of the target width or target ' . 'height values were specified.'); else if (empty($boundWidth)) $scale = $boundHeight/$originalHeight; else if (empty($boundHeight)) $scale = $boundWidth/$originalWidth; else $scale = min($boundWidth/$originalWidth, $boundHeight/$originalHeight); if ($scale < 1) { $targetWidth = floor($scale * $originalWidth); $targetHeight = floor($scale * $originalHeight); $gd2Thumbnail = imagecreatetruecolor($targetWidth, $targetHeight); // Copy and resample into the thumbnail. imagecopyresampled($gd2Thumbnail, $gd2Original, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); } else { // No need to do anything - the image is already // within the defined thumbnail size constraints! $gd2Thumbnail = $gd2Original; } // Finally, write the thumbnail to a file. $func = 'image' . $type; if (function_exists($func)) $func($gd2Thumbnail, $targetFileName, TARGET_QUALITY);
Now, let's go through this source code step by step...
Defining some limits
We begin by specifying some limits as to how large of a picture our re-sampling script can handle. If we don't, then our script may fail in points we don't expect: the file may be too large, in which case it would fill the entire memory available to PHP.
To create maintainable code, make sure you define constants for every literal value you use in your code. To see more advice, check out Tips for increasing your PHP code maintainability
The first limits are the ones which constrain the maximum file size, and which keep the width and height of the original image file within some limits:
define(MAX_ORIGINAL_FILE_SIZE, 1000000); define(MAX_ORIGINAL_FILE_WIDTH, 1600); define(MAX_ORIGINAL_FILE_HEIGHT, 1200);
Then, the thumbnail maximum dimensions must be set up:
define(MAX_TARGET_FILE_WIDTH, 160); define(MAX_TARGET_FILE_HEIGHT, 120);
The TARGET_QUALITY value (between 1 and 100) determines the quality of the thumbnail image compression:
define(TARGET_QUALITY, 90);
Reading the image file with a gd function
Next, we're just going to check that the filename is readable, that it's a regular file, not a directory, and that it doesn't exceed the maximum allowed file size:
if (!(is_file($originalFileName) && is_readable($originalFileName))) exit(sprintf('Not a readable file: %s', $originalFileName) . PHP_EOL); // Check for maximum file size if (filesize($originalFileName) > MAX_ORIGINAL_FILE_SIZE) exit(sprintf('File too large: %s', $originalFileName) . PHP_EOL);
The next thing that we do is determine which gd function to use, depending on the file extension. gd has different functions for each file format. There's also a separate tutorial dealing with finding the file extension in PHP: Obtaining the the file extension out of a file name
$fileExtension = null; $info = pathinfo($originalFileName); if (isset($info['extension'])) $fileExtension = $info['extension']; if (empty($fileExtension)) exit(sprintf('Could not determine file extension: %s', $originalFileName) . PHP_EOL);
Next, we create a gd2 resource which holds a reference to the image file after it was read in memory.
Typically, we can use the following php functions to achieve this: imagecreatefromjpeg() , imagecreatefromgif() , and imagecreatefrompng() . We would like, depending on the file extension (which we have in the $fileExtension variable), to choose the appropriate function:
// Compute the type depending on the extension $type = strtolower($fileExtension); if ($type == 'jpg') $type = 'jpeg'; $func = 'imagecreatefrom' . $type;
After this, $func will contain the function name we want to call in order to read our image. Of course, there's a possibility that the image we are trying to read produces a function name that doesn't exist. For this reason, we must first check if the function exists before continuing:
if (!function_exists($func)) exit(sprintf('Unsuported image type: %s', $type) . PHP_EOL);
Now that we're sure that this function is defined, we will try to read the image file (or abort if the image format doesn't correspond to the actual file):
if (empty($gd2Original)) exit(sprintf('Invalid %s format in %s', $type, $originalFileName) . PHP_EOL);
Determining the scale
Next we would like to determine a ratio between the original image and the thumbnail image. For example, using the example values in the code below, a 1600 by 1200 image will be rescaled to 160 by 120, and the ratio will be 0.1.
First we use the imagesx() and imagesy() gd functions to determine the width and height of the original photo. Remember the MAX_ORIGINAL_FILE_WIDTH and MAX_ORIGINAL_FILE_HEIGHT from earlier? This is where they come into play. We will make sure the file that we create is within those bounds:
// Check the width and height $originalWidth = imagesx($gd2Original); $originalHeight = imagesy($gd2Original); if ($originalWidth > MAX_ORIGINAL_FILE_WIDTH || $originalHeight > MAX_ORIGINAL_FILE_HEIGHT) exit(sprintf('Image dimensions too large: %s width, ' . 'and %s height. Maximum supported are: ' . '%s width, and %s height', $originalWidth, $originalHeight, MAX_ORIGINAL_FILE_WIDTH, MAX_ORIGINAL_FILE_HEIGHT) . PHP_EOL);
Then we define the $boundWidth and $boundHeight variables. These are the maximum width, and height values. There are 3 use cases:
- $boundWidth and $boundHeight defined: the thumbnail will be a sub-rectangle of the boundWidth and boundHeight rectangle.
- Only $boundWidth defined: the thumbnail will be at most $boundWidth wide
- Only $boundHeight defined: the thumbnail will have at moust $boundHeight height.
$scale = null; $boundWidth = MAX_TARGET_FILE_WIDTH; $boundHeight = MAX_TARGET_FILE_HEIGHT; if (empty($boundWidth) && empty($boundHeight)) exit('Neither one of the target width or target ' . 'height values were specified.'); else if (empty($boundWidth)) $scale = $boundHeight/$originalHeight; else if (empty($boundHeight)) $scale = $boundWidth/$originalWidth; else $scale = min($boundWidth/$originalWidth, $boundHeight/$originalHeight);
Performing the actual resize
What we want to do next is obtain a new gd2 resource containing the re-sampled image. To do this, we determine the actual thumbnail width and height, then use the imagecopyresampled() function (Note that if the scale is larger or equal to 1, there is no resize needed):
if ($scale < 1) { $targetWidth = floor($scale * $originalWidth); $targetHeight = floor($scale * $originalHeight); $gd2Thumbnail = imagecreatetruecolor($targetWidth, $targetHeight); // Copy and resample into the thumbnail. imagecopyresampled($gd2Thumbnail, $gd2Original, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); } else { $gd2Thumbnail = $gd2Original; }
Writing the result to a file
Finally, we save the image to a file.
$func = 'image' . $type; if (function_exists($func)) $func($gd2Thumbnail, $targetFileName, TARGET_QUALITY);
Now you should be able to open the rescaled image in $targetFilename.
Please note that the code shown in this tutorial is by no means complete - it would have to be adapted to your specific situation, for example you may consider it as a starting point to defining a class which you can use to repeatedly rescale images, which may check if a thumbnail of the file already exists (and if it does, whether requires redrawing).