Sign in to follow this  
no0n

imagecreatefrompng problem

Recommended Posts

I'm pretty sure what the problem IS however I do not know how I can handle it well. I have a function that uses imagecreatefrompng($im) and there is an issue with images and transparency. Here is my code:
	$im = imagecreatefrompng('images/test/' . $image);
	
	// Calculate how many grid squares needed
	$yquad = (int) (imagesy($im) / 16);
	$yquad += ((imagesy($im) % 16) > 0) ? 1 : 0;
	$xquad = (int) (imagesx($im) / 16);
	$xquad += ((imagesx($im) % 16) > 0) ? 1 : 0;
	
	// # of pixels used.
	// imagesx, imagesy not sufficient because it may not be
	// an even multiple of 16
	$row = $xquad*16;
	$col = $yquad*16;
	
	//	Generate grid squares
	for ($y = 0; $y < $col; $y++)
	{
		for ($x = 0; $x < $row; $x++)
		{
			$color = imagecolorat($im,$x,$y);
			$a = ((int) ($x / 16)) + 1;
			$b = ((int) ($y / 16)) + 1;
						
			if ($color!=NULL)
				$grid[$a][$b] .= sprintf("#%'06X;", $color);
			else
				$grid[$a][$b] .= '#FFFFFF;';			
		}
	}
I am capturing the color information at the given coordinates and converting it to hex. The only way I could figure out to keep leading zeros is to use the '06 to specify padding of 6 and fill character of 0. If I have a PNG with transparency, my result is drastically wrong (either blue or red tint to it). The only fix I have is to open up a graphics editor (im using GIMP) and copy -> paste into a new file with background contents as white. Even when I tried using IrfanView and saving with save transparency unchecked I get the tint. How can I solve this? PS - Taking off the padding results in a lot of two character hex values (eg #76;) and not longer than 6 character results.

Share this post


Link to post
Share on other sites
I'm not certain how the transparency (alpha) channel is manipulated in GD, but it is possibly in the form of a fourth channel, which would result in two additional digits at the beginning of the integer representation of the color.

If that is the case, you could choose to eliminate that channel using
sprintf("#%'06X;", $color & 0xFFFFFF);

Share this post


Link to post
Share on other sites
What exactly does 0xFFFFFF at the end of my sprintf do? Trim? Convert?

Whatever it does, it doesn't solve my problem. On the image with transparency #000076; (#76; with no padding) is showing instead of white.

Share this post


Link to post
Share on other sites
Quote:
Original post by no0n
What exactly does 0xFFFFFF at the end of my sprintf do? Trim? Convert?


sprintf("#%'06X;", $color & 0xFFFFFF);

& is the bitwise AND operator in this case, so it's doing a bitwise AND of $color and 0xFFFFFF.

0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Look up bit masking. In short, if you AND with a certain bitmask, then you can 'select' only those bits from the source (only bits with a 1 in the mask will carry over their values to the result, bits corresponding to a 0 in the mask will be set to 0 in the result).

e.g.


0101 0110
AND 0000 1111
= 0000 0110


The effect in this case is to set the high byte of $color (which, as ToohrVyk is saying, is probably the alpha/transparency byte) to 0.

EDIT: Or perhaps I should say "was probably", re-reading your last response.

Share this post


Link to post
Share on other sites
Quote:
Original post by no0n
Whatever it does, it doesn't solve my problem. On the image with transparency #000076; (#76; with no padding) is showing instead of white.


Why do you expect it to show as white? Judging from the output, the pixel wouldn't be white even if you removed transparency (I reread the description of imagecolorat in the PHP manual, and transparency is apparently handled using 7 bits at offset 24, which should be removed by masking with 0xFFFFFF), it would be dark blue.

I also notice in your code the conditional if ($color!=NULL). What do you expect this conditional to do? I didn't know imagecolorat could return a null value.

If you are trying to convert 100% transparent pixels to white, then you should examine the alpha channel for being zero or not. For instance:

function RemoveAlpha($argb) {
$a = ($argb & 0x7F000000) >> 24;
$rgb = $argb & 0xFFFFFF;
if ($a == 0) return "#FFFFFF";
else return sprintf("#%'06X",$rgb);
}


You could also decide to compute the result of drawing the transparent image on a white background (this would get a much cleaner effect for the edges):

function RemoveAlphaImproved($argb) {
$a = ($argb & 0x7F000000) >> 24;
$r = ($argb & 0x00FF0000) >> 16;
$g = ($argb & 0x0000FF00) >> 8;
$b = ($argb & 0x000000FF);
$f = (float)$a / (float)0xFF;
$white = 255 * $f;
$r = (int)($f * $r + $white);
$g = (int)($f * $g + $white);
$b = (int)($f * $b + $white);
return sprintf("#%'02X%'02X%'02X",$r,$g,$b);
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this