Last active
December 26, 2018 16:24
-
-
Save stephencweiss/eab510dabb2ba50652434372e46b5980 to your computer and use it in GitHub Desktop.
Color conversion algorithms for HSV, HSL, and RGB in Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This gist covers the conversion of color values. | |
* It includes: | |
* 1) hsvFromRGB | |
* 2) rgbFromHSV | |
* 3) hslFromRGB | |
* 4) rgbFromHSL | |
* 5) hexFromRGB | |
* 6) rgbFromHex | |
* | |
* The primary inspiration for this was the work done by https://gist.github.com/mjackson/5311256 | |
* Source I found helpful for understanding the details and deriving the values include: | |
* [Wikipedia: HSL and HSV](https://en.wikipedia.org/wiki/HSL_and_HSV) | |
* [CS StackExchange: Convert HSV to RGB Colors](https://cs.stackexchange.com/questions/64549/convert-hsv-to-rgb-colors) | |
* [Rapid Tables](https://www.rapidtables.com/) | |
* [MDN: parseInt()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) | |
* [MDN: toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) | |
*/ | |
function hsvFromRGB(r, g, b) { | |
/** | |
* I: Three arguments, red (r), green (g), blue (b), all ∈ [0, 255] | |
* O: An array of three elements hue (h) ∈ [0, 360], and saturation (s) and value (v) which are both ∈ [0, 1] | |
*/ | |
r /= 255, g /= 255, b /= 255; | |
const max = Math.max(r, g, b); | |
const min = Math.min(r, g, b); | |
const diff = max - min; | |
let h, s; | |
// Value | |
const v = max; | |
// Saturation | |
s = (max === 0) ? 0 : (diff / max); | |
// Hue | |
if (diff === 0) { | |
h = 0; | |
} else { | |
// 1/6 is equivalent to 60 degrees | |
if (max === r) { h = 1/6 * (0 + ((g - b) / diff)) }; | |
if (max === g) { h = 1/6 * (2 + ((b - r) / diff)) }; | |
if (max === b) { h = 1/6 * (4 + ((r - g) / diff)) }; | |
} | |
h = Math.round(h * 360) | |
return [h, s, v]; | |
} | |
function rgbFromHSV(h, s, v) { | |
/** | |
* I: Three elements hue (h) ∈ [0, 360], and saturation (s) and value (v) which are both ∈ [0, 1] | |
* O: An array of red (r), green (g), blue (b), all ∈ [0, 255] | |
*/ | |
hprime = h / 60; | |
const c = v * s; | |
const x = c * (1 - Math.abs(hprime % 2 - 1)); | |
const m = v - c; | |
let rPrime, gPrime, bPrime; | |
if (!hprime) {rPrime = 0; gPrime = 0; bPrime = 0; } | |
if (hprime >= 0 && hprime < 1) { rPrime = c; gPrime = x; bPrime = 0} | |
if (hprime >= 1 && hprime < 2) { rPrime = x; gPrime = c; bPrime = 0} | |
if (hprime >= 2 && hprime < 3) { rPrime = 0; gPrime = c; bPrime = x} | |
if (hprime >= 3 && hprime < 4) { rPrime = 0; gPrime = x; bPrime = c} | |
if (hprime >= 4 && hprime < 5) { rPrime = x; gPrime = 0; bPrime = c} | |
if (hprime >= 5 && hprime < 6) { rPrime = c; gPrime = 0; bPrime = x} | |
const r = Math.round( (rPrime + m)* 255); | |
const g = Math.round( (gPrime + m)* 255); | |
const b = Math.round( (bPrime + m)* 255); | |
return [r, g, b] | |
} | |
function rgbFromHSL(h, s, l) { | |
/** | |
* I: Three elements hue (h) ∈ [0, 360], and saturation (s) and lightness (l) which are both ∈ [0, 1] | |
* O: An array of red (r), green (g), blue (b), all ∈ [0, 255] | |
*/ | |
const hprime = h / 60; | |
const c = (1 - Math.abs(2 * l - 1)) * s; | |
const x = c * (1 - Math.abs((hprime % 2) - 1)); | |
const m = l - (c / 2); | |
let rPrime, gPrime, bPrime; | |
if (h >= 0 && h < 60) { rPrime = c; gPrime = x; bPrime = 0} | |
if (h >= 60 && h < 120) { rPrime = x; gPrime = c; bPrime = 0} | |
if (h >= 120 && h < 180) { rPrime = 0; gPrime = c; bPrime = x} | |
if (h >= 180 && h < 240) { rPrime = 0; gPrime = x; bPrime = c} | |
if (h >= 240 && h < 300) { rPrime = x; gPrime = 0; bPrime = c} | |
if (h >= 300 && h < 360) { rPrime = c; gPrime = 0; bPrime = x} | |
const r = Math.round( (rPrime + m)* 255); | |
const g = Math.round( (gPrime + m)* 255); | |
const b = Math.round( (bPrime + m)* 255); | |
return [r, g, b] | |
} | |
function hslFromRGB(r, g, b) { | |
/** | |
* I: Three arguments, red (r), green (g), blue (b), all ∈ [0, 255] | |
* O: An array of three elements hue (h) ∈ [0, 360], and saturation (s) and lightness (l) which are both ∈ [0, 1] | |
*/ | |
r /= 255, g /= 255, b /= 255; | |
const max = Math.max(r, g, b); | |
const min = Math.min(r, g, b); | |
const diff = max - min; | |
let h, s; | |
//Lightness | |
const l = (max + min) / 2; | |
//Saturation | |
s = (diff === 0) ? 0 : diff / (1 - Math.abs((2 * l) - 1));; | |
//Hue | |
if (diff === 0) { | |
h = 0; | |
} else { | |
// 1/6 is equivalent to 60 degrees | |
if (max === r) { h = 1/6 * (0 + ((g - b) / diff)) }; | |
if (max === g) { h = 1/6 * (2 + ((b - r) / diff)) }; | |
if (max === b) { h = 1/6 * (4 + ((r - g) / diff)) }; | |
} | |
h = Math.round(h * 360) | |
return [h, s, l]; | |
} | |
function baseTenToHex(c) { | |
/** | |
* I: A number | |
* O: A string representation of the number in base 16 | |
*/ | |
let hex = c.toString(16); | |
return hex.length == 1 ? "0" + hex : hex; | |
} | |
function hexFromRGB(r, g, b) { | |
/** | |
* I: Three arguments, red (r), green (g), blue (b), all ∈ [0, 255] | |
* O: A hexidecimal representation of the three numbers, concatenated as one string. | |
*/ | |
return "#" + baseTenToHex(r) + baseTenToHex(g) + baseTenToHex(b); | |
} | |
function baseHexToTen(c) { | |
/** | |
* I: A string of a number in base 16 | |
* O: A number representation of the string in base 10 | |
*/ | |
return parseInt(c, 16) | |
} | |
function rgbFromHex(hexValue) { | |
/** | |
* I: A single hexidecimal value (without a leading `#`); | |
* O: An array of red (r), green (g), blue (b), all ∈ [0, 255] | |
*/ | |
debugger; | |
const r = baseHexToTen(hexValue.slice(0, 2)) | |
const g = baseHexToTen(hexValue.slice(2, 4)) | |
const b = baseHexToTen(hexValue.slice(4, 6)) | |
return [r, g, b] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment