Fix transparency handling in `GDImageAdapter::overlayImage()`
authorMatthias Schmidt <gravatronics@live.com>
Sun, 6 Nov 2016 07:37:52 +0000 (08:37 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 6 Nov 2016 07:37:52 +0000 (08:37 +0100)
wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php

index 0410dc387ed76f040a339b46fd3ef444968b9c2c..10a8f1285113e40de0ea5369a9915103b8411418 100644 (file)
@@ -390,9 +390,76 @@ class GDImageAdapter implements IImageAdapter {
                // fix PNG alpha channel handling
                // see http://php.net/manual/en/function.imagecopymerge.php#92787
                $cut = imagecreatetruecolor($overlayImage->getWidth(), $overlayImage->getHeight());
+               imagealphablending($cut, false);
+               imagesavealpha($cut, true);
+               
                imagecopy($cut, $this->image, 0, 0, $x, $y, $overlayImage->getWidth(), $overlayImage->getHeight());
                imagecopy($cut, $overlayImage->image, 0, 0, 0, 0, $overlayImage->getWidth(), $overlayImage->getHeight());
-               imagecopymerge($this->image, $cut, $x, $y, 0, 0, $overlayImage->getWidth(), $overlayImage->getHeight(), $opacity * 100);
+               
+               $this->imagecopymerge_alpha($this->image, $cut, $x, $y, 0, 0, $overlayImage->getWidth(), $overlayImage->getHeight(), $opacity * 100);
+       }
+       
+       /**
+        * `imagecopymerge` implementation with alpha support.
+        * 
+        * @see http://php.net/manual/en/function.imagecopymerge.php#88456
+        * 
+        * @param       resource        $dst_im         destination image resource
+        * @param       resource        $src_im         source image resource
+        * @param       integer         $dst_x          x-coordinate of destination point
+        * @param       integer         $dst_y          y-coordinate of destination point
+        * @param       integer         $src_x          x-coordinate of source point
+        * @param       integer         $src_y          y-coordinate of source point
+        * @param       integer         $src_w          source width
+        * @param       integer         $src_h          source height
+        * @param       integer         $pct            opacity percent
+        * @return      boolean
+        */
+       private function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct) {
+               if (!isset($pct)) {
+                       return false;
+               }
+               $pct /= 100;
+               // Get image width and height 
+               $w = imagesx($src_im);
+               $h = imagesy($src_im);
+               // Turn alpha blending off 
+               imagealphablending($src_im, false);
+               // Find the most opaque pixel in the image (the one with the smallest alpha value) 
+               $minalpha = 127;
+               for ($x = 0; $x < $w; $x++) {
+                       for ($y = 0; $y < $h; $y++) {
+                               $alpha = (imagecolorat($src_im, $x, $y) >> 24) & 0xFF;
+                               if ($alpha < $minalpha) {
+                                       $minalpha = $alpha;
+                               }
+                       }
+               }
+               // loop through image pixels and modify alpha for each 
+               for ($x = 0; $x < $w; $x++) {
+                       for ($y = 0; $y < $h; $y++) {
+                               // get current alpha value (represents the TANSPARENCY!) 
+                               $colorxy = imagecolorat($src_im, $x, $y);
+                               $alpha = ($colorxy >> 24) & 0xFF;
+                               // calculate new alpha 
+                               if ($minalpha !== 127) {
+                                       $alpha = 127 + 127 * $pct * ($alpha - 127) / (127 - $minalpha);
+                               }
+                               else {
+                                       $alpha += 127 * $pct;
+                               }
+                               // get the color index with new alpha 
+                               $alphacolorxy = imagecolorallocatealpha($src_im, ($colorxy >> 16) & 0xFF, ($colorxy >> 8) & 0xFF, $colorxy & 0xFF, $alpha);
+                               // set pixel with the new color + opacity 
+                               if (!imagesetpixel($src_im, $x, $y, $alphacolorxy)) {
+                                       return false;
+                               }
+                       }
+               }
+               // The image copy 
+               imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
+               
+               return true;
        }
        
        /**