Skip to content

Instantly share code, notes, and snippets.

@aemkei
Forked from 140bytes/LICENSE.txt
Created October 30, 2011 14:15
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save aemkei/1325937 to your computer and use it in GitHub Desktop.
Save aemkei/1325937 to your computer and use it in GitHub Desktop.
hsl2rgb - 140byt.es

hsl2rgb - 140byt.es

This method converts color values from hue-saturation-lightness (HSL) to it's red-green-blue representation.

Check out the demo!

Special thanks to tsaniel, Alex Kloss, subzey, Jed Schmidt, and maettig for there unbelievable magic and effort!

For more information

See the 140byt.es site for a showcase of entries (built itself using 140-byte entries!), and follow @140bytes on Twitter.

To learn about byte-saving hacks for your own code, or to contribute what you've learned, head to the wiki.

140byt.es is brought to you by Jed Schmidt, with help from Alex Kloss. It was inspired by work from Thomas Fuchs and Dustin Diaz.

function(
a, // hue
b, // saturation
c // lightness
){
a *= 6;
b = [
c += b *= c < .5 ?
c :
1 - c,
c - a % 1 * b * 2,
c -= b *= 2,
c,
c + a % 1 * b,
c + b
];
return[
b[ ~~a % 6 ], // red
b[ (a|16) % 6 ], // green
b[ (a|8) % 6 ] // blue
]
}
function(a,b,c){a*=6;b=[c+=b*=c<.5?c:1-c,c-a%1*b*2,c-=b*=2,c,c+a%1*b,c+b];return[b[~~a%6],b[(a|16)%6],b[(a|8)%6]]}
// With proper error checking for all positive values. Saturation and lightness is clipped at 1.
function(a,b,c){a*=6;b=b>1||b;c=c>1||c;b=[c+=b*=c<.5?c:1-c,c-a%1*b*2,c-=b*=2,c,c+a%1*b,c+b];return[b[~~a%6],b[(a|16)%6],b[(a|8)%6]]}
// This version (137 bytes) uses a range from 0..360 for hue and 0..100 for saturation and lightness.
function(a,b,c){a/=60;c/=100;b=[c+=b*=(c<.5?c:1-c)/100,c-a%1*b*2,c-=b*=2,c,c+a%1*b,c+b];return[b[~~a%6],b[(a|16)%6],b[(a|8)%6]]}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 YOUR_NAME_HERE <YOUR_URL_HERE>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "hsl2rgb",
"description": "Converts hue-saturation-lightness to red-green-blue color value.",
"contributors": [
{
"name" : "Martin Kleppe",
"url" : "https://github.com/aemkei"
},
{
"name" : "tsaniel",
"url" : "https://github.com/tsaniel"
},
{
"name" : "Alex Kloss",
"url" : "https://github.com/atk"
},
{
"name" : "subzey",
"url" : "https://github.com/subzey"
},
{
"name": "Jed Schmidt",
"url": "https://github.com/jed"
},
{
"name": "maettig",
"url": "https://github.com/maettig"
}
],
"keywords": [
"color",
"convert",
"hsl",
"rgb"
]
}
<!DOCTYPE html>
<title>hsl2rgb - 140byt.es</title>
<style type="text/css" media="screen">
span {
display: inline-block;
width: 8px;
height: 8px;
}
#output {
margin-bottom: 1em;
}
#output div {
height: 8px;
}
</style>
<div id="output"></div>
<a href="https://gist.github.com/1325937">Source Code</a>
<script>
var hsl=function(a,b,c){a*=6;b=[c+=b*=c<.5?c:1-c,c-a%1*b*2,c-=b*=2,c,c+a%1*b,c+b];return[b[~~a%6],b[(a|16)%6],b[(a|8)%6]]}
var html = "", h, s, l, rgb;
for (h = 0; h <= 1; h += 0.1){
html += "<div>";
for (s = 0; s <= 1; s += 0.3){
for (l = 0; l <= 1; l += 0.1){
rgb = hsl(h, s, l);
rgb = [
~~(rgb[0] * 255),
~~(rgb[1] * 255),
~~(rgb[2] * 255)
].join(",")
html += "<span style='background:rgb(" + rgb + ")'></span>"
}
}
html += "</div>";
}
document.getElementById("output").innerHTML = html;
</script>
@p01
Copy link

p01 commented Nov 10, 2011

@maetig: @subzey approach is actually pretty simple. In the end, a is an integer in the range [ 0; 5 ], in short it only uses the 3 LSB. We are looking for a shorter way to write a=0|a%6 , (a+2)%6 and (a+4)%6 . With the knowledge that a|0 only uses the 3 LSB, we can just look for a numbers that don't touch those bits and whose modulo 6 is either 2 or 4. And that's what we have: 8%6==2 and 16%6==4

Actually, we can probably save 2 more bytes by doing:

/* ... */return[b[0|a],b[(a|16)%6],b[(a|8)%6]]}

Sorry if I missed that shot. Haven't read the whole comments thread :p

@maettig
Copy link

maettig commented Nov 10, 2011

@p01, thanks, but this will break the function if hue is 1. Then your b[0|a] becomes b[6]. Unfortunately this is not checked in test.html. See my comment above.
@aemkei, please edit the "137 bytes" in index2.js.

