Page 1 of 2

All the colors in a JPEG: Color Palette

Posted: Tue Jan 02, 2007 10:27 am
by 696020
onion2k | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


Hi,

I've had great success getting the following code to work with GIF files in the same directory as the script. I've been tinkering with the code trying to get it to work for JPEG files. Stumped. Any ideas?
Thanks.

Andrew

Code: Select all

<?PHP
function bildinfo($bild)
{
/*
******* FUNCTION BILDINFO() ******* ******* ******* *******
******* ******* ******* ******* ******* ******* ******* *******
******* Copyright 2003 by http://www.BLACKEYE.org ******* *******
******* ******* ******* ******* ******* ******* ******* *******
Please don't change the copyright in this file. You can modify
this file, but NEVER remove the copyright !
If YOU were the creator of this function, you would say the
same, eh ? 

For more informations / How to use:
HOMEPAGE: http://www.blackeye.org
******* ******* ******* ******* ******* ******* ******* *******
*/
$fp = fopen($bild, "rb"); // Open image in binary mode (for windows)
$f = fread($fp, filesize($bild));
$c = bin2hex($f); // Binary file -> Hex
$c = ereg_replace("5c30", "0000", $c); // In gif-files "5c30" stands for real "00" values. why ? i dont know
$b = $c;

$pos = strpos($c, "fe0102"); // 6 Byte termination for the color table
if ($pos > 0)
{
$c = substr($c, 26);
$c = substr($c, 0, strpos($c, "fe0102")); // Termination for the color table of non-transparent images
}
else
{
$c = substr($c, 26);
$c = substr($c, 0, strpos($c, "21f904")); // Termination for the color table
}

echo "<table border='0'>";

$i = 0;
$y = 0;
$str = "";
$pix = chunk_split($c, 6, ";"); // 6 Char long block (color)
$pix = explode(";",$pix);
sort($pix);
foreach($pix as $col)
{
if ($col && !ereg($col.";", $str) && strlen($col) == 6) // So that no color is twice in the list
{
$str .= $col.";";
$i++; // F?r die Table anzeige
$y++; // Anzahl Farben
if ($i == 1) { echo ""; }
echo "<td width='6' height='8' bgcolor='#$col' style='border:1px solid #000000;font-size:1px;' title='?2003 by http://www.BLACKEYE.org'>";
echo " ";
echo "</td>";
if ($i == 10)
{
echo ""; $i = 0;
}
}
}

echo "</table>";
echo $y." visible colors";
}

$bild = ""; // Imagefile
bildinfo($bild);
?>

Only copy & paste this text into your .php file, where you want to show the image.


onion2k | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]

Posted: Tue Jan 02, 2007 10:39 am
by onion2k
GIF files and JPEG files are completely and utterly different. You'll need to rewrite that script to decompress JPEG's LWZ compression. That's will be incredibly difficult because it's complicated stuff.

Alternatively, rewrite the script to use GD's imagecolorat() function.

Posted: Tue Jan 02, 2007 10:54 am
by 696020
Thanks for the insight. If I use imagecolorat(), on an image that is 500x500 pixels (250,000 pixels) wouldn't I have to call the imagecolorat() function 250,000 times?

Posted: Tue Jan 02, 2007 11:05 am
by onion2k
696020 wrote:Thanks for the insight. If I use imagecolorat(), on an image that is 500x500 pixels (250,000 pixels) wouldn't I have to call the imagecolorat() function 250,000 times?
Yes. It's not *that* slow. Not something you'd want to do all the time of course. You really don't have a choice with JPEG images though. They're essentially compressed bitmaps. There's no colour palette to query like you're doing with the GIFs.

Posted: Tue Jan 02, 2007 11:58 am
by neel_basu
Would You Please Explain Whats the job Of This Function

Posted: Tue Jan 02, 2007 12:10 pm
by onion2k
neel_basu wrote:Would You Please Explain Whats the job Of This Function
It builds an HTML table of colours defined in the first palette in a GIF file.

Posted: Tue Jan 02, 2007 12:18 pm
by neel_basu
OK Thanks

Posted: Tue Jan 02, 2007 1:22 pm
by 696020
Thanks for the info...so a while loop is probably the best way to do this you think?
onion2k wrote:
696020 wrote:Thanks for the insight. If I use imagecolorat(), on an image that is 500x500 pixels (250,000 pixels) wouldn't I have to call the imagecolorat() function 250,000 times?
Yes. It's not *that* slow. Not something you'd want to do all the time of course. You really don't have a choice with JPEG images though. They're essentially compressed bitmaps. There's no colour palette to query like you're doing with the GIFs.

Posted: Tue Jan 02, 2007 1:46 pm
by onion2k
696020 wrote:Thanks for the info...so a while loop is probably the best way to do this you think?
No. A for loop. A while loop would need to evaluate the condition on each iteration. That would be slower.

