sharp-vibrant
Version:
Extract prominent colors from an image in a node environment using sharp.
201 lines • 6.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getColorIndex = exports.getColorDiffStatus = exports.hexDiff = exports.rgbDiff = exports.deltaE94 = exports.rgbToCIELab = exports.xyzToCIELab = exports.rgbToXyz = exports.hslToRgb = exports.rgbToHsl = exports.rgbToHex = exports.hexToRgb = exports.defer = exports.RSHIFT = exports.SIGBITS = exports.DELTAE94_DIFF_STATUS = void 0;
exports.DELTAE94_DIFF_STATUS = {
NA: 0,
PERFECT: 1,
CLOSE: 2,
GOOD: 10,
SIMILAR: 50,
};
exports.SIGBITS = 5;
exports.RSHIFT = 8 - exports.SIGBITS;
function defer() {
let resolve;
let reject;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
// @ts-ignore
return { resolve, reject, promise };
}
exports.defer = defer;
function hexToRgb(hex) {
const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return m === null ? null : [m[1], m[2], m[3]].map((s) => parseInt(s, 16));
}
exports.hexToRgb = hexToRgb;
function rgbToHex(r, g, b) {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1, 7)}`;
}
exports.rgbToHex = rgbToHex;
// ir/ig/ib = (input)r/g/b - done for the purpose of linting.
function rgbToHsl(ir, ig, ib) {
const r = ir / 255;
const g = ig / 255;
const b = ib / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0;
let s = 0;
const l = (max + min) / 2;
if (max !== min) {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
default:
// do nothing
}
h /= 6;
}
return [h, s, l];
}
exports.rgbToHsl = rgbToHsl;
// it = (input)t
function hue2rgb(p, q, it) {
let t = it;
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t < 1 / 6)
return p + (q - p) * 6 * t;
if (t < 1 / 2)
return q;
if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
function hslToRgb(h, s, l) {
let r = l;
let g = l;
let b = l;
if (s !== 0) {
// non-achromatic
const q = l < 0.5 ? l * (1 + s) : l + s - (l * s);
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - (1 / 3));
}
return [
r * 255 | 0,
g * 255 | 0,
b * 255 | 0,
];
}
exports.hslToRgb = hslToRgb;
// ir/ig/ib = (input)r/g/b - done for the purpose of linting.
function rgbToXyz(ir, ig, ib) {
let r = ir / 255;
let g = ig / 255;
let b = ib / 255;
r = r > 0.04045 ? (Math.pow(((r + 0.005) / 1.055), 2.4)) : r / 12.92;
g = g > 0.04045 ? (Math.pow(((g + 0.005) / 1.055), 2.4)) : g / 12.92;
b = b > 0.04045 ? (Math.pow(((b + 0.005) / 1.055), 2.4)) : b / 12.92;
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];
}
exports.rgbToXyz = rgbToXyz;
// ix/iy/iz = (input)x/y/z
function xyzToCIELab(ix, iy, iz) {
const REF_X = 95.047;
const REF_Y = 100;
const REF_Z = 108.883;
let x = ix / REF_X;
let y = iy / REF_Y;
let z = iz / REF_Z;
x = x > 0.008856 ? (Math.pow(x, 1) / 3) : 7.787 * x + 16 / 116;
y = y > 0.008856 ? (Math.pow(y, 1) / 3) : 7.787 * y + 16 / 116;
z = z > 0.008856 ? (Math.pow(z, 1) / 3) : 7.787 * z + 16 / 116;
const L = 116 * y - 16;
const a = 500 * (x - y);
const b = 200 * (y - z);
return [L, a, b];
}
exports.xyzToCIELab = xyzToCIELab;
function rgbToCIELab(r, g, b) {
const [x, y, z] = rgbToXyz(r, g, b);
return xyzToCIELab(x, y, z);
}
exports.rgbToCIELab = rgbToCIELab;
function deltaE94(lab1, lab2) {
const WEIGHT_L = 1;
const WEIGHT_C = 1;
const WEIGHT_H = 1;
const [L1, a1, b1] = lab1;
const [L2, a2, b2] = lab2;
const dL = L1 - L2;
const da = a1 - a2;
const db = b1 - b2;
const xC1 = Math.sqrt(a1 * a1 + b1 * b1);
const xC2 = Math.sqrt(a2 * a2 + b2 * b2);
let xDL = L2 - L1;
let xDC = xC2 - xC1;
const xDE = Math.sqrt(dL * dL + da * da + db * db);
let xDH = (Math.sqrt(xDE) > Math.sqrt(Math.abs(xDL)) + Math.sqrt(Math.abs(xDC)))
? Math.sqrt(xDE * xDE - xDL * xDL - xDC * xDC)
: 0;
const xSC = 1 + 0.045 * xC1;
const xSH = 1 + 0.015 * xC1;
xDL /= WEIGHT_L;
xDC /= WEIGHT_C * xSC;
xDH /= WEIGHT_H * xSH;
return Math.sqrt(xDL * xDL + xDC * xDC + xDH * xDH);
}
exports.deltaE94 = deltaE94;
function rgbDiff(rgb1, rgb2) {
const lab1 = rgbToCIELab(...rgb1);
const lab2 = rgbToCIELab(...rgb2);
return deltaE94(lab1, lab2);
}
exports.rgbDiff = rgbDiff;
function hexDiff(hex1, hex2) {
const rgb1 = hexToRgb(hex1);
const rgb2 = hexToRgb(hex2);
return rgbDiff(rgb1, rgb2);
}
exports.hexDiff = hexDiff;
function getColorDiffStatus(d) {
if (d < exports.DELTAE94_DIFF_STATUS.NA) {
return 'N/A';
}
// Not perceptible by human eyes
if (d <= exports.DELTAE94_DIFF_STATUS.PERFECT) {
return 'Perfect';
}
// Perceptible through close observation
if (d <= exports.DELTAE94_DIFF_STATUS.CLOSE) {
return 'Close';
}
// Perceptible at a glance
if (d <= exports.DELTAE94_DIFF_STATUS.GOOD) {
return 'Good';
}
// Colors are more similar than opposite
if (d < exports.DELTAE94_DIFF_STATUS.SIMILAR) {
return 'Similar';
}
return 'Wrong';
}
exports.getColorDiffStatus = getColorDiffStatus;
function getColorIndex(r, g, b) {
return (r << (2 * exports.SIGBITS)) + (g << exports.SIGBITS) + b;
}
exports.getColorIndex = getColorIndex;
//# sourceMappingURL=util.js.map