protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte) { // generate images $img = imagecreatefrompng($file); if ($img === false) { return; } // FIXME The pixel transformation doesn't work well with 8bit PNGs $eight_bit = ($byte & 4) !== 4; $wpx = imagesx($img); $hpx = imagesy($img); imagesavealpha($img, false); // create temp alpha file $tempfile_alpha = tempnam($this->tmp, "cpdf_img_"); @unlink($tempfile_alpha); $tempfile_alpha = "{$tempfile_alpha}.png"; // create temp plain file $tempfile_plain = tempnam($this->tmp, "cpdf_img_"); @unlink($tempfile_plain); $tempfile_plain = "{$tempfile_plain}.png"; $imgalpha = imagecreate($wpx, $hpx); imagesavealpha($imgalpha, false); // generate gray scale palette (0 -> 255) for ($c = 0; $c < 256; ++$c) { imagecolorallocate($imgalpha, $c, $c, $c); } // Use PECL gmagick + Graphics Magic to process transparent PNG images if (extension_loaded("gmagick")) { $gmagick = new Gmagick($file); $gmagick->setimageformat('png'); // Get opacity channel (negative of alpha channel) $alpha_channel_neg = clone $gmagick; $alpha_channel_neg->separateimagechannel(Gmagick::CHANNEL_OPACITY); // Negate opacity channel $alpha_channel = new Gmagick(); $alpha_channel->newimage($wpx, $hpx, "#FFFFFF", "png"); $alpha_channel->compositeimage($alpha_channel_neg, Gmagick::COMPOSITE_DIFFERENCE, 0, 0); $alpha_channel->separateimagechannel(Gmagick::CHANNEL_RED); $alpha_channel->writeimage($tempfile_alpha); // Cast to 8bit+palette $imgalpha_ = imagecreatefrompng($tempfile_alpha); imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($imgalpha_); imagepng($imgalpha, $tempfile_alpha); // Make opaque image $color_channels = new Gmagick(); $color_channels->newimage($wpx, $hpx, "#FFFFFF", "png"); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYRED, 0, 0); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYGREEN, 0, 0); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYBLUE, 0, 0); $color_channels->writeimage($tempfile_plain); $imgplain = imagecreatefrompng($tempfile_plain); } elseif (extension_loaded("imagick")) { $imagick = new Imagick($file); $imagick->setFormat('png'); // Get opacity channel (negative of alpha channel) $alpha_channel = clone $imagick; $alpha_channel->separateImageChannel(Imagick::CHANNEL_ALPHA); $alpha_channel->negateImage(true); $alpha_channel->writeImage($tempfile_alpha); // Cast to 8bit+palette $imgalpha_ = imagecreatefrompng($tempfile_alpha); imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($imgalpha_); imagepng($imgalpha, $tempfile_alpha); // Make opaque image $color_channels = new Imagick(); $color_channels->newImage($wpx, $hpx, "#FFFFFF", "png"); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYRED, 0, 0); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYGREEN, 0, 0); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYBLUE, 0, 0); $color_channels->writeImage($tempfile_plain); $imgplain = imagecreatefrompng($tempfile_plain); } else { // allocated colors cache $allocated_colors = array(); // extract alpha channel for ($xpx = 0; $xpx < $wpx; ++$xpx) { for ($ypx = 0; $ypx < $hpx; ++$ypx) { $color = imagecolorat($img, $xpx, $ypx); $col = imagecolorsforindex($img, $color); $alpha = $col['alpha']; if ($eight_bit) { // with gamma correction $gammacorr = 2.2; $pixel = pow((127 - $alpha) * 255 / 127 / 255, $gammacorr) * 255; } else { // without gamma correction $pixel = (127 - $alpha) * 2; $key = $col['red'] . $col['green'] . $col['blue']; if (!isset($allocated_colors[$key])) { $pixel_img = imagecolorallocate($img, $col['red'], $col['green'], $col['blue']); $allocated_colors[$key] = $pixel_img; } else { $pixel_img = $allocated_colors[$key]; } imagesetpixel($img, $xpx, $ypx, $pixel_img); } imagesetpixel($imgalpha, $xpx, $ypx, $pixel); } } // extract image without alpha channel $imgplain = imagecreatetruecolor($wpx, $hpx); imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($img); imagepng($imgalpha, $tempfile_alpha); imagepng($imgplain, $tempfile_plain); } // embed mask image $this->addImagePng($tempfile_alpha, $x, $y, $w, $h, $imgalpha, true); imagedestroy($imgalpha); // embed image, masked with previously embedded mask $this->addImagePng($tempfile_plain, $x, $y, $w, $h, $imgplain, false, true); imagedestroy($imgplain); // remove temp files unlink($tempfile_alpha); unlink($tempfile_plain); }
protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte) { $img = imagecreatefrompng($file); if ($img === false) { return; } $eight_bit = ($byte & 4) !== 4; $wpx = imagesx($img); $hpx = imagesy($img); imagesavealpha($img, false); $tempfile_alpha = tempnam($this->tmp, "cpdf_img_"); @unlink($tempfile_alpha); $tempfile_alpha = "{$tempfile_alpha}.png"; $tempfile_plain = tempnam($this->tmp, "cpdf_img_"); @unlink($tempfile_plain); $tempfile_plain = "{$tempfile_plain}.png"; $imgalpha = imagecreate($wpx, $hpx); imagesavealpha($imgalpha, false); for ($c = 0; $c < 256; ++$c) { imagecolorallocate($imgalpha, $c, $c, $c); } if (extension_loaded("gmagick")) { $gmagick = new Gmagick($file); $gmagick->setimageformat('png'); $alpha_channel_neg = clone $gmagick; $alpha_channel_neg->separateimagechannel(Gmagick::CHANNEL_OPACITY); $alpha_channel = new Gmagick(); $alpha_channel->newimage($wpx, $hpx, "#FFFFFF", "png"); $alpha_channel->compositeimage($alpha_channel_neg, Gmagick::COMPOSITE_DIFFERENCE, 0, 0); $alpha_channel->separateimagechannel(Gmagick::CHANNEL_RED); $alpha_channel->writeimage($tempfile_alpha); $imgalpha_ = imagecreatefrompng($tempfile_alpha); imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($imgalpha_); imagepng($imgalpha, $tempfile_alpha); $color_channels = new Gmagick(); $color_channels->newimage($wpx, $hpx, "#FFFFFF", "png"); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYRED, 0, 0); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYGREEN, 0, 0); $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYBLUE, 0, 0); $color_channels->writeimage($tempfile_plain); $imgplain = imagecreatefrompng($tempfile_plain); } elseif (extension_loaded("imagick")) { $imagick = new Imagick($file); $imagick->setFormat('png'); $alpha_channel = clone $imagick; $alpha_channel->separateImageChannel(Imagick::CHANNEL_ALPHA); $alpha_channel->negateImage(true); $alpha_channel->writeImage($tempfile_alpha); $imgalpha_ = imagecreatefrompng($tempfile_alpha); imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($imgalpha_); imagepng($imgalpha, $tempfile_alpha); $color_channels = new Imagick(); $color_channels->newImage($wpx, $hpx, "#FFFFFF", "png"); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYRED, 0, 0); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYGREEN, 0, 0); $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYBLUE, 0, 0); $color_channels->writeImage($tempfile_plain); $imgplain = imagecreatefrompng($tempfile_plain); } else { $allocated_colors = array(); for ($xpx = 0; $xpx < $wpx; ++$xpx) { for ($ypx = 0; $ypx < $hpx; ++$ypx) { $color = imagecolorat($img, $xpx, $ypx); $col = imagecolorsforindex($img, $color); $alpha = $col['alpha']; if ($eight_bit) { $gammacorr = 2.2; $pixel = pow((127 - $alpha) * 255 / 127 / 255, $gammacorr) * 255; } else { $pixel = (127 - $alpha) * 2; $key = $col['red'] . $col['green'] . $col['blue']; if (!isset($allocated_colors[$key])) { $pixel_img = imagecolorallocate($img, $col['red'], $col['green'], $col['blue']); $allocated_colors[$key] = $pixel_img; } else { $pixel_img = $allocated_colors[$key]; } imagesetpixel($img, $xpx, $ypx, $pixel_img); } imagesetpixel($imgalpha, $xpx, $ypx, $pixel); } } $imgplain = imagecreatetruecolor($wpx, $hpx); imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx); imagedestroy($img); imagepng($imgalpha, $tempfile_alpha); imagepng($imgplain, $tempfile_plain); } $this->addImagePng($tempfile_alpha, $x, $y, $w, $h, $imgalpha, true); imagedestroy($imgalpha); $this->addImagePng($tempfile_plain, $x, $y, $w, $h, $imgplain, false, true); imagedestroy($imgplain); unlink($tempfile_alpha); unlink($tempfile_plain); }