HSL to RGB color conversion

I am looking for an algorithm to convert between HSL color to RGB.

It seems to me that HSL is not very widely used so I am not having much luck searching for a converter.

9

22 Answers

Garry Tan posted a Javascript solution on his blog (which he attributes to a now defunct mjijackson.com, but is archived here and the original author has a gist - thanks to user2441511).

The code is re-posted below:

HSL to RGB:

/** * Converts an HSL color value to RGB. Conversion formula * adapted from * Assumes h, s, and l are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. * * @param {number} h The hue * @param {number} s The saturation * @param {number} l The lightness * @return {Array} The RGB representation */ function hslToRgb(h, s, l){ var r, g, b; if(s == 0){ r = g = b = l; // achromatic }else{ var hue2rgb = function hue2rgb(p, q, t){ if(t < 0) t += 1; if(t > 1) t -= 1; if(t < 1/6) return p + (q - p) * 6 * t; if(t < 1/2) return q; if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; } var q = l < 0.5 ? l * (1 + s) : l + s - l * s; var p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } 

RGB to HSL:

/** * Converts an RGB color value to HSL. Conversion formula * adapted from * Assumes r, g, and b are contained in the set [0, 255] and * returns h, s, and l in the set [0, 1]. * * @param {number} r The red color value * @param {number} g The green color value * @param {number} b The blue color value * @return {Array} The HSL representation */ 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]; } 
24

Found the easiest way, python to the rescue :D

colorsys.hls_to_rgb(h, l, s)

Convert the color from HLS coordinates to RGB coordinates.

3

Java implementation of Mohsen's code

Note that all integer are declared as float (i.e 1f) and must be float, else you will optain grey colors.

