This is a very old topic. When I search this title online, I can get some articles which are published as early as 2003. Though there are so many reference, it still takes me a huge amount of time to figure this out when I am working on my open source project “Free Online Sprite Sheet Decomposer“. The concept of this project is dividing the PNG sprite sheet into pieces of frame by frame png files. The challenge is copying the color info from source image to the destination image and keeping the transparent info as the same. However, PNGs have several different types and each type supports the transparency feature in different way. For more details, you can check this article: Transparency Concept in PNG.

A Simple Way to Create Transparent PNG Image

In my project, I am using a simple way to duplicate PNG Image with Transparency. The result PNG format is truecolor PNG with transparency. It is not truecolor PNG with alpha or RGBA. The concept is defining an RGB color as the transparency color, so any pixel in the destination image which has this color will be interpreted as transparency. The risk of this approach is it could set some pixels transparent in the destination image while it is not transparent in the source image.

For example, if we define black color (0x000000) as transparency color in destination image, it could set a character’s eye or hair transparent by mistake after we copy the image from source PNG image. Therefore, we need to find a color which is not used in the source image and define that color as transparency color in the destination PNG image before we copy them. Here is an example source code:

//find the colors used in the image
function getColorCollection($imageResource, $width, $height)
{
	$totalPixels = $width * $height;
	$colorCollection = array();
	for($i = 0; $i < $width; $i++)
	{
		for($j = 0; $j < $height; $j++)
		{
			$rgb = ImageColorAt($imageResource, $i, $j);
			$r = ($rgb >> 16) & 0xFF;
			$g = ($rgb >> 8) & 0xFF;
			$b = $rgb & 0xFF;
			$colorCollection[$rgb] = $rgb;
		}
	}
	
	return $colorCollection;
}

//find an unused color
function findNotUsedColor($colorCollection)
{
	for($i = 0; $i < 0xFFFFFF; $i++)
	{
		if(!in_array($i, $colorCollection))
		{
			return $i;
		}
	}
}

//create the png image with transparency
$fileName = "sourceImg.png";
$srcimage = imagecreatefrompng($fileName);
list($width, $height) = getimagesize($fileName);
$usedColor = getColorCollection($srcimage, $width, $height);
$colorInt = findNotUsedColor($usedColor);
$r = ($colorInt >> 16) & 0xFF;
$g = ($colorInt >> 8) & 0xFF;
$b = $colorInt & 0xFF;

$desimage = imagecreatetruecolor($width, $height);
$transparent_new = ImageColorAllocate($desimage, $r, $g, $b);
$transparent_new_index = ImageColorTransparent( $desimage, $transparent_new );
ImageFill( $desimage, 0, 0, $transparent_new_index );
imagecopy($desimage, $srcimage, 0, 0, $width, $height, $width, $height);
imagepng($desimage);
imagedestroy($desimage);

The above example has two limitations:

  • When your source PNG image is true-color PNG with alpha channel (RGBA), getColorCollection function will extract the wrong color code.
  • The RGB PNG format with transparency flag only supports one transparency value. So the pixel in this type of PNG is either opaque or fully transparent. There is no ability to set a pixel as 50% opacity or 80% opacity. It doesn’t support alpha blending.

A Better Way To Copy PNG Transparency or Alpha channel

As PHP provides a new way to create true-color PNG image with alpha channel, I guess it may solve above problems. But I don’t have time to test it. Here is the example code to copy a PNG with alpha channel:

// Load a png image with alpha channels
$src = imagecreatefrompng('./a.png');
imagealphablending($src, false);
imagesavealpha($src, true);
imagepng($src, "b.png");
imagedestroy($src);

Here is a piece of source code example to show you copy one transparent PNG to a new PNG partially.

// Load a png image with alpha channels
$src = imagecreatefrompng('./a.png');
//the src image is 194x228, we just copy half of the source image
$dest = imagecreatetruecolor(194, 114);
imagealphablending($dest, false);
imagesavealpha($dest, true);

imagecopy($dest, $src, 0, 0, 0, 0, 194, 114);
imagepng($dest, "b.png");
imagedestroy($src);
imagedestroy($dest);

This method will support RGBA PNG image perfectly. It will copy the PNG alpha channel from source image to the destination PNG image without any different. However, it doesn’t work properly if the source PNG image is not RGBA format (true-color with alpha channel). If you are using above code to copy the PNG to a new PNG image, the transparent part of the result PNG will be black.

Previous PostNext Post

Leave a Reply

Your email address will not be published. Required fields are marked *