Skip to content

Instantly share code, notes, and snippets.

@mplungjan
Created April 18, 2024 09:35
Show Gist options
  • Select an option

  • Save mplungjan/dab9a56ee673615a540801c5a4ba99f0 to your computer and use it in GitHub Desktop.

Select an option

Save mplungjan/dab9a56ee673615a540801c5a4ba99f0 to your computer and use it in GitHub Desktop.

Revisions

  1. mplungjan created this gist Apr 18, 2024.
    98 changes: 98 additions & 0 deletions demo.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    <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>