HSL to RGB

 /** * Converts an HSL color value to RGB. Conversion formula * adapted from * Assumes h, s, and l are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. * * @param h The hue * @param s The saturation * @param l The lightness * @return int array, the RGB representation */ public static int[] hslToRgb(float h, float s, float l){ float r, g, b; if (s == 0f) { r = g = b = l; // achromatic } else { float q = l < 0.5f ? l * (1 + s) : l + s - l * s; float p = 2 * l - q; r = hueToRgb(p, q, h + 1f/3f); g = hueToRgb(p, q, h); b = hueToRgb(p, q, h - 1f/3f); } int[] rgb = {to255(r), to255(g), to255(b)}; return rgb; } public static int to255(float v) { return (int)Math.min(255,256*v); } /** Helper method that converts hue to rgb */ public static float hueToRgb(float p, float q, float t) { if (t < 0f) t += 1f; if (t > 1f) t -= 1f; if (t < 1f/6f) return p + (q - p) * 6f * t; if (t < 1f/2f) return q; if (t < 2f/3f) return p + (q - p) * (2f/3f - t) * 6f; return p; } 

RGB to HSL

/** * Converts an RGB color value to HSL. Conversion formula * adapted from * Assumes pR, pG, and bpBare contained in the set [0, 255] and * returns h, s, and l in the set [0, 1]. * * @param pR The red color value * @param pG The green color value * @param pB The blue color value * @return float array, the HSL representation */ public static float[] rgbToHsl(int pR, int pG, int pB) { float r = pR / 255f; float g = pG / 255f; float b = pB / 255f; float max = (r > g && r > b) ? r : (g > b) ? g : b; float min = (r < g && r < b) ? r : (g < b) ? g : b; float h, s, l; l = (max + min) / 2.0f; if (max == min) { h = s = 0.0f; } else { float d = max - min; s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min); if (r > g && r > b) h = (g - b) / d + (g < b ? 6.0f : 0.0f); else if (g > b) h = (b - r) / d + 2.0f; else h = (r - g) / d + 4.0f; h /= 6.0f; } float[] hsl = {h, s, l}; return hsl; } 
1

The article for HSL and HSV on wikipedia contains some formulas. The calculations are a bit tricky, so it might be useful to take a look at existing implementations.

1

If you're looking for something that definitely conforms with the CSS semantics for HSL and RGB, you could use the algorithm specified in the CSS 3 specification, which reads:

HOW TO RETURN hsl.to.rgb(h, s, l): SELECT: l<=0.5: PUT l*(s+1) IN m2 ELSE: PUT l+s-l*s IN m2 PUT l*2-m2 IN m1 PUT hue.to.rgb(m1, m2, h+1/3) IN r PUT hue.to.rgb(m1, m2, h ) IN g PUT hue.to.rgb(m1, m2, h-1/3) IN b RETURN (r, g, b) HOW TO RETURN hue.to.rgb(m1, m2, h): IF h<0: PUT h+1 IN h IF h>1: PUT h-1 IN h IF h*6<1: RETURN m1+(m2-m1)*h*6 IF h*2<1: RETURN m2 IF h*3<2: RETURN m1+(m2-m1)*(2/3-h)*6 RETURN m1 

I believe this is the source for some of the other answers here.

0

Shor but precise - JS

Use this JS code (more: rgb2hsl, hsv2rgb rgb2hsv and hsl2hsv) - php version here

// input: h as an angle in [0,360] and s,l in [0,1] - output: r,g,b in [0,1] function hsl2rgb(h,s,l) { let a=s*Math.min(l,1-l); let f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1); return [f(0),f(8),f(4)]; } 
// oneliner version 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)]; // r,g,b are in [0-1], result e.g. #0812fa. let rgb2hex = (r,g,b) => "#" + [r,g,b].map(x=>Math.round(x*255).toString(16).padStart(2,0) ).join(''); console.log(`hsl: (30,0.2,0.3) --> rgb: (${hsl2rgb(30,0.2,0.3)}) --> hex: ${rgb2hex(...hsl2rgb(30,0.2,0.3))}`); // --------------- // UX // --------------- rgb= [0,0,0]; hs= [0,0,0]; let $ = x => document.querySelector(x); function changeRGB(i,e) { rgb[i]= hs = rgb2hsl(...rgb); refresh(); } function changeHS(i,e) { hs[i]=(i?255:1); rgb= hsl2rgb(...hs); refresh(); } function refresh() { rr = rgb.map(x=>x*255|0).join(', ') hh = rgb2hex(...rgb); tr = `RGB: ${rr}` th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+'%':x|0).join(', ')}` thh= `HEX: ${hh}` $('.box').style.backgroundColor=`rgb(${rr})`; $('.infoRGB').innerHTML=`${tr}`; $('.infoHS').innerHTML =`${th}\n${thh}`; $('#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; } function rgb2hsl(r,g,b) { let a=Math.max(r,g,b), n=a-Math.min(r,g,b), f=(1-Math.abs(a+a-n-1)); let h= n && ((a==r) ? (g-b)/n : ((a==g) ? 2+(b-r)/n : 4+(r-g)/n)); return [60*(h<0?h+6:h), f ? n/f : 0, (a+a-n)/2]; } refresh();
.box { width: 50px; height: 50px; margin: 20px; } body { display: flex; }
<div> <input type="range" min="0" max="255" oninput="changeRGB(0,event)">R<br> <input type="range" min="0" max="255" oninput="changeRGB(1,event)">G<br> <input type="range" min="0" max="255" oninput="changeRGB(2,event)">B<br> <pre></pre> </div> <div> <div></div> </div> <div> <input type="range" min="0" max="360" oninput="changeHS(0,event)">H<br> <input type="range" min="0" max="255" oninput="changeHS(1,event)">S<br> <input type="range" min="0" max="255" oninput="changeHS(2,event)">L<br> <pre></pre><br> </div>

Here is formula which I discover and precisely describe in wiki + error analysis,

enter image description here

1

C# Code from Mohsen's answer.

Here is the code from Mohsen's answer in C# if anyone else wants it. Note: Color is a custom class and Vector4 is from OpenTK. Both are easy to replace with something else of your choosing.

Hsl To Rgba

/// <summary> /// Converts an HSL color value to RGB. /// Input: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] ) /// Output: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] ) /// </summary> /// <param name="hsl">Vector4 defining X = h, Y = s, Z = l, W = a. Ranges [0, 1.0]</param> /// <returns>RGBA Color. Ranges [0, 255]</returns> public static Color HslToRgba(Vector4 hsl) { float r, g, b; if (hsl.Y == 0.0f) r = g = b = hsl.Z; else { var q = hsl.Z < 0.5f ? hsl.Z * (1.0f + hsl.Y) : hsl.Z + hsl.Y - hsl.Z * hsl.Y; var p = 2.0f * hsl.Z - q; r = HueToRgb(p, q, hsl.X + 1.0f / 3.0f); g = HueToRgb(p, q, hsl.X); b = HueToRgb(p, q, hsl.X - 1.0f / 3.0f); } return new Color((int)(r * 255), (int)(g * 255), (int)(b * 255), (int)(hsl.W * 255)); } // Helper for HslToRgba private static float HueToRgb(float p, float q, float t) { if (t < 0.0f) t += 1.0f; if (t > 1.0f) t -= 1.0f; if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t; if (t < 1.0f / 2.0f) return q; if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f; return p; } 

Rgba To Hsl

/// <summary> /// Converts an RGB color value to HSL. /// Input: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] ) /// Output: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] ) /// </summary> /// <param name="rgba"></param> /// <returns></returns> public static Vector4 RgbaToHsl(Color rgba) { float r = rgba.R / 255.0f; float g = rgba.G / 255.0f; float b = rgba.B / 255.0f; float max = (r > g && r > b) ? r : (g > b) ? g : b; float min = (r < g && r < b) ? r : (g < b) ? g : b; float h, s, l; h = s = l = (max + min) / 2.0f; if (max == min) h = s = 0.0f; else { float d = max - min; s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min); if (r > g && r > b) h = (g - b) / d + (g < b ? 6.0f : 0.0f); else if (g > b) h = (b - r) / d + 2.0f; else h = (r - g) / d + 4.0f; h /= 6.0f; } return new Vector4(h, s, l, rgba.A / 255.0f); } 
1

Php Implementation of Chris's C# Code

Also from here, which explains the math of it very well.

This is basically a bunch of functions to convert to and from HSL (Hue Saturation Lightness)

Tested and working on PHP 5.6.15

TL;DR: The full code can be found here on Pastebin.


Hex to HSL

Input: Hex color in format: [#]0f4 or [#]00ff44 (pound sign optional)
Output: HSL in Degrees, Percent, Percent

/** * Input: hex color * Output: hsl(in ranges from 0-1) * * Takes the hex, converts it to RGB, and sends * it to RGBToHsl. Returns the output. * */ function hexToHsl($hex) { $r = ""; $g = ""; $b = ""; $hex = str_replace('#', '', $hex); if (strlen($hex) == 3) { $r = substr($hex, 0, 1); $r = $r . $r; $g = substr($hex, 1, 1); $g = $g . $g; $b = substr($hex, 2, 1); $b = $b . $b; } elseif (strlen($hex) == 6) { $r = substr($hex, 0, 2); $g = substr($hex, 2, 2); $b = substr($hex, 4, 2); } else { return false; } $r = hexdec($r); $g = hexdec($g); $b = hexdec($b); $hsl = rgbToHsl($r,$g,$b); return $hsl; } 

RGB to HSL

Input: RGB in range 0-255 Output: HSL in Degrees, Percent, Percent.

/** * *Credits: * * * * Called by hexToHsl by default. * * Converts an RGB color value to HSL. Conversion formula * adapted from * Assumes r, g, and b are contained in the range [0 - 255] and * returns h, s, and l in the format Degrees, Percent, Percent. * * @param Number r The red color value * @param Number g The green color value * @param Number b The blue color value * @return Array The HSL representation */ function rgbToHsl($r, $g, $b){ //For the calculation, rgb needs to be in the range from 0 to 1. To convert, divide by 255 (ff). $r /= 255; $g /= 255; $b /= 255; $myMax = max($r, $g, $b); $myMin = min($r, $g, $b); $maxAdd = ($myMax + $myMin); $maxSub = ($myMax - $myMin); //luminence is (max + min)/2 $h = 0; $s = 0; $l = ($maxAdd / 2.0); //if all the numbers are equal, there is no saturation (greyscale). if($myMin != $myMax){ if ($l < 0.5) { $s = ($maxSub / $maxAdd); } else { $s = (2.0 - $myMax - $myMin); //note order of opperations - can't use $maxSub here $s = ($maxSub / $s); } //find hue switch($myMax){ case $r: $h = ($g - $b); $h = ($h / $maxSub); break; case $g: $h = ($b - $r); $h = ($h / $maxSub); $h = ($h + 2.0); break; case $b: $h = ($r - $g); $h = ($h / $maxSub); $h = ($h + 4.0); break; } } $hsl = hslToDegPercPerc($h, $s, $l); return $hsl; } 

HSL (0-1 range) to Degrees, Percent, Percent format

For the math calculations, HSL is easier to deal with in the 0-1 range, but for human readability, it's easier in Degrees, Percent, Percent. This function takes HSL in the ranges 0-1, and returns HSL in Degrees, Percent, Percent.

/** * Input: HSL in ranges 0-1. * Output: HSL in format Deg, Perc, Perc. * * Note: rgbToHsl calls this function by default. * * Multiplies $h by 60, and $s and $l by 100. */ function hslToDegPercPerc($h, $s, $l) { //convert h to degrees $h *= 60; if ($h < 0) { $h += 360; } //convert s and l to percentage $s *= 100; $l *= 100; $hsl['h'] = $h; $hsl['s'] = $s; $hsl['l'] = $l; return $hsl; } 

HSL (Degrees, Percent, Percent format) to HSL in range 0-1

This function converts HSL in the format Degrees, Percent, Percent, to the ranges 0-1 for easier computing.

/** * Input: HSL in format Deg, Perc, Perc * Output: An array containing HSL in ranges 0-1 * * Divides $h by 60, and $s and $l by 100. * * hslToRgb calls this by default. */ function degPercPercToHsl($h, $s, $l) { //convert h, s, and l back to the 0-1 range //convert the hue's 360 degrees in a circle to 1 $h /= 360; //convert the saturation and lightness to the 0-1 //range by multiplying by 100 $s /= 100; $l /= 100; $hsl['h'] = $h; $hsl['s'] = $s; $hsl['l'] = $l; return $hsl; } 

HSL to RGB

Input: HSL in the format Degrees, Percent, Percent Output: RGB in the format 255, 255, 255.

/** * Converts an HSL color value to RGB. Conversion formula * adapted from * Assumes h, s, and l are in the format Degrees, * Percent, Percent, and returns r, g, and b in * the range [0 - 255]. * * Called by hslToHex by default. * * Calls: * degPercPercToHsl * hueToRgb * * @param Number h The hue value * @param Number s The saturation level * @param Number l The luminence * @return Array The RGB representation */ function hslToRgb($h, $s, $l){ $hsl = degPercPercToHsl($h, $s, $l); $h = $hsl['h']; $s = $hsl['s']; $l = $hsl['l']; //If there's no saturation, the color is a greyscale, //so all three RGB values can be set to the lightness. //(Hue doesn't matter, because it's grey, not color) if ($s == 0) { $r = $l * 255; $g = $l * 255; $b = $l * 255; } else { //calculate some temperary variables to make the //calculation eaisier. if ($l < 0.5) { $temp2 = $l * (1 + $s); } else { $temp2 = ($l + $s) - ($s * $l); } $temp1 = 2 * $l - $temp2; //run the calculated vars through hueToRgb to //calculate the RGB value. Note that for the Red //value, we add a third (120 degrees), to adjust //the hue to the correct section of the circle for //red. Simalarly, for blue, we subtract 1/3. $r = 255 * hueToRgb($temp1, $temp2, $h + (1 / 3)); $g = 255 * hueToRgb($temp1, $temp2, $h); $b = 255 * hueToRgb($temp1, $temp2, $h - (1 / 3)); } $rgb['r'] = $r; $rgb['g'] = $g; $rgb['b'] = $b; return $rgb; } 

Hue to RGB

This function is called by hslToRgb to convert the hue into the separate RGB values.

/** * Converts an HSL hue to it's RGB value. * * Input: $temp1 and $temp2 - temperary vars based on * whether the lumanence is less than 0.5, and * calculated using the saturation and luminence * values. * $hue - the hue (to be converted to an RGB * value) For red, add 1/3 to the hue, green * leave it alone, and blue you subtract 1/3 * from the hue. * * Output: One RGB value. * * Thanks to Easy RGB for this function (Hue_2_RGB). * * */ function hueToRgb($temp1, $temp2, $hue) { if ($hue < 0) { $hue += 1; } if ($hue > 1) { $hue -= 1; } if ((6 * $hue) < 1 ) { return ($temp1 + ($temp2 - $temp1) * 6 * $hue); } elseif ((2 * $hue) < 1 ) { return $temp2; } elseif ((3 * $hue) < 2 ) { return ($temp1 + ($temp2 - $temp1) * ((2 / 3) - $hue) * 6); } return $temp1; } 

HSL to Hex

Input: HSL in format Degrees, Percent, Percent Output: Hex in format 00ff22 (no pound sign).

Converts to RGB, then converts separately to hex.

/** * Converts HSL to Hex by converting it to * RGB, then converting that to hex. * * string hslToHex($h, $s, $l[, $prependPound = true] * * $h is the Degrees value of the Hue * $s is the Percentage value of the Saturation * $l is the Percentage value of the Lightness * $prependPound is a bool, whether you want a pound * sign prepended. (optional - default=true) * * Calls: * hslToRgb * * Output: Hex in the format: #00ff88 (with * pound sign). Rounded to the nearest whole * number. */ function hslToHex($h, $s, $l, $prependPound = true) { //convert hsl to rgb $rgb = hslToRgb($h,$s,$l); //convert rgb to hex $hexR = $rgb['r']; $hexG = $rgb['g']; $hexB = $rgb['b']; //round to the nearest whole number $hexR = round($hexR); $hexG = round($hexG); $hexB = round($hexB); //convert to hex $hexR = dechex($hexR); $hexG = dechex($hexG); $hexB = dechex($hexB); //check for a non-two string length //if it's 1, we can just prepend a //0, but if it is anything else non-2, //it must return false, as we don't //know what format it is in. if (strlen($hexR) != 2) { if (strlen($hexR) == 1) { //probably in format #0f4, etc. $hexR = "0" . $hexR; } else { //unknown format return false; } } if (strlen($hexG) != 2) { if (strlen($hexG) == 1) { $hexG = "0" . $hexG; } else { return false; } } if (strlen($hexB) != 2) { if (strlen($hexB) == 1) { $hexB = "0" . $hexB; } else { return false; } } //if prependPound is set, will prepend a //# sign to the beginning of the hex code. //(default = true) $hex = ""; if ($prependPound) { $hex = "#"; } $hex = $hex . $hexR . $hexG . $hexB; return $hex; } 
7

This is how I do it which is easy to remember is to think of RGB as three spokes on a wheel, 120 degrees apart.

H = hue (0-360) S = saturation (0-1) L = luminance (0-1) R1 = SIN( H ) * L G1 = SIN( H + 120 ) * L B1 = SIN( H + 240 ) * L 

The tricky part is saturation, which is to a scale down to the average of those three.

AVERAGE = (R1 + G1 + B1) / 3 R2 = ((R1 - AVERAGE) * S) + AVERAGE G2 = ((G1 - AVERAGE) * S) + AVERAGE B2 = ((B1 - AVERAGE) * S) + AVERAGE RED = R2 * 255 GREEN = G2 * 255 BLUE = B2 * 255 
4

Here's a fast, super-simple, branchless version in GLSL:

vec3 hsl2rgb( vec3 c ) { vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0, 4.0, 2.0), 6.0)-3.0)-1.0, 0.0, 1.0); return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0)); } 

Doesn't get much shorter than that ~


Link to the original proof-of-concept:

(Disclaimer: not my code!)

Here is the modified javascript function, it outputs Hue in set 0-360 degrees.

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 ; break; case g: h = 2 + ( (b - r) / d); break; case b: h = 4 + ( (r - g) / d); break; } h*=60; if (h < 0) h +=360; } return([h, s, l]); } alert(rgbToHsl(125,115,145)); 

