Resizing images with correct gamma using PHP and GD

by Sander Marechal

A short while ago Ty W posted an interesting question on StackOverflow. Apparently, most graphics software cannot scale images the right way. Usually it's hard to notice the flaw but the linked article does a great job of explaining the problem.

PHP's GD library suffers from the same issue, but Ty discovered that the sample PHP program provided with the article did not work on partially transparent images. After a couple of hours of fiddling I managed to get a working solution.

Apparently, the imagegammacorrect() function in PHP deals badly with images that have an alpha channel. I suspect that it tries to apply the same calculation to the alpha channel that it applies to the red, green and blue channels. To work around this, my solution splits the aplha channel from the original image. The alpha channel is resampled regularly while the red, green and blue channels are resampled using gamma correction.

Here's the code.

  1. <?php
  2.  
  3. // Load image
  4. $image = imagecreatefrompng($path_to_image);
  5.  
  6. // Create destination
  7. $resized_image = imagecreatetruecolor($new_width, $new_height);
  8. imagealphablending($resized_image, false); // Overwrite alpha
  9. imagesavealpha($resized_image, true);
  10.  
  11. // Create a separate alpha channel
  12. $alpha_image = imagecreatetruecolor($width, $height);
  13. imagealphablending($alpha_image, false); // Overwrite alpha
  14. imagesavealpha($alpha_image, true);
  15.  
  16. for ($x = 0; $x < $width; $x++) {
  17.     for ($y = 0; $y < $height; $y++) {
  18.         $alpha = (imagecolorat($image, $x, $y) >> 24) & 0xFF;
  19.         $color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
  20.         imagesetpixel($alpha_image, $x, $y, $color);
  21.     }
  22. }
  23.  
  24. // Resize image to destination, using gamma correction
  25. imagegammacorrect($image, 2.2, 1.0);
  26. imagecopyresampled($resized_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  27. imagegammacorrect($resized_image, 1.0, 2.2);
  28.  
  29. // Resize alpha channel
  30. $alpha_resized_image = imagecreatetruecolor($width, $height);
  31. imagealphablending($alpha_resized_image, false);
  32. imagesavealpha($alpha_resized_image, true);
  33.  
  34. imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  35.  
  36. // Copy alpha channel back to resized image
  37. for ($x = 0; $x < $new_width; $x++) {
  38.     for ($y = 0; $y < $new_height; $y++) {
  39.         $alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
  40.         $rgb = imagecolorat($resized_image, $x, $y);
  41.         $r = ($rgb >> 16 ) & 0xFF;
  42.         $g = ($rgb >> 8 ) & 0xFF;
  43.         $b = $rgb & 0xFF;
  44.         $color = imagecolorallocatealpha($resized_image, $r, $g, $b, $alpha);
  45.         imagesetpixel($resized_image, $x, $y, $color);
  46.     }
  47. }
  48.  
  49. // Write resized image
  50. imagepng($resized_image, $path_to_resized_image);
  51.  
  52. // Clean-up
  53. imagedestroy($image);
  54. imagedestroy($resized_image);
  55. imagedestroy($alpha_image);
  56. imagedestroy($alpha_resized_image);
  57.  
  58. ?>
  59.  
  60. <p>I hope this is of help to other people as well!</p>
Creative Commons Attribution-ShareAlike

Comments

Nobody has posted any comments yet.

Post a new comment

Registration is not required to post comments, but cookies must be enabled. One of the advantages of registration is that you can edit your comments later on (editing not yet implemented). You can register or login here.




Your e-mail address will not be published, but your website URL will. All links that you post will tagged rel="nofollow" to throw off spammers. You are allowed to use the following XHTML tags in your comment: <em> <strong> <u> <b> <i> <strike> <blockquote> <big> <small> <ul> <ol> <li> <a href=""> <pre> <code> <tt> <br>. Please allow up to 60 second processing time after you post a comment. Our spam filters may take some time.