UNPKG

color-classifier

Version:

Classify the color along the reference color. using algorithm the CIEDE2000, RGB, HSV.

142 lines (109 loc) 3.34 kB
const HEX_SHORT = /^#([a-fA-F0-9]{3})$/; const HEX = /^#([a-fA-F0-9]{6})$/; function roundColors(obj, round) { if (!round) return obj; const o = {}; for (let k in obj) { o[k] = Math.round(obj[k]); } return o; } function hasProp(obj, key) { return obj.hasOwnProperty(key); } function isRgb(obj) { return hasProp(obj, "r") && hasProp(obj, "g") && hasProp(obj, "b"); } export default class Color { static normalizeHex(hex) { if (HEX.test(hex)) { return hex; } else if (HEX_SHORT.test(hex)) { const r = hex.slice(1, 2); const g = hex.slice(2, 3); const b = hex.slice(3, 4); return `#${r + r}${g + g}${b + b}`; } return null; } static hexToRgb(hex) { const normalizedHex = this.normalizeHex(hex); if (normalizedHex == null) { return null; } const m = normalizedHex.match(HEX); const i = parseInt(m[1], 16); const r = (i >> 16) & 0xFF; const g = (i >> 8) & 0xFF; const b = i & 0xFF; return { r, g, b }; } static rgbToHex(rgb) { const { r, g, b} = rgb; const i = ((Math.round(r) & 0xFF) << 16) + ((Math.round(g) & 0xFF) << 8) + (Math.round(b) & 0xFF); const s = i.toString(16).toLowerCase(); return `#${"000000".substring(s.length) + s}`; } static rgbToHsv(rgb, round = true) { const { r, g, b } = rgb; const min = Math.min(r, g, b); const max = Math.max(r, g, b); const delta = max - min; const hsv = {}; if (max === 0) { hsv.s = 0; } else { hsv.s = (delta / max * 1000) / 10; } if (max === min) { hsv.h = 0; } else if (r === max) { hsv.h = (g - b) / delta; } else if (g === max) { hsv.h = 2 + (b - r) / delta; } else { hsv.h = 4 + (r - g) / delta; } hsv.h = Math.min(hsv.h * 60, 360); hsv.h = hsv.h < 0 ? hsv.h + 360 : hsv.h; hsv.v = ((max / 255) * 1000) / 10; return roundColors(hsv, round); } static rgbToXyz(rgb, round = true) { const r = rgb.r / 255; const g = rgb.g / 255; const b = rgb.b / 255; const rr = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : r / 12.92; const gg = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : g / 12.92; const bb = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : b / 12.92; const x = (rr * 0.4124 + gg * 0.3576 + bb * 0.1805) * 100; const y = (rr * 0.2126 + gg * 0.7152 + bb * 0.0722) * 100; const z = (rr * 0.0193 + gg * 0.1192 + bb * 0.9505) * 100; return roundColors({ x, y, z }, round); } static rgbToLab(rgb, round = true) { const xyz = Color.rgbToXyz(rgb, false); let { x, y, z } = xyz; x /= 95.047; y /= 100; z /= 108.883; 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 roundColors({ l, a, b }, round); } constructor(value) { this.original = value; if (isRgb(value)) { this.rgb = value; this.hex = Color.rgbToHex(value); } else { this.hex = Color.normalizeHex(value); this.rgb = Color.hexToRgb(this.hex); } this.hsv = Color.rgbToHsv(this.rgb); } }