I got this from Brandon Mathis' HSL Picker source code.

It was originally written in CoffeeScript. I converted it to JavaScript using an online converter, and took out the mechanism to verify the user input was a valid RGB value. This answer worked for my usecase, as the most up-voted answer on this post I found to not produce a valid HSL value.

Note that it returns an hsla value, with a representing opacity/transparency. 0 is completely transparent, and 1 fully opaque.

function rgbToHsl(rgb) { var a, add, b, diff, g, h, hue, l, lum, max, min, r, s, sat; r = parseFloat(rgb[0]) / 255; g = parseFloat(rgb[1]) / 255; b = parseFloat(rgb[2]) / 255; max = Math.max(r, g, b); min = Math.min(r, g, b); diff = max - min; add = max + min; hue = min === max ? 0 : r === max ? ((60 * (g - b) / diff) + 360) % 360 : g === max ? (60 * (b - r) / diff) + 120 : (60 * (r - g) / diff) + 240; lum = 0.5 * add; sat = lum === 0 ? 0 : lum === 1 ? 1 : lum <= 0.5 ? diff / add : diff / (2 - add); h = Math.round(hue); s = Math.round(sat * 100); l = Math.round(lum * 100); a = parseFloat(rgb[3]) || 1; return [h, s, l, a]; } 
2

