2

The following code I use is to merge a source png to a destination png with 50% opacity to make it look stitched. The code works fine but the merge function merges the file to the transparent areas of destination too. Is there any way to merge the source to the non-transparent areas only?

<?php
  $src = imagecreatefrompng( 'http://dev.syntrio.in/arshad/project/test/texture.png' );
  $dst = imagecreatefrompng( 'https://upload.wikimedia.org/wikipedia/en/3/34/Gmail_Logo.png' );
  $w = imagesx( $dst );
  $h = imagesy( $dst ); 

  header( 'Content-type: image/png' );

  imagealphablending($dst, false);
  imagesavealpha($dst, true);

  imagecopymerge( $dst, $src, 0, 0, 0, 0, $w, $h, 50 );

  imagepng( $dst );

  imagedestroy( $src );
  imagedestroy( $dst );
?>
arshad
  • 883
  • 7
  • 30

2 Answers2

1

imagecopymerge function was never meant to support alpha channel. Hope it helps someone:

<?php 
/** 
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge(); 
* by Sina Salek 
* 
* Bugfix by Ralph Voigt (bug which causes it 
* to work only for $src_x = $src_y = 0. 
* Also, inverting opacity is not necessary.) 
* 08-JAN-2011 
* 
**/ 
    function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){ 
        // creating a cut resource 
        $cut = imagecreatetruecolor($src_w, $src_h); 

        // copying relevant section from background to the cut resource 
        imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h); 

        // copying relevant section from watermark to the cut resource 
        imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h); 

        // insert cut resource to destination image 
        imagecopymerge($dst_im, $cut, $dst_x, $dst_y, 0, 0, $src_w, $src_h, $pct); 
    } 

?>

Source: PHP Manual - imagecopymerge.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
0

Another solution from a php developer (takes less memory, but is slower)

<?php 
/** 
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge(); 
* This is a function like imagecopymerge but it handle alpha channel well!!! 
**/ 

// A fix to get a function like imagecopymerge WITH ALPHA SUPPORT 
// Main script by aiden dot mail at freemail dot hu 
// Transformed to imagecopymerge_alpha() by rodrigo dot polo at gmail dot com 
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); 
} 

// USAGE EXAMPLE: 
$img_a = imagecreatefrompng('image1.png'); 
$img_b = imagecreatefrompng('wm2.png'); 

// SAME COMMANDS: 
imagecopymerge_alpha($img_a, $img_b, 10, 10, 0, 0, imagesx($img_b), imagesy($img_b),50); 

// OUTPUT IMAGE: 
header("Content-Type: image/png"); 
imagesavealpha($img_a, true); 
imagepng($img_a, NULL); 
?>

Source: a comment on PHP Manual - imagecopymerge.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
  • I have tried this before. The problem with all these are the extra area of the destination image. Those transparent area also gets merged with the source file. – arshad Sep 10 '15 at 06:48
  • @arshad Oh, sorry! I've just realized what you want.. Maybe you need to preprocess the source image masking it with the destination image to make it of the same shape. I mean something like this: http://stackoverflow.com/questions/7203160/php-gd-use-one-image-to-mask-another-image-including-transparency – naXa stands with Ukraine Sep 10 '15 at 07:55
  • Or http://stackoverflow.com/questions/10926712/masking-one-image-against-another-using-php-gd – naXa stands with Ukraine Sep 10 '15 at 07:56