@spellix/magic-color-transformer
Version:
Magic color transform library
66 lines (49 loc) • 2.01 kB
text/typescript
/* eslint-disable -- allow for magic-color */
import type { HexColor, HsbColor, HslColor, LabColor, RgbColor } from '../types';
import { rgbToHex, rgbToHsb, rgbToHsl } from './rgb';
const labRegex =
/^lab\(\s*(100|[1-9]?\d(?:\.\d+)?)\s+(-?(?:1[01]\d|12[0-8]|\d?\d)(?:\.\d+)?)\s+(-?(?:1[01]\d|12[0-8]|\d?\d)(?:\.\d+)?)(?:\s*\/\s*(0|0?\.\d+|1(?:\.0)?))?\s*\)$/;
export function isLab(color: string): boolean {
return labRegex.test(color);
}
export function parseLab(color: string): { values: LabColor; alpha: number } {
const match = labRegex.exec(color);
if (!match) throw new Error('Invalid Lab color format.');
// @ts-expect-error - allow for magic-color
const lab = [Number.parseFloat(match[1]), Number.parseFloat(match[2]), Number.parseFloat(match[3])] as LabColor;
const alpha = match[4] ? Number.parseFloat(match[4]) : 1;
return { values: lab, alpha };
}
function xyz_rgb(r: number) {
r = 255 * (r <= 0.003_04 ? 12.92 * r : 1.055 * r ** (1 / 2.4) - 0.055);
return Math.min(Math.max(0, r), 255);
// return 255 * (r <= 0.00304 ? 12.92 * r : 1.055 * r ** (1 / 2.4) - 0.055)
}
function lab_xyz(t: number) {
return t > 0.206_896_552 ? t * t * t : 0.128_418_55 * (t - 0.137_931_034);
}
export function labToRgb(color: LabColor): RgbColor {
const [l, a, b] = color;
let x;
let y;
let z;
y = (l + 16) / 116;
x = y + a / 500;
z = y - b / 200;
y = Number(lab_xyz(y));
x = 0.950_47 * lab_xyz(x);
z = 1.088_83 * lab_xyz(z);
const r = xyz_rgb(3.240_454_2 * x - 1.537_138_5 * y - 0.498_531_4 * z); // D65 -> sRGB
const g = xyz_rgb(-0.969_266 * x + 1.876_010_8 * y + 0.041_556 * z);
const b_ = xyz_rgb(0.055_643_4 * x - 0.204_025_9 * y + 1.057_225_2 * z);
return [r, g, b_];
}
export function labToHex(color: LabColor): HexColor {
return rgbToHex(labToRgb(color));
}
export function labToHsl(color: LabColor): HslColor {
return rgbToHsl(labToRgb(color));
}
export function labToHsb(color: LabColor): HsbColor {
return rgbToHsb(labToRgb(color));
}