If you're interested I could dig out some code I wrote once that generates a histogram of colours in a jpeg. It wouldn't be very much work to modify it to produce a table of colours instead. Mind you, you should be aware that a photo stored as a JPEG will have lots of colours ... many thousands usually even in a small photo. It'll be a massive table.

Posted: Tue Jan 02, 2007 1:56 pm
by 696020
That source code would be much appreciated. Thanks for all your help.

I'm using this code to evaluate colors in logos for companies that are uploaded, so the color table won't be too too big.
onion2k wrote:
696020 wrote:Thanks for the info...so a while loop is probably the best way to do this you think?
No. A for loop. A while loop would need to evaluate the condition on each iteration. That would be slower.

If you're interested I could dig out some code I wrote once that generates a histogram of colours in a jpeg. It wouldn't be very much work to modify it to produce a table of colours instead. Mind you, you should be aware that a photo stored as a JPEG will have lots of colours ... many thousands usually even in a small photo. It'll be a massive table.

Posted: Tue Jan 02, 2007 2:01 pm
by onion2k

Code: Select all

$image = imagecreatefromjpeg($imageFilename);
$canvas_x = imagesx($image);
$canvas_y = imagesy($image);

	for ($x=0;$x<$canvas_x;$x++) {
		for ($y=0;$y<$canvas_y;$y++) {

			$rgb = imagecolorat($image,$x,$y);
			$r   = ($rgb >> 16) & 0xFF;
			$g   = ($rgb >>  & 0xFF;
			$b   = $rgb & 0xFF;

			$r_total[$r]++;
			$g_total[$g]++;
			$b_total[$b]++;

			$pixelcount++;

		}
	}

	imagedestroy($image);

	$r_range = (max($r_total)-min($r_total));
	$g_range = (max($g_total)-min($g_total));
	$b_range = (max($b_total)-min($b_total));

	$histogram = imagecreatetruecolor(300,324);

	$white = imagecolorallocate($histogram,255,255,255);
	imagefilledrectangle($histogram,0,0,300,324,$white);
	imagecolordeallocate($histogram,$white);

	$black = imagecolorallocate($histogram,0,0,0);

	for ($x=0;$x<256;$x++) {

		imageline($histogram,($x+20),100,($x+20),(100-(($r_total[$x]/$r_range)*80)),$black);
		$red = imagecolorallocate($histogram,255,$x,$x);
		imageline($histogram,($x+20),102,($x+20),104,$red);
		imagecolordeallocate($histogram,$red);

		imageline($histogram,($x+20),200,($x+20),(200-(($g_total[$x]/$g_range)*80)),$black);
		$green = imagecolorallocate($histogram,$x,255,$x);
		imageline($histogram,($x+20),202,($x+20),204,$green);
		imagecolordeallocate($histogram,$green);

		imageline($histogram,($x+20),300,($x+20),(300-(($b_total[$x]/$b_range)*80)),$black);
		$blue = imagecolorallocate($histogram,$x,$x,255);
		imageline($histogram,($x+20),302,($x+20),304,$blue);
		imagecolordeallocate($histogram,$blue);

	}

	imagestring($histogram,2,200,104,"Red Channel",$black);
	imagestring($histogram,2,200,204,"Green Channel",$black);
	imagestring($histogram,2,200,304,"Blue Channel",$black);

	header("Content-Type: image/jpeg");
	imageJPEG($histogram);
	imagedestroy($histogram);

Posted: Tue Jan 02, 2007 2:24 pm
by Kieran Huggins
You could use imagecolorstotal() to see what you're dealing with, then imagetruecolortopalette() to reduce it to a reasonable number if you so desire. This will be especially useful if you're expecting logos with just a few colours, as imagetruecolortopalette() will allow you to dither the result and restrict the number of colours in the final product.

I can only assume the most predominant colours will remain in the final palette, which is what I gather you're looking for.

If you get really fancy, you could write an algorithm that reduces the number of colours and compares the similarity of all the colours until only distinct ones are left.... I'd better stop now :-)

Posted: Tue Jan 02, 2007 2:26 pm
by 696020
Thanks everybody for your suggestions and help. I'll get to coding and let you know if I hit any roadblocks.

Andrew

Posted: Thu Jan 04, 2007 2:45 am
by Jaxolotl
I'll try to find a similar script I made long time ago.
One thing I remember is that using PNG(24) images was better than using JPG files but at this very moment I don't remember exactly why, if I find it I'll let you know.

Posted: Thu Jan 04, 2007 3:00 am
by onion2k
Jaxolotl wrote:One thing I remember is that using PNG(24) images was better than using JPG files but at this very moment I don't remember exactly why, if I find it I'll let you know.
Each image format has it's pros and cons. You can't just say "PNG is better than JPEG". It depends on the image, and what features you need.