Problem
You want to create scaled-down thumbnail images.
Solution
Use the ImageCopyResampled() function, scaling the image as needed.
To shrink proportionally:
$filename = __DIR__ . '/php.png';
$scale = 0.5; // Scale
// Images
$image = ImageCreateFromPNG($filename);
$thumbnail = ImageCreateTrueColor(
ImageSX($image) * $scale,
ImageSY($image) * $scale);
// Preserve Transparency
ImageColorTransparent($thumbnail,
ImageColorAllocateAlpha($thumbnail, 0, 0, 0, 127));
ImageAlphaBlending($thumbnail, false);
ImageSaveAlpha($thumbnail, true);
// Scale & Copy
ImageCopyResampled($thumbnail, $image, 0, 0, 0, 0,
ImageSX($thumbnail), ImageSY($thumbnail),
ImageSX($image), ImageSY($image));
// Send
header('Content-type: image/png');
ImagePNG($thumbnail);
ImageDestroy($image);
ImageDestroy($thumbnail);
To shrink to a fixed-size rectangle:
// Rectangle Version
$filename = __DIR__ . '/php.png';
// Thumbnail Dimentions
$w = 50; $h = 20;
// Images
$original = ImageCreateFromPNG($filename);
$thumbnail = ImageCreateTrueColor($w, $h);
// Preserve Transparency
ImageColorTransparent($thumbnail,
ImageColorAllocateAlpha($thumbnail, 0, 0, 0, 127));
ImageAlphaBlending($thumbnail, false);
ImageSaveAlpha($thumbnail, true);
// Scale & Copy
$x = ImageSX($original);
$y = ImageSY($original);
$scale = min($x / $w, $y / $h);
ImageCopyResampled($thumbnail, $original,
0, 0, ($x - ($w * $scale)) / 2, ($y - ($h * $scale)) / 2,
$w, $h, $w * $scale, $h * $scale);
// Send
header('Content-type: image/png');
ImagePNG($thumbnail);
ImageDestroy($original);
ImageDestroy($thumbnail);
Discussion
Thumbnail images allow you to quickly display a large number of photos in a small amount of space. The hardest part is knowing the best algorithm to scale or crop (or both) when your original pictures may be a wide variety of sizes and ratios.
The entire image is preserved when you shrink proportionally; however, this works best when all your pictures are about the same size and shape. Otherwise, you risk an unwieldy layout and pictures that are oddly shaped.
Another option is shrinking to a fixed size. This simplifies laying out the thumbnails, but when your ratio doesn’t match the source ratio, you end up with very small pictures. This recipe compensates by cropping out the largest proportional rectangle from the image’s center.
Figure Iguana scaled and cropped
The two algorithms are similar: first, you load in the original and create the thumbnail canvas; then you adjust the thumbnail to preserve the transparencies; next you calculate the parameters to pass to the ImageCopyResampled() function, which does the work of scaling the original image to the new size and copying it to the thumbnail canvas; finally, you save the thumbnail as a PNG.
When scaling to a proportional size, the thumbnail canvas is a factor of the original dimensions. The ImageSX() and ImageSY() functions allow you to dynamically extract that data:
$thumbnail = ImageCreateTrueColor(
ImageSX($image) * $scale,
ImageSY($image) * $scale);
Then, when it’s time to scale the image, you again use those two functions to specify the size of the images:
// Scale & Copy
ImageCopyResampled($thumbnail, $image, 0, 0, 0, 0,
ImageSX($thumbnail), ImageSY($thumbnail),
ImageSX($image), ImageSY($image));
The ImageCopyResampled() function takes 10 (yes, 10) arguments: the first two are the new and existing images. The next two are the x and y coordinates of where to put the new copied image; in this case, because you are overwriting the entire thumbnail, it’s always 0 and 0. The fifth and sixth arguments are the similar coordinates for the original image. Again, these are 0 and 0 because you’re scaling down the entire picture.
The final four arguments are another two pairs of coordinates. The first set are the width and height of the destination rectangle. The second are the same for the origin rectangle. Here, it’s the full canvas for both.
When scaling to a constant size, the thumbnail canvas is simple. It’s the width and height you choose:
$thumbnail = ImageCreateTrueColor($w, $h);
However, the code to scale and copy the image is more complicated:
// Scale & Copy
$x = ImageSX($original);
$y = ImageSY($original);
$scale = min($x / $w, $y / $h);
ImageCopyResampled($thumbnail, $original,
0, 0, ($x - ($w * $scale)) / 2, ($y - ($h * $scale)) / 2,
$w, $h, $w * $scale, $h * $scale);
First, you compute the smallest possible proportional rectangle that can fit inside the original image. You do that by finding the smaller of the two ratios of the original and thumbnail width and length. Now you know the size of the original rectangle you’re cropping out: $w * $scale and $h * $scale.
You could crop this from (0,0); however, the middle of the image is more likely to be representative of the whole. Therefore, find the offset within the original by subtracting out half of the scaled rectangle from the middle of the image: $x - ($w * $scale)) / 2 and ($y - ($h * $scale)) / 2.
With this information, ImageCopyResampled() can do its job, scaling and smoothing the image down to a pretty looking, but smaller, picture.
No comments:
Post a Comment