colorizr
Version:
Manipulate colors like a boss
32 lines (25 loc) • 1.4 kB
text/typescript
import { GAMUT_EPSILON, LMS_TO_LRGB, OKLAB_TO_CLMS, SRGB_TO_P3 } from '~/modules/constants';
import { ColorTuple } from '~/types';
function multiplyMatrix(matrix: number[][], vector: ColorTuple): ColorTuple {
return [
matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2],
matrix[1][0] * vector[0] + matrix[1][1] * vector[1] + matrix[1][2] * vector[2],
matrix[2][0] * vector[0] + matrix[2][1] * vector[1] + matrix[2][2] * vector[2],
];
}
export function isInGamut(color: ColorTuple): boolean {
return color.every(component => component >= 0 - GAMUT_EPSILON && component <= 1 + GAMUT_EPSILON);
}
export function oklabToLinearP3(L: number, a: number, b: number): ColorTuple {
return multiplyMatrix(SRGB_TO_P3, oklabToLinearSRGB(L, a, b));
}
export function oklabToLinearSRGB(L: number, a: number, b: number): ColorTuple {
const l = (OKLAB_TO_CLMS[0][0] * L + OKLAB_TO_CLMS[0][1] * a + OKLAB_TO_CLMS[0][2] * b) ** 3;
const m = (OKLAB_TO_CLMS[1][0] * L + OKLAB_TO_CLMS[1][1] * a + OKLAB_TO_CLMS[1][2] * b) ** 3;
const s = (OKLAB_TO_CLMS[2][0] * L + OKLAB_TO_CLMS[2][1] * a + OKLAB_TO_CLMS[2][2] * b) ** 3;
return [
LMS_TO_LRGB[0][0] * l + LMS_TO_LRGB[0][1] * m + LMS_TO_LRGB[0][2] * s,
LMS_TO_LRGB[1][0] * l + LMS_TO_LRGB[1][1] * m + LMS_TO_LRGB[1][2] * s,
LMS_TO_LRGB[2][0] * l + LMS_TO_LRGB[2][1] * m + LMS_TO_LRGB[2][2] * s,
];
}