-
-
Save Daniel-Walsh/57c8713b99e505484f0fda270c6e89fc to your computer and use it in GitHub Desktop.
RGB color hex to lightness
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
// based on https://stackoverflow.com/a/56678483/65387 | |
type RGB = [r: number, g: number, b: number] | |
const UNK = 255 / 2 | |
/** | |
* @param hex RGB hex string like "#CCCFDB" | |
* @returns RGB tuple in [0-255] | |
*/ | |
function hexToRgb(hex: string): RGB { | |
const h = String(hex).replace(/^#/, '') | |
if(h.length === 3) { | |
return [ | |
parseRadix(h[0] + h[0], 16, UNK), | |
parseRadix(h[1] + h[1], 16, UNK), | |
parseRadix(h[2] + h[2], 16, UNK), | |
] | |
} | |
if(h.length === 6) { | |
return [ | |
parseRadix(h.slice(0, 2), 16, UNK), | |
parseRadix(h.slice(2, 4), 16, UNK), | |
parseRadix(h.slice(4, 6), 16, UNK), | |
] | |
} | |
return [UNK, UNK, UNK] | |
} | |
function sRGBtoLin(colorChannel: number) { | |
// Send this function a decimal sRGB gamma encoded color value | |
// between 0.0 and 1.0, and it returns a linearized value. | |
if(colorChannel <= 0.04045) { | |
return colorChannel / 12.92 | |
} | |
return Math.pow((colorChannel + 0.055) / 1.055, 2.4) | |
} | |
/** | |
* @param r Red, [0-1] | |
* @param g Green, [0-1] | |
* @param b Blue, [0-1] | |
* @returns Luminance, [0-1] | |
*/ | |
function rgbToY(r: number, g: number, b: number) { | |
return 0.2126 * sRGBtoLin(r) + 0.7152 * sRGBtoLin(g) + 0.0722 * sRGBtoLin(b) | |
} | |
/** | |
* Luminance to perceived lightness. | |
* | |
* @param Y Luminance, [0-1] | |
*/ | |
function YtoLstar(Y: number) { | |
// Send this function a luminance value between 0.0 and 1.0, | |
// and it returns L* which is "perceptual lightness" | |
if(Y <= (216 / 24389)) { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036 | |
return Y * (24389 / 27) // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296 | |
} | |
return Math.pow(Y, (1 / 3)) * 116 - 16 | |
} | |
/** | |
* Calculate perceived lightness from RGB hex string. | |
* | |
* @param rgb RGB hex string like "#CCCFDB" | |
* @returns Lightness value, [0-100]. | |
*/ | |
export function rgbHexToLightness(rgb: string) { | |
const [r, g, b] = hexToRgb(rgb) | |
return YtoLstar(rgbToY(r / 255, g / 255, b / 255)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment