Created
April 18, 2024 09:35
-
-
Save mplungjan/dab9a56ee673615a540801c5a4ba99f0 to your computer and use it in GitHub Desktop.
CIELAB get nearest colour
This file contains hidden or 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
<title>Color Distance in CIELAB</title> | |
<div style="background:#520975; width:100px; height:100px; display:block; float:left; margin:0;">#520975<br>array color</div> | |
<div style="background:#5D0C8B; width:100px; height:100px; display:block; float:left; margin:0;">#5D0C8B<br>array color</div> | |
<div style="clear:both;background:#854B97; width:100px; height:100px; display:block; float:left; margin:0;">#854B97<br>find near for this color</div> | |
<div id="near" style="width:100px; height:100px; display:block; float:left; margin:0;"></div> | |
<script> | |
const colors = [ | |
"#B2CFAD", "#F4C6CE", "#7CADD3", "#A4C7E2", "#1BCFC9", "#F7EA5F", "#ffffff", "#520975", "#004987", "#F5E500", | |
"#FF8300", "#D8262E", "#999899", "#016836", "#005CB8", "#008995", "#D08900", "#EF8F7A", "#F0B2C9", "#EA534D", | |
"#823550", "#98C11E", "#009ADD", "#FF8188", "#AA7BC9", "#E7E6E5", "#4D9C2D", "#C5093B", "#D7006D", "#970047", | |
"#10576C", "#00CAC3", "#F1F0E2", "#8FC6E8", "#004876", "#FF637D", "#2E5BBE", "#B0A198", "#FFBE9E", "#7B2F3E", | |
"#EB6BAF", "#F2F0A1", "#B9AAD4", "#86ad3f", "#AFC9B8", "#D1CCBD", "#D25D12", "#ECCCCE", "#F3CD00", "#006547", | |
"#789D90", "#80A7BC", "#B8C7D3", "#AF90A7", "#777779", "#5D0C8B", "#01426A", "#F6CE3C", "#00AFA9", "#E11282", | |
"#F3D09E", "#00A6CE", "#F8B5CC", "#32393C", "#FFDB00", "#EB0028", "#F0B2C9", "#FF6B0B", "#C4D5EC" | |
]; | |
</script> | |
<script> | |
/** | |
* Converts a hexadecimal color value to an RGB array. | |
* @param {string} hex - The hexadecimal color string (e.g., "#FFFFFF"). | |
* @returns {number[]} An array containing the RGB values [red, green, blue]. | |
*/ | |
const hexToRgb = hex => { | |
const r = parseInt(hex.slice(1, 3), 16); | |
const g = parseInt(hex.slice(3, 5), 16); | |
const b = parseInt(hex.slice(5, 7), 16); | |
return [r, g, b]; | |
}; | |
/** | |
* Converts an RGB color array into an XYZ color array using the sRGB color space. | |
* @param {number[]} rgb - An array of RGB values [red, green, blue]. | |
* @returns {number[]} An array containing the XYZ values. | |
*/ | |
const rgbToXyz = rgb => { | |
let [r, g, b] = rgb.map(v => { | |
v /= 255; | |
return v > 0.04045 ? Math.pow((v + 0.055) / 1.055, 2.4) : v / 12.92; | |
}); | |
[r, g, b] = [r * 100, g * 100, b * 100]; | |
const x = r * 0.4124 + g * 0.3576 + b * 0.1805; | |
const y = r * 0.2126 + g * 0.7152 + b * 0.0722; | |
const z = r * 0.0193 + g * 0.1192 + b * 0.9505; | |
return [x, y, z]; | |
}; | |
/** | |
* Converts an XYZ color array to a CIELAB color array which more closely aligns with human color perception. | |
* @param {number[]} xyz - An array of XYZ values. | |
* @returns {number[]} An array containing the CIELAB values [L*, a*, b*]. | |
*/ | |
const xyzToLab = xyz => { | |
let [x, y, z] = xyz; | |
[x, y, z] = [x / 95.047, y / 100.000, z / 108.883]; | |
[x, y, z] = [x, y, z].map(v => v > 0.008856 ? Math.pow(v, 1 / 3) : (7.787 * v) + (16 / 116)); | |
const l = (116 * y) - 16; | |
const a = 500 * (x - y); | |
const b = 200 * (y - z); | |
return [l, a, b]; | |
}; | |
/** | |
* Calculates the Delta E (Euclidean distance in the LAB color space) color difference between two CIELAB colors. | |
* @param {number[]} labA - The first CIELAB color array. | |
* @param {number[]} labB - The second CIELAB color array. | |
* @returns {number} The Delta E color difference. | |
*/ | |
const deltaE = (labA, labB) => { | |
return Math.sqrt( | |
Math.pow(labA[0] - labB[0], 2) + | |
Math.pow(labA[1] - labB[1], 2) + | |
Math.pow(labA[2] - labB[2], 2) | |
); | |
}; | |
/** | |
* Finds the nearest color from a predefined set to the given hexadecimal color. | |
* @param {string} colorHex - The hexadecimal color code. | |
* @returns {string} The hexadecimal code of the nearest color from the set. | |
*/ | |
const nearestColor = colorHex => { | |
const targetLab = xyzToLab(rgbToXyz(hexToRgb(colorHex))); | |
return colors.reduce((acc, curr) => { | |
const currLab = xyzToLab(rgbToXyz(hexToRgb(curr))); | |
const currDeltaE = deltaE(targetLab, currLab); | |
return currDeltaE < acc.deltaE ? { color: curr, deltaE: currDeltaE } : acc; | |
}, { color: null, deltaE: Infinity }).color; | |
}; | |
/** Test the code **/ | |
var nearest = nearestColor('#854B97'); | |
document.getElementById("near").innerHTML = "result<br>" + nearest; | |
document.getElementById("near").style.backgroundColor = nearest; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment