Gga
Gga

Reputation: 4421

Merge transparent images in PHP

I am trying to layer a partially transparent PNG on top of another opaque PNG.

There are many example of how to do this across this site and the net, however with every version I try I seem to not be able to maintain the foreground image's transparency.

Currently the code looks like this:

 $image = imagecreatefrompng($_GET['fg']);
 $frame = imagecreatefrompng($_GET['bg']);

 imagealphablending($frame,true);
 imagecopymerge($image, $frame, 0, 0, 0, 0, 0, 100, 100);

 # Save the image to a file
 $output_file = 'preview-' . time() . '.png';

 imagepng( $image, $_SERVER['DOCUMENT_ROOT'] . '/share/' . $output_file );

Which produces an image made up of the foreground image with the transparent parts as white (or black).

Also I have tried this as seen in the image thumbnail generator, TimThumb, which produces the same output:

$canvas= imagecreatefrompng($_GET['bg']);

$overlay_gd_image = imagecreatefrompng( $_GET['fg'] );
$overlay_width = imagesx( $overlay_gd_image );
$overlay_height = imagesy( $overlay_gd_image );
imagealphablending($canvas, true );
imagecopy( $canvas, $overlay_gd_image, 0, 0, 0, 0, $overlay_width, $overlay_height);
imagealphablending($canvas, false );
imagesavealpha($canvas , true); 

imagepng($canvas, 'new.png');

I am running out of things to try and would be grateful if anyone could shed light on the problem.

Upvotes: 2

Views: 1644

Answers (2)

PepeNietnagel
PepeNietnagel

Reputation: 239

I had exactly the same issue. The solution for me was to use imagecopyresampled instead of imagecopymerge. This will preserve transparency for both images.

be aware of the slightly different parameters to pass

Upvotes: 0

Anni
Anni

Reputation: 15

The native imagecopymerge doesn't really work so well when it comes to transparent images. If you want to merge two PNG's together and not have the alpha channel get messed up, this function found on the manual page works like a charm for me and actually preserves transparency. I have been merging PNGs nonstop with this function and have not had a problem so I think it could solve yours. (Posted by "rodrigo dot polo at gmail dot com", so all credits to him/her.)

<?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); 
?>

If you use the example, you'll see that $img_a would be below $img_b and instead of having a weird black box, $img_b's transparency would be preserved.

Upvotes: 1

Related Questions