UNPKG

colorally

Version:

Name colors by well-known definitions

73 lines (58 loc) 2.79 kB
import colors from '../data/colors.json'; import { getDeltaE00 } from 'delta-e'; // ╻ ╻╺┳╸╻╻ ╻╺┳╸╻ ╻ // ┃ ┃ ┃ ┃┃ ┃ ┃ ┗┳┛ // ┗━┛ ╹ ╹┗━╸╹ ╹ ╹ const duplicate = x => x + x; const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); const isString = x => typeof x === 'string'; const take = n => arr => arr.slice(0, n); const zipObj = ks => vs => ks.reduce((acc, k, idx) => ({ ...acc, [k]: vs[idx] }), {}); // ┏━╸┏━┓┏┓╻╻ ╻┏━╸┏━┓╺┳╸┏━╸┏━┓┏━┓ const omitTypeIndicators = str => str.replace(/^#|0x/, ''); const expandShortHex = str => str.length === 3 ? Array.from(str).map(duplicate).join('') : str; const convertStringToHex = str => parseInt(str, 16); const rgbToXyz = rgb => { const [r, g, b] = rgb.map(x => { const y = x / 255; return y > 0.04045 ? Math.pow((y + 0.055) / 1.055, 2.4) : y / 12.92; }); return [(r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047, (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0, (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883].map(x => x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116); }; const xyzToLab = ([x, y, z]) => [116 * y - 16, 500 * (x - y), 200 * (y - z)]; const hexToRgb = hex => { const r = hex >> 16; const g = hex >> 8 & 0xff; const b = hex & 0xff; return [r, g, b]; }; const strToHex = compose(convertStringToHex, expandShortHex, take(6), omitTypeIndicators); const rgbToLab = compose(xyzToLab, rgbToXyz); // ┏━┓╻ ╻╻ ┏━╸┏━┓ const measureDistance = (...rgbs) => getDeltaE00(...rgbs.map(compose(zipObj(['L', 'A', 'B']), rgbToLab))); const findSimilarDefinition = definitions => rgb => { const getNearestDefinition = nearest => current => nearest == null || nearest.distance > current.distance ? current : nearest; const traverseDefinitions = (nearest, idx = 0) => { if (idx === definitions.length) return nearest; const def = definitions[idx]; const current = { ...def, distance: measureDistance(rgb, def.rgb) }; return current.distance === 0 ? current : traverseDefinitions(getNearestDefinition(nearest)(current), idx + 1); }; return traverseDefinitions(); }; // ┏━╸┏━┓╻ ┏━┓┏━┓┏━┓╻ ╻ ╻ ╻ /** * Find visually similar color definition. * * @param {(string|number|number[])} color A color value in hex-string, hex or RGB array. * @returns {object} A color definition object with name, rgb array and optional match statistics. */ function colorally(color) { const rgb = Array.isArray(color) ? color.map(Number) : hexToRgb(isString(color) ? strToHex(color) : color); return findSimilarDefinition(colors)(rgb); } export { colorally as default };