UNPKG

@spellix/magic-color-transformer

Version:

Magic color transform library

141 lines (112 loc) 3.82 kB
/* eslint-disable -- allow for magic-color */ import type { HexColor, HsbColor, HslColor, LabColor, RgbColor } from '../types'; const rgbRegex = /^rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(0|0?\.\d+|1(?:\.0)?))?\)$/; const newRgbRegex = /^rgb\((\d+)\s+(\d+)\s+(\d+)(?:\s*\/\s*(0|0?\.\d+|1(?:\.0)?))?\s*\)$/; export function isRgb(color: string): boolean { return rgbRegex.test(color) || newRgbRegex.test(color); } export function parseRgb(color: string) { const match = rgbRegex.exec(color) || newRgbRegex.exec(color); if (!match) throw new Error('Invalid RGB or RGBA color format.'); const rgb = [match[1], match[2], match[3]].map(Number) as RgbColor; const alpha = match[4] ? Number.parseFloat(match[4]) : 1; return { values: rgb, alpha }; } export function rgbToHex(color: RgbColor): HexColor { const [r, g, b] = color.map(Math.round); // @ts-expect-error - allow for magic-color return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; } export function rgbToHsl(color: RgbColor): HslColor { const [r, g, b] = color.map((i) => i / 255); // @ts-expect-error - allow for magic-color const max = Math.max(r, g, b); // @ts-expect-error - allow for magic-color const min = Math.min(r, g, b); let h = 0; let s = 0; const l = (max + min) / 2; if (max !== min) { const delta = max - min; s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min); switch (max) { case r: { // @ts-expect-error - allow for magic-color h = (g - b) / delta + (g < b ? 6 : 0); break; } case g: { // @ts-expect-error - allow for magic-color h = (b - r) / delta + 2; break; } case b: { // @ts-expect-error - allow for magic-color h = (r - g) / delta + 4; break; } } h *= 60; } return [h, s * 100, l * 100]; } export function rgbToHsb(color: RgbColor): HsbColor { const [r, g, b] = color.map((i) => i / 255); // @ts-expect-error - allow for magic-color const max = Math.max(r, g, b); // @ts-expect-error - allow for magic-color const min = Math.min(r, g, b); let h = 0; const v = max; const d = max - min; const s = max === 0 ? 0 : d / max; if (max === min) { h = 0; // achromatic } else { switch (max) { case r: { // @ts-expect-error - allow for magic-color h = (g - b) / d + (g < b ? 6 : 0); break; } case g: { // @ts-expect-error - allow for magic-color h = (b - r) / d + 2; break; } case b: { // @ts-expect-error - allow for magic-color h = (r - g) / d + 4; break; } } h /= 6; } return [h * 360, s * 100, v * 100]; } export function rgbToLab(color: RgbColor): LabColor { function rgb_xyz(rgb: number) { const r = rgb / 255; if (r <= 0.040_45) return r / 12.92; return ((r + 0.055) / 1.055) ** 2.4; } function xyz_lab(t: number) { if (t > 0.008_856_452) return t ** (1 / 3); return t / 0.128_418_55 + 0.137_931_034; } function rgb2xyz(color: RgbColor) { const [r, g, b] = color.map(rgb_xyz); // @ts-expect-error - allow for magic-color const x = xyz_lab((0.412_456_4 * r + 0.357_576_1 * g + 0.180_437_5 * b) / 0.950_47); // @ts-expect-error - allow for magic-color const y = xyz_lab((0.212_672_9 * r + 0.715_152_2 * g + 0.072_175 * b) / 1); // @ts-expect-error - allow for magic-color const z = xyz_lab((0.019_333_9 * r + 0.119_192 * g + 0.950_304_1 * b) / 1.088_83); return [x, y, z]; } const [x, y, z] = rgb2xyz(color); // @ts-expect-error - allow for magic-color const l = 116 * y - 16; // @ts-expect-error - allow for magic-color return [l < 0 ? 0 : l, 500 * (x - y), 200 * (y - z)] as LabColor; }