Page 1 of 1

Colour Manipulation

Posted: Sat Apr 03, 2010 9:41 pm
by samwho
Hey, I'd like to submit a code snippet for review/comment/to help others :)

It concerns dynamic colour changing. I noticed that for websites with different colour schemes it's a little bit fiddly and annoying to define all of the colours manually in a database and after seeing Adobe's kuler (http://kuler.adobe.com/) I thought it would be cool to have a PHP implementation of this.

Some source code:

Code: Select all

	function getStrongest($r, $g, $b) {
		$strongest = max($r, $g, $b);
		if ($strongest == $r) {
			return 'r';
		}
		else if ($strongest == $g) {
			return 'g';
		}
		else if ($strongest == $b) {
			return 'b';
		}
	}
	function colourChange($colour, $red_change, $green_change, $blue_change) {
		$colour = preg_replace("/\#/","",$colour);
		if (strlen($colour) != 6) {
			return array("colour" => false, "error" => "Invalid colour value.");
		}
		$red = hexdec(substr($colour,0,2));
		$green = hexdec(substr($colour,2,2));
		$blue = hexdec(substr($colour,4,2));
		
		$red += intval($red_change);
		$green += intval($green_change);
		$blue += intval($blue_change);
		
		if ($red > 255) {
			$red = 255;
		}
		if ($red < 0) {
			$red = 0;
		}
		if ($green > 255) {
			$green = 255;
		}
		if ($green < 0) {
			$green = 0;
		}
		if ($blue > 255) {
			$blue = 255;
		}
		if ($blue < 0) {
			$blue = 0;
		}
		if (strlen(dechex($red)) == 1) {
			$new_red = "0".dechex($red);
		}
		else {
			$new_red = dechex($red);
		}
		if (strlen(dechex($green)) == 1) {
			$new_green = "0".dechex($green);
		}
		else {
			$new_green = dechex($green);
		}
		if (strlen(dechex($blue)) == 1) {
			$new_blue = "0".dechex($blue);
		}
		else {
			$new_blue = dechex($blue);
		}
		return array("colour" => "#".$new_red.$new_green.$new_blue, "error" => false);
	}
Currently it returns an array containing indices "colour" and "error". It was written like this at the time because I wanted descriptions of the errors but I realise that may not be the best way of doing it. Fairly easy to change, though :)

The way it works is quite simple, it breaks down a 3 byte hexidecimal value into its separate red, green and blue bytes and allows you to edit them with parameters passed to the function. I have found this code very useful for doing things such as slight increase/decrease in brightness for mouse overs etc.

I am open to the fact it probably isn't as efficient/well written as it could be which is why I would love some constructive criticism on it to make it a really good, useful function :)

Example of its usage:

http://lbak.co.uk/experiments/colourchange/

The first box is your initial colour, the following 3 boxes are your red, green and blue increment/decrement values (respectively). Clicking "Go!" gives you a little gradient of your desired changes as well as their output values and the "Colour Square" option is really cool. It was a proof of concept kinda thing I decided to try out that generates a colour square similar to one you would find in Photoshop when selecting a colour. It isn't perfect, I recommend you just try it with solid red, green or blue but the idea is definitely there :) Just to prove how cool this little code snippet can be (it's an AJAX based call that takes a little while to load).

Source code for the colour square and colour gradient:

Code: Select all