An hsl|a color value, set in javascript, will be instantly converted to rgb|a All you need to do then is access the computed style value

document.body.style.color = 'hsla(44, 100%, 50%, 0.8)'; console.log(window.getComputedStyle(document.body).color); // displays: rgba(255, 187, 0, 0.8) 

Technically, I guess, this isn't even any lines of code - it's just done automatically. So, depending on your environment, you might be able to get away with just this. Not that there aren't a lot of very thoughtful responses here. I don't know what your goal is.

Now, what if you want to convert from rbg|a to hsl|a?

With H, S,and L in [0,1] range:

ConvertHslToRgb: function (iHsl) { var min, sv, sextant, fract, vsf; var v = (iHsl.l <= 0.5) ? (iHsl.l * (1 + iHsl.s)) : (iHsl.l + iHsl.s - iHsl.l * iHsl.s); if (v === 0) return { Red: 0, Green: 0, Blue: 0 }; min = 2 * iHsl.l - v; sv = (v - min) / v; var h = (6 * iHsl.h) % 6; sextant = Math.floor(h); fract = h - sextant; vsf = v * sv * fract; switch (sextant) { case 0: return { r: v, g: min + vsf, b: min }; case 1: return { r: v - vsf, g: v, b: min }; case 2: return { r: min, g: v, b: min + vsf }; case 3: return { r: min, g: v - vsf, b: v }; case 4: return { r: min + vsf, g: min, b: v }; case 5: return { r: v, g: min, b: v - vsf }; } } 

