From a4556a327e3cc93185852a89f4ccc42f3f282bb0 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sun, 6 Nov 2016 08:37:52 +0100 Subject: [PATCH] Fix transparency handling in `GDImageAdapter::overlayImage()` --- .../image/adapter/GDImageAdapter.class.php | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php b/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php index 0410dc387e..10a8f12851 100644 --- a/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php +++ b/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php @@ -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; } /** -- 2.20.1