color-delta-e
Version:
   • 9 kB
JavaScript
import { isArray, isString } from 'yewtils';
var __pow = Math.pow;
function convertHexToTuple(h) {
let r = 0;
let g = 0;
let b = 0;
if (h.length === 4) {
r = `0x${h[1]}${h[1]}`;
g = `0x${h[2]}${h[2]}`;
b = `0x${h[3]}${h[3]}`;
} else if (h.length === 7) {
r = `0x${h[1]}${h[2]}`;
g = `0x${h[3]}${h[4]}`;
b = `0x${h[5]}${h[6]}`;
}
return [parseInt(r), parseInt(g), parseInt(b)];
}
function convertRGBToLAB(rgb) {
let r = rgb[0] / 255;
let g = rgb[1] / 255;
let b = rgb[2] / 255;
let x;
let y;
let z;
r = r > 0.04045 ? __pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
g = g > 0.04045 ? __pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
b = b > 0.04045 ? __pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1;
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
x = x > 8856e-6 ? __pow(x, 1 / 3) : 7.787 * x + 16 / 116;
y = y > 8856e-6 ? __pow(y, 1 / 3) : 7.787 * y + 16 / 116;
z = z > 8856e-6 ? __pow(z, 1 / 3) : 7.787 * z + 16 / 116;
return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
}
function toRBGString([r, g, b]) {
return `rgb(${r},${g},${b})`;
}
function toHSLString([h, s, l]) {
return `hsl(${h},${s},${l})`;
}
const convertStringToTuple = (color) => {
const r = color.match(/\d+/g);
if (!r)
return [0, 0, 0];
return r;
};
const convertHSLtoTuple = (color) => {
let [h, s, l] = convertStringToTuple(color);
s /= 100;
l /= 100;
if (color.includes("rad"))
h = Math.round(h * (180 / Math.PI));
else if (color.includes("turn"))
h = Math.round(h * 360);
if (h >= 360)
h %= 360;
const c = (1 - Math.abs(2 * l - 1)) * s;
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
const m = l - c / 2;
let r = 0;
let g = 0;
let b = 0;
if (h >= 0 && h < 60) {
r = c;
g = x;
b = 0;
} else if (h >= 60 && h < 120) {
r = x;
g = c;
b = 0;
} else if (h >= 120 && h < 180) {
r = 0;
g = c;
b = x;
} else if (h >= 180 && h < 240) {
r = 0;
g = x;
b = c;
} else if (h >= 240 && h < 300) {
r = x;
g = 0;
b = c;
} else if (h >= 300 && h < 360) {
r = c;
g = 0;
b = x;
}
r = Math.round((r + m) * 255);
g = Math.round((g + m) * 255);
b = Math.round((b + m) * 255);
return [r, g, b];
};
const stringConverstionMap = {
rgb: convertStringToTuple,
hex: convertHexToTuple,
hsl: convertHSLtoTuple,
lab: convertStringToTuple
};
const tupleConverstionMap = {
rgb: (color) => convertRGBToLAB(color),
hsl: (color) => convertRGBToLAB(stringConverstionMap.hsl(toHSLString(color))),
lab: (color) => color
};
function getType(color) {
if (color.slice(0, 3).includes("rgb"))
return "rgb";
if (color.slice(0, 3).includes("hsl"))
return "hsl";
if (color.slice(0, 3).includes("#"))
return "hex";
if (color.slice(0, 3).includes("lab"))
return "lab";
return "rgb";
}
function getStringColorConvertion(color) {
const type = getType(color);
const rgbTuple = stringConverstionMap[type](color);
return getTupleColorConvertion(rgbTuple, "rgb");
}
function getTupleColorConvertion(color, type) {
const res = tupleConverstionMap[type](color);
return res;
}
function isColorTuple(possibleColorTuple) {
return isArray(possibleColorTuple) && possibleColorTuple.length === 3;
}
const deltaCache = /* @__PURE__ */ new Map();
function clearCache() {
deltaCache.clear();
}
function deltaE(color1, color2, type, nocache) {
if (isString(color1))
color1 = getStringColorConvertion(color1);
else if (isColorTuple(color1))
color1 = getTupleColorConvertion(color1, type || "rgb");
else
throw new Error(`${color1} type could not be infered if is string, otherwise type has not been provided as an option if passing a tuple`);
if (isString(color2))
color2 = getStringColorConvertion(color2);
else if (isColorTuple(color2))
color2 = getTupleColorConvertion(color2, type || "rgb");
else
throw new Error(`${color2} type could not be infered if is string, otherwise type has not been provided as an option `);
if (!nocache) {
const value = deltaCache.get(JSON.stringify([color1, color2]));
if (value)
return value;
}
if (!isColorTuple(color1) || !isColorTuple(color2))
throw new Error(`colors: ${color1} and ${color2} could type could not be infered or converted`);
const labA = color1;
const labB = color2;
const deltaL = labA[0] - labB[0];
const deltaA = labA[1] - labB[1];
const deltaB = labA[2] - labB[2];
const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
const deltaC = c1 - c2;
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
const sc = 1 + 0.045 * c1;
const sh = 1 + 0.015 * c1;
const deltaLKlsl = deltaL / 1;
const deltaCkcsc = deltaC / sc;
const deltaHkhsh = deltaH / sh;
const i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
const result = i < 0 ? 0 : Math.sqrt(i);
if (!nocache)
deltaCache.set(JSON.stringify([color1, color2]), result);
return result;
}
function isPerceivable(first, second, options) {
const threshold = (options == null ? void 0 : options.threshold) || 5;
const type = (options == null ? void 0 : options.type) || "rgb";
return Math.round(deltaE(first, second, type, options == null ? void 0 : options.nocache)) > threshold;
}
const colorReturnMapsString = {
rgb: ["rgb(0, 0, 0)", "rgb(255, 255, 255)"],
hsl: ["hsl(0, 0%, 0%)", "hsl(0, 100%, 100%)"],
hex: ["#000", "#fff"],
lab: ["#000", "#fff"]
};
const colorReturnMapsTuples = {
rgb: [[0, 0, 0], [255, 255, 255]],
hsl: [[0, 0, 0], [0, 100, 100]],
lab: [[0, 0, 0], [0, 0, 0]]
};
const maps = {
string: colorReturnMapsString,
array: colorReturnMapsTuples
};
function contrastText(color, type) {
if (type === void 0 && isColorTuple(color))
throw new Error("No color space type passed contrastText when tuple is passed");
type = isColorTuple(color) ? type : getType(color);
if (!type)
throw new Error("Could not infer color space type inside contrastText");
const m = maps[isString(color) ? "string" : "array"];
return m[type][+isPerceivable(color, colorReturnMapsString[type][1], { type, threshold: 50 })];
}
function sampleImage(imgEl) {
var _a;
if (!((_a = window == null ? void 0 : window.document) == null ? void 0 : _a.createElement)) {
console.error("[color-delta-e]: sampleImage can only run in browser as it needs access to HTMLCanvas API, please check your runtime environment");
return [0, 0, 0];
}
const blockSize = 5;
const defaultRGB = { r: 0, g: 0, b: 0 };
const canvas = document.createElement("canvas");
const context = canvas.getContext && canvas.getContext("2d");
let data;
let i = -4;
const rgb = { r: 0, g: 0, b: 0 };
let count = 0;
if (!context)
return [defaultRGB.r, defaultRGB.g, defaultRGB.b];
const height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
const width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch (e) {
console.error(e);
return [defaultRGB.r, defaultRGB.g, defaultRGB.b];
}
const length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return [rgb.r, rgb.g, rgb.b];
}
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
const defaultOptions = {
type: "rgb",
threshold: 5
};
function selector(options, ...fallbacks) {
let { compare, threshold, type } = __spreadValues(__spreadValues({}, defaultOptions), options);
function filter(...filters) {
if (filters.length > 1) {
if (!isPerceivable(compare, filters[0], { threshold, type }))
return selector(options, ...filters.slice(1));
else
return filters[0];
} else {
return filters[0];
}
}
return filter(...fallbacks);
}
export { clearCache, contrastText, deltaE, isPerceivable, sampleImage, selector, toHSLString, toRBGString };