For when you need RGB to HSV and vice versa instead:

function rgbToHsv(r, g, b) { r /= 255, g /= 255, b /= 255; var min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h = 0, s = 0, v = max; if (min != max) { s = (delta / max); switch (max) { case r: h = (g - b) / delta + (g < b ? 6 : 0); break; case g: h = (b - r) / delta + 2; break; case b: h = (r - g) / delta + 4; break; } h /= 6; } return [h, s, v]; } function hsvToRgb(h, s, v) { var step = h / (1 / 6), pos = step - Math.floor(step), // the hue position within the current step m = (Math.floor(step) % 2) ? (1 - pos) * v : pos * v, // mix color value adjusted to the brightness(v) max = 1 * v, min = (1 - s) * v, med = m + ((1 - s) * (v - m)), r, g, b; switch (Math.floor(step)) { case 0: r = max; g = med; b = min; break; case 1: r = med; g = max; b = min; break; case 2: r = min; g = max; b = med; break; case 3: r = min; g = med; b = max; break; case 4: r = med; g = min; b = max; break; case 5: r = max; g = min; b = med; break; } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } 

Unity3D C# Code from Mohsen's answer.

Here is the code from Mohsen's answer in C# targeted specifically for Unity3D. It was adapted from the C# answer given by Alec Thilenius above.

using UnityEngine; using System.Collections; public class ColorTools { /// <summary> /// Converts an HSL color value to RGB. /// Input: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )**strong text** /// Output: Color ( R: [0.0, 1.0], G: [0.0, 1.0], B: [0.0, 1.0], A: [0.0, 1.0] ) /// </summary> /// <param name="hsl">Vector4 defining X = h, Y = s, Z = l, W = a. Ranges [0, 1.0]</param> /// <returns>RGBA Color. Ranges [0.0, 1.0]</returns> public static Color HslToRgba(Vector4 hsl) { float r, g, b; if (hsl.y == 0.0f) r = g = b = hsl.z; else { var q = hsl.z < 0.5f ? hsl.z * (1.0f + hsl.y) : hsl.z + hsl.y - hsl.z * hsl.y; var p = 2.0f * hsl.z - q; r = HueToRgb(p, q, hsl.x + 1.0f / 3.0f); g = HueToRgb(p, q, hsl.x); b = HueToRgb(p, q, hsl.x - 1.0f / 3.0f); } return new Color(r, g, b, hsl.w); } // Helper for HslToRgba private static float HueToRgb(float p, float q, float t) { if (t < 0.0f) t += 1.0f; if (t > 1.0f) t -= 1.0f; if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t; if (t < 1.0f / 2.0f) return q; if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f; return p; } /// <summary> /// Converts an RGB color value to HSL. /// Input: Color ( R: [0.0, 1.0], G: [0.0, 1.0], B: [0.0, 1.0], A: [0.0, 1.0] ) /// Output: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] ) /// </summary> /// <param name="rgba"></param> /// <returns></returns> public static Vector4 RgbaToHsl(Color rgba) { float max = (rgba.r > rgba.g && rgba.r > rgba.b) ? rgba.r : (rgba.g > rgba.b) ? rgba.g : rgba.b; float min = (rgba.r < rgba.g && rgba.r < rgba.b) ? rgba.r : (rgba.g < rgba.b) ? rgba.g : rgba.b; float h, s, l; h = s = l = (max + min) / 2.0f; if (max == min) h = s = 0.0f; else { float d = max - min; s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min); if (rgba.r > rgba.g && rgba.r > rgba.b) h = (rgba.g - rgba.b) / d + (rgba.g < rgba.b ? 6.0f : 0.0f); else if (rgba.g > rgba.b) h = (rgba.b - rgba.r) / d + 2.0f; else h = (rgba.r - rgba.g) / d + 4.0f; h /= 6.0f; } return new Vector4(h, s, l, rgba.a); } } 

For all who said that Garry Tan solution converting incorrect from RGB to HSL and back. It because he left out fraction part of number in his code. I corrected his code (javascript). Sorry for link on russian languadge, but on english absent - HSL-wiki

function toHsl(r, g, b) { r /= 255.0; g /= 255.0; b /= 255.0; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var h, s, l = (max + min) / 2.0; if(max == min) { h = s = 0; } else { var d = max - min; s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min)); if(max == r && g >= b) { h = 1.0472 * (g - b) / d ; } else if(max == r && g < b) { h = 1.0472 * (g - b) / d + 6.2832; } else if(max == g) { h = 1.0472 * (b - r) / d + 2.0944; } else if(max == b) { h = 1.0472 * (r - g) / d + 4.1888; } } return { str: 'hsl(' + parseInt(h / 6.2832 * 360.0 + 0.5) + ',' + parseInt(s * 100.0 + 0.5) + '%,' + parseInt(l * 100.0 + 0.5) + '%)', obj: { h: parseInt(h / 6.2832 * 360.0 + 0.5), s: parseInt(s * 100.0 + 0.5), l: parseInt(l * 100.0 + 0.5) } }; }; 

