3

For example I have a blue color:

#049cd9 or rgba(4, 156, 218)

How can I calculate the correspondent color, which in this case it would be a dark blue color:

#004ea0 or rgba(0, 78, 160)

?

Normally I don't know the 2nd color (that I want to find out), so I want to find a way to get the darker color based on the first color.

enter image description here

Is there a formula or something that I can generate by substracting the two colors somehow?


So I've found HEX to HSL and HSL to HEX functions:

function hex_to_hue($hexcode)
{
    $redhex  = substr($hexcode,0,2);
    $greenhex = substr($hexcode,2,2);
    $bluehex = substr($hexcode,4,2);

    // $var_r, $var_g and $var_b are the three decimal fractions to be input to our RGB-to-HSL conversion routine
    $var_r = (hexdec($redhex)) / 255;
    $var_g = (hexdec($greenhex)) / 255;
    $var_b = (hexdec($bluehex)) / 255;

    // Input is $var_r, $var_g and $var_b from above
    // Output is HSL equivalent as $h, $s and $l — these are again expressed as fractions of 1, like the input values

    $var_min = min($var_r,$var_g,$var_b);
    $var_max = max($var_r,$var_g,$var_b);
    $del_max = $var_max - $var_min;

    $l = ($var_max + $var_min) / 2;

    if ($del_max == 0) {
        $h = 0;
        $s = 0;
    } else {
        if ($l < 0.5) {
            $s = $del_max / ($var_max + $var_min);
        } else {
            $s = $del_max / (2 - $var_max - $var_min);
        }
        ;

        $del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
        $del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
        $del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;

        if ($var_r == $var_max) {
            $h = $del_b - $del_g;
        } else if ($var_g == $var_max) {
            $h = (1 / 3) + $del_r - $del_b;
        } else if ($var_b == $var_max) {
            $h = (2 / 3) + $del_g - $del_r;
        }
        ;

        if ($h < 0) {
            $h += 1;
        }
        ;

        if ($h > 1) {
            $h -= 1;
        }
        ;
    }
    ;

    return array($h, $s, $l);

    /*
// Calculate the opposite hue, $h2
$h2 = $h + 0.5;
if ($h2 > 1)
{
$h2 -= 1;
};

return array($h2, $s, $l);
*/

}



function hue_to_hex($hue = array())
{
    function hue_2_rgb($v1,$v2,$vh)
    {
        if ($vh < 0) {
            $vh += 1;
        }
        ;

        if ($vh > 1) {
            $vh -= 1;
        }
        ;

        if ((6 * $vh) < 1) {
            return($v1 + ($v2 - $v1) * 6 * $vh);
        }
        ;

        if ((2 * $vh) < 1) {
            return($v2);
        }
        ;

        if ((3 * $vh) < 2) {
            return($v1 + ($v2 - $v1) * ((2 / 3 - $vh) * 6));
        }
        ;

        return($v1);
    }
    ;


    list($h2, $s, $l) = $hue;

    // Input is HSL value of complementary colour, held in $h2, $s, $l as fractions of 1
    // Output is RGB in normal 255 255 255 format, held in $r, $g, $b
    // Hue is converted using function hue_2_rgb, shown at the end of this code

    if ($s == 0) {
        $r = $l * 255;
        $g = $l * 255;
        $b = $l * 255;
    } else {
        if ($l < 0.5) {
            $var_2 = $l * (1 + $s);
        } else {
            $var_2 = ($l + $s) - ($s * $l);
        }
        ;

        $var_1 = 2 * $l - $var_2;
        $r = 255 * hue_2_rgb($var_1,$var_2,$h2 + (1 / 3));
        $g = 255 * hue_2_rgb($var_1,$var_2,$h2);
        $b = 255 * hue_2_rgb($var_1,$var_2,$h2 - (1 / 3));
    }
    ;


    $rhex = sprintf("%02X",round($r));
    $ghex = sprintf("%02X",round($g));
    $bhex = sprintf("%02X",round($b));

    return $rhex.$ghex.$bhex;
}

They work because I tested them by converting a color back and forth.

But I don't know how can I change the Hue and Luminosity properties just like in Photoshop? The dark color would be H +13 and L -28.

And the hex_to_hsl function above returns float values between 0 and 1...

Alex
  • 66,732
  • 177
  • 439
  • 641
  • 2
    What exactly do you mean? What is a "correspondent color"? – Pointy Nov 04 '11 at 14:05
  • What defines a corresponding colour? Do you just want to get a darker version of the colour? – musefan Nov 04 '11 at 14:05
  • yes, something like that – Alex Nov 04 '11 at 14:06
  • 1
    You'll need to describe what you want more clearly, or provide a much larger sample set so that we can try to pattern match. – zzzzBov Nov 04 '11 at 14:07
  • The simplest form of darkening i can think of is to divide by 2. You'll maintain proportions of rgb, but it will be darker. It wont match the colors you provided though. – zzzzBov Nov 04 '11 at 14:09
  • The colours look nice together, but I can't see how they are 'corresponding'. There doesn't seem to be much of a relationship between the colours apart from the fact that they're both blue. – Mick Sear Nov 04 '11 at 14:10

5 Answers5

4

There are formulas that convert an RGB color to HSV (Hue, Saturation and Value). From the HSV you can change any of the HSV components and then convert back to RGB. I've found stuff online and done this before. Let me know if you want more details on the algorithms, I can dig them up for you if you want.

rogerlsmith
  • 6,670
  • 2
  • 20
  • 25
  • How did you get the idea (out of curiosity) that the question is about mapping back and forth between RGB and HSV color spaces? – Pointy Nov 04 '11 at 14:07
  • thanks, I could search for that myself, I just want ideas on how to do this :) – Alex Nov 04 '11 at 14:07
  • 1
    ah I see - convert to HSV, reduce "V", then convert back :-) – Pointy Nov 04 '11 at 14:09
  • @Pointy converting to HSV is the only way that I know of that will allow you to take an RGB color and darken or lighten it. – rogerlsmith Nov 04 '11 at 14:10
  • The other thing you could do is interpolate on a "straight line" through RGB color space from the starting color back to (0, 0, 0). – Pointy Nov 04 '11 at 14:11
  • I do this on my own website, however I change the hue based on the time of day. In a 24 hour period, my site changes colors through the entire spectrum of hues. – rogerlsmith Nov 04 '11 at 14:11
  • @Pointy, interpolation will kind of work, but you might find it'll make it greyer too... a bit like reducing the S and V of HSV. – Nathan MacInnes Nov 04 '11 at 14:17
  • Just reduce the R, G and B components uniformly and cap at 0. This will reduce brightness but keep the hue and saturation. – Polynomial Nov 04 '11 at 14:19
  • Yes true, though the OP doesn't appear to be too picky in this case :-) – Pointy Nov 04 '11 at 14:22
  • I found out this: http://serennu.com/colour/rgbtohsl.php . Do you think I can use HSL to get the darker color? I've played with the Hue/Saturation function from Photoshop and I think I can – Alex Nov 04 '11 at 14:33
  • @Alex - It looks worth a try. If you have problems, let me know. I have code that I know works, I just have to dig it up. :) – rogerlsmith Nov 04 '11 at 14:36
  • ok I found out the Photoshop thing, it's Hue: +13 and Lightness: -28. Now the problem is how do I change this in the PHP function, because there I see that H/S/L have float values between 0 and 1... – Alex Nov 04 '11 at 14:41
  • I've posted RGB-HSV conversion routines (PHP) on my website. I also included the function I use to convert time of day into Hue. See this url: http://rogerlsmith.net/index.php/blog/19-programming/18-color-conversion-code – rogerlsmith Nov 04 '11 at 14:51
  • I think so, V = Value; L = Lumination. I also posted the code on GitHub @ https://gist.github.com/1339510 – rogerlsmith Nov 04 '11 at 14:58
  • thanks, but I still get 0-1 values, which I don't know how to change :( In Photopsop H can take values from -180 to +180, and V (or L) from -100 to +100 – Alex Nov 04 '11 at 15:10
  • Try multiplying the 0 to 1 number by 255. This should give you something valid. – rogerlsmith Nov 04 '11 at 15:14
  • ok I found it:D it's H = current_H + 0.036 and V = current_V - 0.122. It seems to generate dark colors correctly. PS: your functions seem to generate inaccurate S and V values, you should use the ones I have posted (or maybe hsl =/= hsv?) – Alex Nov 04 '11 at 15:27