(CSS)
.r {
width: 4px;
height: 4px;
display: inline-block;
}
(/CSS)
                $x = 0;
		$y = 0;
		$z = 0;
		$start = preg_replace("/\#/","",$_POST['colour']);
		$strongest = getStrongest(hexdec(substr($start,0,2)),hexdec(substr($start,2,2)),hexdec(substr($start,4,2)));
		$cur_red = hexdec(substr($start,0,2));
		$cur_green = hexdec(substr($start,2,2));
		$cur_blue = hexdec(substr($start,4,2));
		$length = 64;
		if ($strongest == 'r') {
			$r = 0;
			$g = 0;
			$b = 0;
			while ($y < $length) {
				$x = 0;
				while ($x < $length) {
					$g_inc = floor((256 - $cur_green) / $length);
					$b_inc = floor((256 - $cur_blue) / $length);
					$colour = colourChange($start,$r,$g,$b);
					echo '<div class="r" style="background-color: '.$colour['colour'].'"></div>';
					$g += $g_inc;
					$b += $b_inc;
					$x++;
					//echo 'r'.$r.'g'.$g.'b'.$b;
				}
				echo '<br />';
				$y++;
				$r = -4 * $y;
				$g = -4 * $y;
				$b = -4 * $y;
			}
		}
		else if ($strongest == 'g') {
			$r = 0;
			$g = 0;
			$b = 0;
			while ($y < 64) {
				$x = 0;
				while ($x < 64) {
					$r_inc = floor((256 - $cur_red) / $length);
					$b_inc = floor((256 - $cur_blue) / $length);
					$colour = colourChange($start,$r,$g,$b);
					echo '<div style="width: 4px; height: 4px; background-color: '.$colour['colour'].'; display: inline-block;" onclick="document.getElementById(\'colour\').value = this.style.backgroundColor"></div>';
					$r += $r_inc;
					$b += $b_inc;
					$x++;
					//echo 'r'.$r.'g'.$g.'b'.$b;
				}
				echo '<br />';
				$y++;
				$r = -4 * $y;
				$g = -4 * $y;
				$b = -4 * $y;
			}
		}
		else if ($strongest == 'b') {
			$r = 0;
			$g = 0;
			$b = 0;
			while ($y < 64) {
				$x = 0;
				while ($x < 64) {
					$g_inc = floor((256 - $cur_green) / $length);
					$r_inc = floor((256 - $cur_red) / $length);
					$colour = colourChange($start,$r,$g,$b);
					echo '<div style="width: 4px; height: 4px; background-color: '.$colour['colour'].'; display: inline-block;" onclick="document.getElementById(\'colour\').value = this.style.backgroundColor"></div>';
					$g += $g_inc;
					$r += $r_inc;
					$x++;
					//echo 'r'.$r.'g'.$g.'b'.$b;
				}
				echo '<br />';
				$y++;
				$r = -4 * $y;
				$g = -4 * $y;
				$b = -4 * $y;
			}
		}
Note: Colour square may not work in IE...

PS: I apologies for the lack of comments on the colour square example but I hope it makes sense to some of the seasoned PHP coders :)

Thanks,
Sam

Re: Colour Manipulation

Posted: Sun Apr 04, 2010 2:09 pm
by kaszu
Looks nice, but for colors like 069 => 006699 it doesn't work :(
But to be honest I don't see where this snippet could be useful / used.

Re: Colour Manipulation

Posted: Sun Apr 04, 2010 4:45 pm
by VladSun
How about having a "normalize/format" function:

Code: Select all

function normalizeColour($colour)
{
    return str_pad(dechex($colour < 0 ? 0 : ($colour > 255 ? 255 : $colour)), 2, '0', STR_PAD_LEFT);
}
This way your function becomes (by using less expensive str_replace):

Code: Select all

function colourChange($colour, $red_change, $green_change, $blue_change) {
                $colour = str_replace("#","",$colour);
                if (strlen($colour) != 6) {
                        return array("colour" => false, "error" => "Invalid colour value.");
                }
                $red = hexdec(substr($colour,0,2));
                $green = hexdec(substr($colour,2,2));
                $blue = hexdec(substr($colour,4,2));
                
                $red += intval($red_change);
                $green += intval($green_change);
                $blue += intval($blue_change);
                
                $red = normalizeColour($red);
                $green = normalizeColour($green);
                $blue = normalizeColour($blue);

                return array("colour" => "#".$new_red.$new_green.$new_blue, "error" => false);
        }
Also, as kaszu noticed you should take care of "shortcut values":

Code: Select all

       }
        function colourChange($colour, $red_change, $green_change, $blue_change) {
                 $colour = str_replace("#","",$colour);
                if (strlen($colour) == 6) {
                        $bytes =2;
                }
                if (strlen($colour) == 3) {
                        $bytes = 1;
                }
                else {
                        return array("colour" => false, "error" => "Invalid colour value.");
                }

                $red = hexdec(substr($colour, 0, $bytes));
                $green = hexdec(substr($colour, $bytes, $bytes));
                $blue = hexdec(substr($colour, 2*$bytes, $bytes));
                ...

Re: Colour Manipulation

Posted: Sun Apr 04, 2010 6:57 pm
by samwho
Huge thanks for the suggestions guys :D

Kaszu, I have developed for about 3-4 months on a text based RPG that has a little bit of trouble supporting their multiple colour schemes. This function was originally written for hover overs... Just to increase the background colour (that was pulled from a database into a $colorScheme array) by 20 in each area and thus being supported on all colour schemes :)

Uses other than that I'm not entirely sure of... I think I demonstrated some little fun things you can do with it in my example link but I haven't thought too creatively about it yet. I'm sure with the right knowledge and mathematical application you can work out complimentary colours and such :)