0

Please see this question: PHP GD Use one image to mask another image, including transparency - The rules around here say for users to create new questions rather than revisit old ones and ask for support

I've been working with this script to enable transparent masking - the (possible) difference being that the source image has transparency, but it seems like the code below only works if the input PNGs have no transparency. Can someone have a look and see if I'm doing anything wrong?

What I'm trying to do below: 1. Grab a $source image 2. Resize it and save it locally as pjg.png, maintaining transparency (this works ok) 3. Mask the resultant image with another PNG.

Info:

  • image.png has transparency.
  • mask1.png is a white oval on black background, no transparency
  • The image saved at the very end has black on it, when it should maintain transparency throughout.

    <?php
    $data       = file_get_contents('assets/img/image.png');
    $source     = imagecreatefromstring( $data);
    
    
    // Set the percentage resize
    
    $percent = 0.5;
    
    // Get new dimensions
    list($width, $height) = getimagesize('assets/img/image.png');
    $new_width = $width * $percent;
    $new_height = $height * $percent;
    
    $image_p = imagecreatetruecolor($new_width, $new_height);
    imagealphablending($image_p, false);
    imagesavealpha( $image_p, true );
    
    imagecopyresampled($image_p, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    
    imagepng($image_p, "assets/img/pjg.png");
    
    $mask_id = 1;
    
    
    create_mask( $image_p, $mask_id ); 
    
    
    function create_mask( &$picture, $mask_id) {
    // Image masking using PHP
    // https://stackoverflow.com/questions/7203160/php-gd-use-one-image-to-mask-another-image-including-transparency
    
    $mask = imagecreatefrompng( 'assets/img/masks/mask'.$mask_id.'.png' );   // The mask is a white-on-black png
    
    
    
    // Get sizes and set up new picture
    $xSize = imagesx( $picture );
    $ySize = imagesy( $picture );
    $newPicture = imagecreatetruecolor( $xSize, $ySize );
    
    imagesavealpha($newPicture, true);  
    imagefill( $newPicture, 0, 0, imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 ) );
    
    
    // Resize mask if necessary
    if( $xSize != imagesx( $mask ) || $ySize != imagesy( $mask ) ) {
        $tempPic = imagecreatetruecolor( $xSize, $ySize );
        imagecopyresampled( $tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx( $mask ), imagesy( $mask ) );
        imagedestroy( $mask );
        $mask = $tempPic;
    }
    
    // Perform pixel-based alpha map application
    for( $x = 0; $x < $xSize; $x++ ) {
        for( $y = 0; $y < $ySize; $y++ ) {
            $alpha = imagecolorsforindex( $mask, imagecolorat( $mask, $x, $y ) );
            $alpha = 127 - floor( $alpha[ 'red' ] / 2 );
            $color = imagecolorsforindex( $picture, imagecolorat( $picture, $x, $y ) );
            imagesetpixel( $newPicture, $x, $y, imagecolorallocatealpha( $newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $alpha ) );
        }
    }
    
    $salt = random_string('alnum', 8); // Another function generating a string, not important
    $now = time();
    $new_filename = $now."_".$salt .".png";
    
    // Save it Locally using a unique name
    imagepng($newPicture, "assets/img/uploads/cropped/".$new_filename);
    
    
    // Copy back to original picture
    imagedestroy( $picture );
    $picture = $newPicture;
    
    }
    

If anyone could point out why the output image is not keeping its transparency, there'd be a nice cold beer in it for you.

Thanks!

PJG

Community
  • 1
  • 1
user1436297
  • 149
  • 1
  • 3

1 Answers1

1

I've worked it out. The original script was not checking for the transparency of the source image. The below script checks the source image for pixel transparency, and acts accordingly. The below script preforms a shap mask on a PNG image, and maintains the source image's transparency.

<?php
$data       = file_get_contents('assets/img/image.png');
$source     = imagecreatefromstring( $data);


// Set the percentage resize

$percent = 0.5;

// Get new dimensions
list($width, $height) = getimagesize('assets/img/image.png');
$new_width = $width * $percent;
$new_height = $height * $percent;

$image_p = imagecreatetruecolor($new_width, $new_height);
imagealphablending($image_p, false);
imagesavealpha( $image_p, true );

imagecopyresampled($image_p, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);

imagepng($image_p, "assets/img/pjg.png");

$mask_id = 1;


create_mask( $image_p, $mask_id ); 


function create_mask( &$picture, $mask_id) {
// Image masking using PHP
// http://stackoverflow.com/questions/7203160/php-gd-use-one-image-to-mask-another-image-including-transparency

$mask = imagecreatefrompng( 'assets/img/masks/mask'.$mask_id.'.png' );   // The mask is a white-on-black png



// Get sizes and set up new picture
$xSize = imagesx( $picture );
$ySize = imagesy( $picture );
$newPicture = imagecreatetruecolor( $xSize, $ySize );

imagesavealpha($newPicture, true);  
imagefill( $newPicture, 0, 0, imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 ) );


// Resize mask if necessary
if( $xSize != imagesx( $mask ) || $ySize != imagesy( $mask ) ) {
    $tempPic = imagecreatetruecolor( $xSize, $ySize );
    imagecopyresampled( $tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx( $mask ), imagesy( $mask ) );
    imagedestroy( $mask );
    $mask = $tempPic;
}

// Perform pixel-based alpha map application
for( $x = 0; $x < $xSize; $x++ ) {
    for( $y = 0; $y < $ySize; $y++ ) {
         $alpha = imagecolorsforindex( $mask, imagecolorat( $mask, $x, $y ) );

            if(($alpha['red'] == 0) && ($alpha['green'] == 0) && ($alpha['blue'] == 0) && ($alpha['alpha'] == 0))
            {
                // It's a black part of the mask
                imagesetpixel( $newPicture, $x, $y, imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 ) ); // Stick a black, but totally transparent, pixel in.
            }
            else
            {

                // Check the alpha state of the corresponding pixel of the image we're dealing with.    
                $alphaSource = imagecolorsforindex( $picture, imagecolorat( $picture, $x, $y ) );

                if(($alphaSource['alpha'] == 127))
                {
                    imagesetpixel( $newPicture, $x, $y, imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 ) ); // Stick a black, but totally transparent, pixel in.
                } 
                else
                {
                    $color = imagecolorsforindex( $picture, imagecolorat( $picture, $x, $y ) );
                    imagesetpixel( $newPicture, $x, $y, imagecolorallocatealpha( $newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $color['alpha'] ) ); // Stick the pixel from the source image in
                }


            }
    }
}

$salt = random_string('alnum', 8); // Another function generating a string, not important
$now = time();
$new_filename = $now."_".$salt .".png";

// Save it Locally using a unique name
imagepng($newPicture, "assets/img/uploads/cropped/".$new_filename);


// Copy back to original picture
imagedestroy( $picture );
$picture = $newPicture;

}
?>

Cheers for reading - looks like I'll be buying myself a beer later :)

PG

user1436297
  • 149
  • 1
  • 3