Skip to content

Instantly share code, notes, and snippets.

@mplungjan
Created April 18, 2024 09:35
Show Gist options
  • Save mplungjan/dab9a56ee673615a540801c5a4ba99f0 to your computer and use it in GitHub Desktop.
Save mplungjan/dab9a56ee673615a540801c5a4ba99f0 to your computer and use it in GitHub Desktop.
CIELAB get nearest colour
<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