1

#XXXXXX represent hexa decimal number in colors for RED, GREEN and BLUE, each two characters from left to right if you increase the number it will get light, if decrease the number, it will be darker.

Pointy
  • 405,095
  • 59
  • 585
  • 614
Riz
  • 9,703
  • 8
  • 38
  • 54
1

You need to convert the RGB value to HSL or HSV and then you can decrease the L (luma) or V (value) component as you wish and then convert back to RGB.

see this answer for example code: RGB to HSV in PHP

Community
  • 1
  • 1
case nelson
  • 3,537
  • 3
  • 30
  • 37
1

The easiest way to tinker with how colours are perceived (ie, lighter, darker, brighter, duller, etc) is to convert it to HSL. There are plenty of resources online for converting RGB to HSL and back again in PHP and JavaScript. Google will find you as many implementations as you want. Then to decrease the lightness, reduce the L value (multiply by 0.75 or similar) and convert back to RGB.

Nathan MacInnes
  • 11,033
  • 4
  • 35
  • 50
-1
function hex_to_hue($hexcode, $percent) {
        $redhex = substr($hexcode, 0, 2);
        $greenhex = substr($hexcode, 2, 2);
        $bluehex = substr($hexcode, 4, 2);

        // $var_r, $var_g and $var_b are the three decimal fractions to be input to our RGB-to-HSL conversion routine
        $var_r = (hexdec($redhex)) / 255;
        $var_g = (hexdec($greenhex)) / 255;
        $var_b = (hexdec($bluehex)) / 255;

        // Input is $var_r, $var_g and $var_b from above
        // Output is HSL equivalent as $h, $s and $l — these are again expressed as fractions of 1, like the input values

        $var_min = min($var_r, $var_g, $var_b);
        $var_max = max($var_r, $var_g, $var_b);
        $del_max = $var_max - $var_min;

        $l = ($var_max + $var_min) / 2;

        if ($del_max == 0) {
            $h = 0;
            $s = 0;
        } else {
            if ($l < 0.5) {
                $s = $del_max / ($var_max + $var_min);
            } else {
                $s = $del_max / (2 - $var_max - $var_min);
            }
            ;

            $del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
            $del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
            $del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;

            if ($var_r == $var_max) {
                $h = $del_b - $del_g;
            } else if ($var_g == $var_max) {
                $h = (1 / 3) + $del_r - $del_b;
            } else if ($var_b == $var_max) {
                $h = (2 / 3) + $del_g - $del_r;
            }
            ;

            if ($h < 0) {
                $h += 1;
            }
            ;

            if ($h > 1) {
                $h -= 1;
            }
            ;
        }
        ;

        //return array($h, $s, $l);
// Calculate the opposite hue, $h2
        $h2 = $h + $percent;
        if ($h2 > 1) {
            $h2 -= 1;
        }

// Calculate the opposite hue, $s2
        $s2 = $s + $percent;
        if ($s2 > 1) {
            $s2 -= 1;
        }

// Calculate the opposite hue, $s2
        $l2 = $l + $percent;
        if ($l2 > 1) {
            $l2 -= 1;
        }
        return array($h2, $s2, $l2);
    }
Jiri
  • 1