colorally
Version:
Name colors by well-known definitions
81 lines (62 loc) • 3.08 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
var colors = require('../data/colors.json');
var deltaE = require('delta-e');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
// ╻ ╻╺┳╸╻╻ ╻╺┳╸╻ ╻
// ┃ ┃ ┃ ┃┃ ┃ ┃ ┗┳┛
// ┗━┛ ╹ ╹┗━╸╹ ╹ ╹
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) => deltaE.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__default["default"])(rgb);
}
exports["default"] = colorally;
;