PHP implementation of @Mohsen's code (including Test!)

Sorry to re-post this. But I really haven't seen any other implementation that gives the quality I needed.

/** * Converts an HSL color value to RGB. Conversion formula * adapted from * Assumes h, s, and l are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. * * @param {number} h The hue * @param {number} s The saturation * @param {number} l The lightness * @return {Array} The RGB representation */ function hue2rgb($p, $q, $t){ if($t < 0) $t += 1; if($t > 1) $t -= 1; if($t < 1/6) return $p + ($q - $p) * 6 * $t; if($t < 1/2) return $q; if($t < 2/3) return $p + ($q - $p) * (2/3 - $t) * 6; return $p; } function hslToRgb($h, $s, $l){ if($s == 0){ $r = $l; $g = $l; $b = $l; // achromatic }else{ $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s; $p = 2 * $l - $q; $r = hue2rgb($p, $q, $h + 1/3); $g = hue2rgb($p, $q, $h); $b = hue2rgb($p, $q, $h - 1/3); } return array(round($r * 255), round($g * 255), round($b * 255)); } /* Uncomment to test * / for ($i=0;$i<360;$i++) { $rgb=hslToRgb($i/360, 1, .9); echo '<div></div>'; } /* End Test */ 
0

C++ implementation with probably better performance than @Mohsen code. It uses a [0-6] range for the hue, avoiding the division and multiplication by 6. S and L range is [0,1]

void fromRGBtoHSL(float rgb[], float hsl[]) { const float maxRGB = max(rgb[0], max(rgb[1], rgb[2])); const float minRGB = min(rgb[0], min(rgb[1], rgb[2])); const float delta2 = maxRGB + minRGB; hsl[2] = delta2 * 0.5f; const float delta = maxRGB - minRGB; if (delta < FLT_MIN) hsl[0] = hsl[1] = 0.0f; else { hsl[1] = delta / (hsl[2] > 0.5f ? 2.0f - delta2 : delta2); if (rgb[0] >= maxRGB) { hsl[0] = (rgb[1] - rgb[2]) / delta; if (hsl[0] < 0.0f) hsl[0] += 6.0f; } else if (rgb[1] >= maxRGB) hsl[0] = 2.0f + (rgb[2] - rgb[0]) / delta; else hsl[0] = 4.0f + (rgb[0] - rgb[1]) / delta; } } void fromHSLtoRGB(const float hsl[], float rgb[]) { if(hsl[1] < FLT_MIN) rgb[0] = rgb[1] = rgb[2] = hsl[2]; else if(hsl[2] < FLT_MIN) rgb[0] = rgb[1] = rgb[2] = 0.0f; else { const float q = hsl[2] < 0.5f ? hsl[2] * (1.0f + hsl[1]) : hsl[2] + hsl[1] - hsl[2] * hsl[1]; const float p = 2.0f * hsl[2] - q; float t[] = {hsl[0] + 2.0f, hsl[0], hsl[0] - 2.0f}; for(int i=0; i<3; ++i) { if(t[i] < 0.0f) t[i] += 6.0f; else if(t[i] > 6.0f) t[i] -= 6.0f; if(t[i] < 1.0f) rgb[i] = p + (q - p) * t[i]; else if(t[i] < 3.0f) rgb[i] = q; else if(t[i] < 4.0f) rgb[i] = p + (q - p) * (4.0f - t[i]); else rgb[i] = p; } } } 

HSL to RGB in Typescript

All the options above didn't work on my code in TS.

I tweak one of those and now it works as a charm:

type HslType = { h: number; s: number; l: number } const hslToRgb = (hsl: HslType): RgbType => { let { h, s, l } = hsl // IMPORTANT if s and l between 0,1 remove the next two lines: s /= 100 l /= 100 const k = (n: number) => (n + h / 30) % 12 const a = s * Math.min(l, 1 - l) const f = (n: number) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))) return { r: Math.round(255 * f(0)), g: Math.round(255 * f(8)), b: Math.round(255 * f(4)), } } 

I needed a really light weight one, Its not 100%, but it gets close enough for some usecases.

float3 Hue(float h, float s, float l) { float r = max(cos(h * 2 * UNITY_PI) * 0.5 + 0.5, 0); float g = max(cos((h + 0.666666) * 2 * UNITY_PI) * 0.5 + 0.5, 0); float b = max(cos((h + 0.333333) * 2 * UNITY_PI) * 0.5 + 0.5, 0); float gray = 0.2989 * r + 0.5870 * g + 0.1140 * b; return lerp(gray, float3(r, g, b), s) * smoothstep(0, 0.5, l) + 1 * smoothstep(0.5, 1, l); } 

PHP - shortest but precise

Here I rewrite my JS answer (math details are there) to PHP - you can run it here

function hsl2rgb($h,$s,$l) { $a = $s * min($l, 1-$l); $k = function($n,$h) { return ($n+$h/30)%12;}; $f = function($n) use ($h,$s,$l,$a,$k) { return $l - $a * max( min($k($n,$h)-3, 9-$k($n,$h), 1),-1); }; return [ $f(0), $f(8), $f(4) ]; } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like