Masking one image against another using PHP GD

时间秒杀一切 提交于 2019-12-08 13:48:14

问题


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


回答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



来源:https://stackoverflow.com/questions/10926712/masking-one-image-against-another-using-php-gd

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!