Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Philips hue, convert xy from api to HEX or RGB

I am making a web interface to manage my hue lamps, but i am struggling when it comes to color handling..

The api of the lamps provides me the x and y coordinates from http://en.wikipedia.org/wiki/CIE_1931_color_space

But not the z value.

I think i must calculate the z from the brightness value or saturation value (0 to 255).

but i am terrible at colors, and math :p.

I tried to use thoses functions https://github.com/eikeon/hue-color-converter/blob/master/colorconverter.ts

But as i saw in the comments, thoses functions do not provide correct values...

Could someone help me here please ? ☺

ps : i need a javascript function.

like image 956
Jeremie4zw Avatar asked Apr 06 '14 13:04

Jeremie4zw


3 Answers

Okay so i manage to make something working with the help of : How do I convert an RGB value to a XY value for the Phillips Hue Bulb

function xyBriToRgb(x, y, bri){
            z = 1.0 - x - y;
            Y = bri / 255.0; // Brightness of lamp
            X = (Y / y) * x;
            Z = (Y / y) * z;
            r = X * 1.612 - Y * 0.203 - Z * 0.302;
            g = -X * 0.509 + Y * 1.412 + Z * 0.066;
            b = X * 0.026 - Y * 0.072 + Z * 0.962;
            r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
            g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
            b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
            maxValue = Math.max(r,g,b);
            r /= maxValue;
            g /= maxValue;
            b /= maxValue;
            r = r * 255;   if (r < 0) { r = 255 };
            g = g * 255;   if (g < 0) { g = 255 };
            b = b * 255;   if (b < 0) { b = 255 };
            return {
                r :r,
                g :g,
                b :b
            }
        }

Its not very very precise, but it works quite well. If someone manage to make something better, please post it here, thanks.

like image 119
Jeremie4zw Avatar answered Sep 19 '22 12:09

Jeremie4zw


I modified your script to return the rgb value in HEX Notation:

function xyBriToRgb(x, y, bri)
{
    z = 1.0 - x - y;

    Y = bri / 255.0; // Brightness of lamp
    X = (Y / y) * x;
    Z = (Y / y) * z;
    r = X * 1.612 - Y * 0.203 - Z * 0.302;
    g = -X * 0.509 + Y * 1.412 + Z * 0.066;
    b = X * 0.026 - Y * 0.072 + Z * 0.962;
    r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
    g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
    b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
    maxValue = Math.max(r,g,b);
    r /= maxValue;
    g /= maxValue;
    b /= maxValue;
    r = r * 255;   if (r < 0) { r = 255 };
    g = g * 255;   if (g < 0) { g = 255 };
    b = b * 255;   if (b < 0) { b = 255 };

    r = Math.round(r).toString(16);
    g = Math.round(g).toString(16);
    b = Math.round(b).toString(16);

    if (r.length < 2)
        r="0"+r;        
    if (g.length < 2)
        g="0"+g;        
    if (b.length < 2)
        b="0"+r;        
    rgb = "#"+r+g+b;

    return rgb;             
}
alert(xyBriToRgb(0.5052,0.4151, 254));

And i made a PHP Version:

function xyBriToRgb($x,$y,$bri)
{
    $z = 1.0 - $x - $y;
    $Y = $bri / 255.0;
    $X = ($Y / $y) * $x;
    $Z = ($Y / $y) * $z;

    $r = $X * 1.612 - $Y * 0.203 - $Z * 0.302;
    $g = ($X * -1) * 0.509 + $Y * 1.412 + $Z * 0.066;
    $b = $X * 0.026 - $Y * 0.072 + $Z * 0.962;

    $r = $r <= 0.0031308 ? 12.92 * $r : (1.0 + 0.055) * pow($r, (1.0 / 2.4)) - 0.055;
    $g = $g <= 0.0031308 ? 12.92 * $g : (1.0 + 0.055) * pow($g, (1.0 / 2.4)) - 0.055;
    $b = $b <= 0.0031308 ? 12.92 * $b : (1.0 + 0.055) * pow($b, (1.0 / 2.4)) - 0.055;

    $maxValue = max( $r , $g, $b );

    $r = $r / $maxValue;
    $g = $g / $maxValue;
    $b = $b / $maxValue;

    $r = $r * 255; if ($r < 0) $r = 255;
    $g = $g * 255; if ($g < 0) $g = 255;
    $b = $b * 255; if ($b < 0) $b = 255;

    $r = dechex(round($r));
    $g = dechex(round($g));
    $b = dechex(round($b));

    if (strlen($r) < 2)     $r = "0" + $r;
    if (strlen($g) < 2)     $g = "0" + $g;
    if (strlen($b) < 2)     $b = "0" + $b;

    return "#".$r.$g.$b;
}
print xyBriToRgb(0.5052,0.4151, 254);

Happy coding to ye all :-)

like image 37
Mikjaer Avatar answered Sep 18 '22 12:09

Mikjaer


At the end it should probably be

r = Math.round(r * 255); if (r < 0) { r = 0; }
g = Math.round(g * 255); if (g < 0) { g = 0; }
b = Math.round(b * 255); if (b < 0) { b = 0; }

If r,g or b is smaller than 0, shouldn't it be 0 instead of 255? The colors I tested make more sense that way. Thanks for the formula though!

like image 22
Sogeman Avatar answered Sep 18 '22 12:09

Sogeman