danielmlima
danielmlima

Reputation: 87

Interpolating colors in PHP

I'm a C++ programmer who recently started delving into web development with PHP, Javascript and HTML. Currently I'm having trouble with something that should be very simple, but isn't working as I expected...

function interpolateColor($corA, $corB, $lerp)
{
$redA = $corA & 0xFF0000;
$greenA = $corA & 0x00FF00;
$blueA = $corA & 0x0000FF;
$redB = $corB & 0xFF0000;
$greenB = $corB & 0x00FF00;
$blueB = $corB & 0x0000FF;

$redC = $redA + (($redB - $redA) * $lerp);
$greenC = $greenA + (($greenB - $greenA) * $lerp);
$blueC = $blueA + (($blueB - $blueA) * $lerp);

return $redC | $greenC | $blueC;
}

I've been trying to use this function to make the rows of a HTML table different colors based on the value of a "Priority" column, that goes from 0 to 10 and is divided by 10 to form the "lerpAmount" (0-1) variable.

$cor = interpolateColor(0xFF0000, 0x0000FF, $lerpAmount);

<tr bgcolor="<?=$cor?>">

However the colors I get don't look like a Red-Blue interpolation... It starts blueish, then only one of the rows is green, then it becomes pink and interpolates to some form of brown, before turning dark blue again, which makes me think that something's very wrong.

Thanks in advance.

Upvotes: 2

Views: 1482

Answers (2)

Andr&#233;s Morales
Andr&#233;s Morales

Reputation: 793

You must do a bitwise AND operation between the result colors and the masks:

$redC = $redA + (($redB - $redA) * $lerp) & 0xFF0000;         // Only Red
$greenC = $greenA + (($greenB - $greenA) * $lerp) & 0x00FF00; // Only Green
$blueC = $blueA + (($blueB - $blueA) * $lerp) & 0x0000FF;     // Only Blue

to get the correct values for RGB, and then to return the color in hexadecimal you must convert it using:

$result = dechex($redC | $greenC | $blueC);
return str_pad($result, 6, "0", STR_PAD_LEFT);

(the str_pad is to add leading zeros to the returned color).

Upvotes: 3

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324750

The problem you face here is one of underflow. I think. I don't know if that's the right word XD

Anyway!

Let's say you're trying to get the colour that is exactly 50% of the way between red and black.

So you're interpolating 0xFF0000 and 0x000000. You would expect either 0x800000 or 0x7F0000 as the result, right?

But that's not what you get. Instead you get 0x7F8000, which is kind of a dull yellow.

Personally, I would do something like this:

$rgbA = array(
    ($corA & 0xFF0000) >> 16,
    ($corA & 0x00FF00) >> 8,
    ($corA & 0x0000FF)
);
$rgbB = array(
    ($corB & 0xFF0000) >> 16,
    ($corB & 0x00FF00) >> 8,
    ($corB & 0x0000FF)
);
$rgbC = array_map(
    function($a,$b) use ($lerp) {return round($a+($b-$a)*$lerp);},
    $rgbA, $rgbB
);
// if you want a number:
return $rgbC[0]<<16 | $rgbC[1]<<8 | $rgbC[2];
// if you want an HTML hex code:
return sprintf("#%02X%02X%02X",$rgbC[0],$rgbC[1],$rgbC[2]);

Upvotes: -1

Related Questions