I found this RGB to HSL script over at http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript. I can't find any other small decent ones. The issue is that this code doesn't even really work. Would anybody know why? (I don't know a bit of color math, but maybe it's returning the complementary?)
function rgbToHsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
Edit: when I run rgbToHsl(126,210,22)
it's giving me [ .24, .81, .45 ], which is the HSL for an orange color.
Formats like RGB and Hex are more machine-readable than human-readable. HSL, the opposite, is meant to be understandable by humans better. HSL is a more recent and spontaneous way to work with colors.
HSL to RGB conversion formula When 0 ≤ H < 360, 0 ≤ S ≤ 1 and 0 ≤ L ≤ 1: C = (1 - |2L - 1|) × S. X = C × (1 - |(H / 60°) mod 2 - 1|) m = L - C/2. (R,G,B) = ((R'+m)×255, (G'+m)×255,(B'+m)×255)
HSL (for hue, saturation, lightness) and HSV (for hue, saturation, value; also known as HSB, for hue, saturation, brightness) are alternative representations of the RGB color model, designed in the 1970s by computer graphics researchers to more closely align with the way human vision perceives color-making attributes.
R, G, B in RGB are all co-related to the color luminance( what we loosely call intensity),i.e., We cannot separate color information from luminance. HSV or Hue Saturation Value is used to separate image luminance from color information. This makes it easier when we are working on or need luminance of the image/frame.
The resulting HSV array has to be interpreted as three fractions. For some programs, if you want to express HSV as integers, you multiply the "H" value by 360 and the "S" and "V" values by 100. The HSV value you quote for your green shade RGB[126, 210, 22] is HSV [87, 81, 45] in integers. You could change the function to return such integers if you want to:
function rgbToHsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [Math.floor(h * 360), Math.floor(s * 100), Math.floor(l * 100)];
}
[edit] that said, it's still giving me something with a brightness ("L" or "V") that's considerably too dark; Gimp says that the HSV value should be [90, 80, 82], or in fractional terms [.20, .80, .82].
[another edit] well one problem could be that HSL and HSV are different schemes ... still looking around.
OK in case anybody wants RGB to HSV (like you'd see in Gimp for example) here's a version of that:
function rgbToHsv(r, g, b) {
var
min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s, v = max;
v = Math.floor(max / 255 * 100);
if ( max != 0 )
s = Math.floor(delta / max * 100);
else {
// black
return [0, 0, 0];
}
if( r == max )
h = ( g - b ) / delta; // between yellow & magenta
else if( g == max )
h = 2 + ( b - r ) / delta; // between cyan & yellow
else
h = 4 + ( r - g ) / delta; // between magenta & cyan
h = Math.floor(h * 60); // degrees
if( h < 0 ) h += 360;
return [h, s, v];
}
It looks that your code is ok (but it returns hue=0.24 - multiply this by 360 degree to get angle integer value) - however Try this shorter one ( more: hsl2rgb, rgb2hsv, hsv2rgb and sl22sv):
// in: r,g,b in [0,1], out: h in [0,360) and s,l in [0,1]
function rgb2hsl(r,g,b) {
let v=Math.max(r,g,b), c=v-Math.min(r,g,b), f=(1-Math.abs(v+v-c-1));
let h= c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c));
return [60*(h<0?h+6:h), f ? c/f : 0, (v+v-c)/2];
}
function rgb2hsl(r,g,b) {
let v=Math.max(r,g,b), c=v-Math.min(r,g,b), f=(1-Math.abs(v+v-c-1));
let h= c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c));
return [60*(h<0?h+6:h), f ? c/f : 0, (v+v-c)/2];
}
console.log(`rgb: (0.36,0.3,0.24) --> hsl: (${rgb2hsl(0.36,0.3,0.24)})`);
// ---------------
// UX
// ---------------
rgb= [0,0,0];
hs= [0,0,0];
let $ = x => document.querySelector(x);
let hsl2rgb = (h,s,l, a=s*Math.min(l,1-l), f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1)) => [f(0),f(8),f(4)];
function changeRGB(i,e) {
rgb[i]=e.target.value/255;
hs = rgb2hsl(...rgb);
refresh();
}
function changeHS(i,e) {
hs[i]=e.target.value/(i?255:1);
rgb= hsl2rgb(...hs);
refresh();
}
function refresh() {
rr = rgb.map(x=>x*255|0).join(', ')
tr = `RGB: ${rr}`
th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+'%':x|0).join(', ')}`
$('.box').style.backgroundColor=`rgb(${rr})`;
$('.infoRGB').innerHTML=`${tr}`;
$('.infoHS').innerHTML =`${th}`;
$('#r').value=rgb[0]*255;
$('#g').value=rgb[1]*255;
$('#b').value=rgb[2]*255;
$('#h').value=hs[0];
$('#s').value=hs[1]*255;
$('#l').value=hs[2]*255;
}
refresh();
.box {
width: 50px;
height: 50px;
margin: 20px;
}
body {
display: flex;
}
<div>
<input id="r" type="range" min="0" max="255" oninput="changeRGB(0,event)">R<br>
<input id="g" type="range" min="0" max="255" oninput="changeRGB(1,event)">G<br>
<input id="b" type="range" min="0" max="255" oninput="changeRGB(2,event)">B<br>
<pre class="infoRGB"></pre>
</div>
<div>
<div class="box hsl"></div>
</div>
<div>
<input id="h" type="range" min="0" max="360" oninput="changeHS(0,event)">H<br>
<input id="s" type="range" min="0" max="255" oninput="changeHS(1,event)">S<br>
<input id="l" type="range" min="0" max="255" oninput="changeHS(2,event)">L<br>
<pre class="infoHS"></pre><br>
</div>
I develop S_HSL wiki formulas (marked by green border) - where MAX=max(r,g,b) and MIN=min(r,g,b) - and in above code I make some improvements and make analysis which shows that results are correct. This allows me to get quite short code at the end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With