@p01
Copy link

p01 commented Nov 10, 2011

I see. My bad.
Didn't realize a was actually in the range [ 0 ; 1 ] not [ 0 ; 1 [

@aemkei
Copy link
Author

aemkei commented Nov 15, 2011

Psst: https://gist.github.com/1362710 - Rubik's Pocket Cube solver in 123 bytes.

@LeverOne
Copy link

// 113

function(a,b,c){a*=6;b=[c-=b*=c<.5?c:1-c,c+a%1*b*2,c+=b*=2,c-a%1*b];return[b[c=~a/.3,c+1.3&3],b[c&3],b[c+2.6&3]]}

http://jsperf.com/hsl2rgb-golf/4

@aemkei
Copy link
Author

aemkei commented Nov 16, 2011

@LeverOne: Not sure if using 0.3, 1.3 and 2.6 will generate correct results for all values.

@maettig
Copy link

maettig commented Nov 17, 2011

I wrote a test to compare the solutions. I'm not sure why, but @LeverOne's works. I need some time to dig down to this. I have the feeling there is an other byte we can save.

About your Rubik's Pocket Cube solver. Yes, it's impressive. Good work. Many new tricks to learn. Just a little problem. The main logic comes from the turn and spin arrays. You can not tell this a "Rubik's Pocket Cube solver in 123 bytes" without counting the arrays. Same problem with all Base64 encoders at 140byt.es.

@LeverOne
Copy link

var hsl_old=function(a,b,c){a*=6;b=[c+=b*=c<.5?c:1-c,c-a%1*b*2,c-=b*=2,c,c+a%1*b,c+b];return[b[~~a%6],b[(a|16)%6],b[(a|8)%6]]}

var hsl_new=function(a,b,c){a*=6;b=[c-=b*=c<.5?c:1-c,c+a%1*b*2,c+=b*=2,c-a%1*b];return[b[c=~a/.3,c+1.3&3],b[c&3],b[c+2.6&3]]}


var  h, s, l;


try{

// test № 1

for (h = 0; h <= 1; h += 0.1){

  for (s = 0; s <= 1; s += 0.3){
    for (l = 0; l <= 1; l += 0.1){
      rgb_old = hsl_old(h, s, l);

      rgb_new = hsl_new(h, s, l);

if(rgb_old[0].toFixed(3)==rgb_new[0].toFixed(3)&&rgb_old[1].toFixed(3)==rgb_new[1].toFixed(3)&&rgb_old[2].toFixed(3)==rgb_new[2].toFixed(3))0;
else throw "something is wrong.";

    }
  }
}


// test № 2

for (h = 0; h <= 1; h = +(h+0.1).toFixed(1)){

  for (s = 0; s <= 1; s = +(s+ 0.3).toFixed(1)){
    for (l = 0; l <= 1; l = +(l+ 0.1).toFixed(1)){
      rgb_old = hsl_old(h, s, l);

      rgb_new = hsl_new(h, s, l);

if(rgb_old[0].toFixed(3)==rgb_new[0].toFixed(3)&&rgb_old[1].toFixed(3)==rgb_new[1].toFixed(3)&&rgb_old[2].toFixed(3)==rgb_new[2].toFixed(3))0;
else throw "something is wrong."


    }
  }
}


alert('We generate correct results for all values.');

}catch(e){alert(e)}



//Because I use the reverse order of values ​​in the array, 
//the error will be the same as in the old version of the hsl2rgb function,
//but in the opposite direction.

alert("hsl:0.02,0.15,0.25\n\nrgb_old:"+hsl_old(0.02,0.15,0.25)+"\n\nrgb_new:"+hsl_new(0.02,0.15,0.25));

alert("hsl:0.02,0.45,0.75\n\nrgb_old:"+hsl_old(0.02,0.45,0.75)+"\n\nrgb_new:"+hsl_new(0.02,0.45,0.75));

@subzey, with fuzzer, joke :) And yes, jsperf's results are questionable. These different versions can not have equal speed in some browsers.

@subzey
Copy link

subzey commented Nov 17, 2011

Another 113 bytes version. Just used rotation of b array by 1:

function(a,b,c){a*=6;b=[c+=b*=c<.5?c:1-c,c,c-a%1*b*2,c-=b*=2,c,c+a%1*b];return[b[-~a%6],b[(4-~a)%6],b[(2-~a)%6]]}

UPD: It seems that @LeverOne's 113 is faster: jsperf test. @LeverOne, how did you do it? :)

@aemkei
Copy link
Author

aemkei commented Jan 27, 2012

Off topic: Have a look at my latest 140byt.es project: The classic Tetris game in 138 bytes!
https://gist.github.com/1672254

@12Me21
Copy link

12Me21 commented Jul 29, 2016

(h,s,l)=>{h*=6;s*=l<.5?l:1-l;H=++h|0;r[2]=0;r[H/2%3|0]=s*2;r[2-H%3]=Math.abs(h%2-1);return r.map(x=>((x+=l-s)<1?x:1)*255|0)}
124 bytes with actual RGB output (0-255). input is 0-1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment