Search code examples
phpimagecolorspngtransparency

Php - replace base color of transparent png image


I have searched a lot and I found only few solutions (on google and stackoverflow so please don't mark this one as a duplicate unless there's really duplicate question), but problems are hard edges. Is there any proper way of changing base color of, let's say black shape png image with transparent background but to preserve soft edges?

This is an example image:

enter image description here

I want it to look like this:

enter image description here

but the solutions I found give me this one:

enter image description here

Since I will be using this on my localhost, only for personal use, any php library that could help achieve this is appreciated.

UPDATE:

This is the function that gives me 3rd image:

function LoadPNG($imgname)
{
    $im = imagecreatefrompng ($imgname);
    imagetruecolortopalette($im,false, 255);
    $index = imagecolorclosest ( $im,  0,0,0 ); // GET BLACK COLOR
    imagecolorset($im,$index,0,150,255); // SET COLOR TO BLUE
    $name = basename($imgname);
    imagepng($im, getcwd()."/tmp/$name" ); // save image as png
    imagedestroy($im);
}
$dir = getcwd()."/img/";
$images = glob($dir."/*.png",GLOB_BRACE);
foreach($images as $image) {
    LoadPNG($image);
}

Originally, this function was a solution for GIF images (palette of 255 colors) so I guess that's why there are hard edges. I am looking for a solution (improvement to this script) to preserve transparency and soft edges of PNG image.

EDIT 2:

I have found an interesting approach using html5 canvas and javascript here: http://users7.jabry.com/overlord/mug.html

Maybe someone could have an idea how to translate this into PHP if even possible.

NEW SOLUTION

In answers


Solution

  • This code doesn't exemplify the problem, but transforms colors like this:

    enter image description here

    Uses the ALPHA channel of an image to determines coloring. For other results, just play around with imagecolorallocatealpha():

    function colorizeBasedOnAplhaChannnel( $file, $targetR, $targetG, $targetB, $targetName ) {
    
        $im_src = imagecreatefrompng( $file );
    
        $width = imagesx($im_src);
        $height = imagesy($im_src);
    
        $im_dst = imagecreatefrompng( $file );
    
        // Note this:
        // Let's reduce the number of colors in the image to ONE
        imagefilledrectangle( $im_dst, 0, 0, $width, $height, 0xFFFFFF );
    
        for( $x=0; $x<$width; $x++ ) {
            for( $y=0; $y<$height; $y++ ) {
    
                $alpha = ( imagecolorat( $im_src, $x, $y ) >> 24 & 0xFF );
    
                $col = imagecolorallocatealpha( $im_dst,
                    $targetR - (int) ( 1.0 / 255.0  * $alpha * (double) $targetR ),
                    $targetG - (int) ( 1.0 / 255.0  * $alpha * (double) $targetG ),
                    $targetB - (int) ( 1.0 / 255.0  * $alpha * (double) $targetB ),
                    $alpha
                    );
    
                if ( false === $col ) {
                    die( 'sorry, out of colors...' );
                }
    
                imagesetpixel( $im_dst, $x, $y, $col );
    
            }
    
        }
    
        imagepng( $im_dst, $targetName);
        imagedestroy($im_dst);
    
    }
    
    unlink( dirname ( __FILE__ ) . '/newleaf.png' );
    unlink( dirname ( __FILE__ ) . '/newleaf1.png' );
    unlink( dirname ( __FILE__ ) . '/newleaf2.png' );
    
    $img = dirname ( __FILE__ ) . '/leaf.png';
    colorizeBasedOnAplhaChannnel( $img, 0, 0, 0xFF, 'newleaf1.png' );
    colorizeBasedOnAplhaChannnel( $img, 0xFF, 0, 0xFF, 'newleaf2.png' );
    ?>
    
    Original
    <img src="leaf.png">
    <br />
    <img src="newleaf1.png">
    <br />
    <img src="newleaf2.png">