allc
Version:
A small typescript package for color conversion.
676 lines (615 loc) • 22 kB
text/typescript
import {
toAdobeRGBComponentFromLinearAdobeRGBComponent,
toCIE1931xyYxFromCIE1931XYZ,
toCIE1931xyYyFromCIE1931XYZ,
toCIE1931XYZXFromCIE1931xyY,
toCIE1931XYZXFromCIELAB,
toCIE1931XYZXFromLinearAdobeRGB,
toCIE1931XYZXFromLinearDisplayP3,
toCIE1931XYZXFromLinearSRGB,
toCIE1931XYZXFromLMS,
toCIE1931XYZYFromCIELAB,
toCIE1931XYZYFromLinearAdobeRGB,
toCIE1931XYZYFromLinearDisplayP3,
toCIE1931XYZYFromLinearSRGB,
toCIE1931XYZYFromLMS,
toCIE1931XYZZFromCIE1931xyY,
toCIE1931XYZZFromCIELAB,
toCIE1931XYZZFromLinearAdobeRGB,
toCIE1931XYZZFromLinearDisplayP3,
toCIE1931XYZZFromLinearSRGB,
toCIE1931XYZZFromLMS,
toCIELABAFromCIE1931XYZ,
toCIELABBFromCIE1931XYZ,
toCIELABLFromCIE1931XYZ,
toCSSFromCIE1931XYZ,
toDisplayP3ComponentFromLinearDisplayP3Component,
toHexStringFromRGB,
toHSIHFromRGB,
toHSIIFromRGB,
toHSISFromRGB,
toHSLLFromRGB,
toHSVSFromRGB,
toHSVVFromRGB,
toIntegerFromRGB,
toLABAFromLCH,
toLABBFromLCH,
toLCHCFromLAB,
toLCHHFromLAB,
toLinearAdobeRGBBFromCIE1931XYZ,
toLinearAdobeRGBComponentFromAdobeRGBComponent,
toLinearAdobeRGBGFromCIE1931XYZ,
toLinearAdobeRGBRFromCIE1931XYZ,
toLinearDisplayP3BFromCIE1931XYZ,
toLinearDisplayP3ComponentFromDisplayP3Component,
toLinearDisplayP3GFromCIE1931XYZ,
toLinearDisplayP3RFromCIE1931XYZ,
toLinearSRGBBFromCIE1931XYZ,
toLinearSRGBComponentFromSRGBComponent,
toLinearSRGBGFromCIE1931XYZ,
toLinearSRGBRFromCIE1931XYZ,
toLMSComponentFromLMSDashComponent,
toLMSDashComponentFromLMSComponent,
toLMSDashLFromOklab,
toLMSDashMFromOklab,
toLMSDashSFromOklab,
toLMSLFromCIE1931XYZ,
toLMSMFromCIE1931XYZ,
toLMSSFromCIE1931XYZ,
toOklabAFromLMSDash,
toOklabBFromLMSDash,
toOklabLFromLMSDash,
toRGBBFromHexString,
toRGBBFromHSI,
toRGBBFromHSL,
toRGBBFromHSV,
toRGBBFromInteger,
toRGBGFromHexString,
toRGBGFromHSI,
toRGBGFromHSL,
toRGBGFromHSV,
toRGBGFromInteger,
toRGBRFromHexString,
toRGBRFromHSI,
toRGBRFromHSL,
toRGBRFromHSV,
toRGBRFromInteger,
toSharedHueFromRGB,
toSRGBComponentFromLinearSRGBComponent,
} from "./conversions";
import type {PerceptualColorSpace, RGBColorSpace} from "./index";
const MAP_LINEAR_TO_RGB = {
sRGB: toSRGBComponentFromLinearSRGBComponent,
"Display P3": toDisplayP3ComponentFromLinearDisplayP3Component,
"Adobe RGB": toAdobeRGBComponentFromLinearAdobeRGBComponent,
} as const;
const MAP_RGB_TO_LINEAR = {
sRGB: toLinearSRGBComponentFromSRGBComponent,
"Display P3": toLinearDisplayP3ComponentFromDisplayP3Component,
"Adobe RGB": toLinearAdobeRGBComponentFromAdobeRGBComponent,
} as const;
const MAP_CIE_1931_XYZ_TO_LINEAR_RGB_R = {
sRGB: toLinearSRGBRFromCIE1931XYZ,
"Display P3": toLinearDisplayP3RFromCIE1931XYZ,
"Adobe RGB": toLinearAdobeRGBRFromCIE1931XYZ,
} as const;
const MAP_CIE_1931_XYZ_TO_LINEAR_RGB_G = {
sRGB: toLinearSRGBGFromCIE1931XYZ,
"Display P3": toLinearDisplayP3GFromCIE1931XYZ,
"Adobe RGB": toLinearAdobeRGBGFromCIE1931XYZ,
} as const;
const MAP_CIE_1931_XYZ_TO_LINEAR_RGB_B = {
sRGB: toLinearSRGBBFromCIE1931XYZ,
"Display P3": toLinearDisplayP3BFromCIE1931XYZ,
"Adobe RGB": toLinearAdobeRGBBFromCIE1931XYZ,
} as const;
const MAP_LINEAR_TO_CIE_1931_XYZ = {
sRGB: [
toCIE1931XYZXFromLinearSRGB,
toCIE1931XYZYFromLinearSRGB,
toCIE1931XYZZFromLinearSRGB,
] as const,
"Display P3": [
toCIE1931XYZXFromLinearDisplayP3,
toCIE1931XYZYFromLinearDisplayP3,
toCIE1931XYZZFromLinearDisplayP3,
] as const,
"Adobe RGB": [
toCIE1931XYZXFromLinearAdobeRGB,
toCIE1931XYZYFromLinearAdobeRGB,
toCIE1931XYZZFromLinearAdobeRGB,
] as const,
} as const;
/**
* Represents a color. You can create colors from various color models and spaces.
*
* Instances of this class are immutable.
* On instantiation, the color is converted to CIE 1931 XYZ internally,
* and properties are calculated from that on access (lazily).
*
* ## Example
*
* ```ts
* const srgbRed = Color.fromRGB(1, 0, 0, "sRGB");
*
* // Logs the RGB values of the Display P3 representation.
* console.log(srgbRed.r("Display P3"), srgbRed.g("Display P3"), srgbRed.b("Display P3"));
* ```
*/
export class Color {
private constructor(
private readonly _X: number,
private readonly _Y: number,
private readonly _Z: number,
) {
}
// CIE 1931 XYZ
/**
* Creates a new color from the given CIE 1931 XYZ components.
*
* @param X The X component of CIE 1931 XYZ.
* @param Y The Y component of CIE 1931 XYZ.
* @param Z The Z component of CIE 1931 XYZ.
*
* @returns The new color.
*/
static fromCIE1931XYZ(X: number, Y: number, Z: number): Color {
return new Color(X, Y, Z);
}
/**
* Creates a new color from the given CIE 1931 xyY components.
*
* @param x The x component of CIE 1931 xyY, range [0, 1].
* @param y The y component of CIE 1931 xyY, range [0, 1].
* @param Y The Y component of CIE 1931 xyY, range [0, 1].
*
* @returns The new color.
*/
static fromCIE1931xyY(x: number, y: number, Y: number): Color {
const X = toCIE1931XYZXFromCIE1931xyY(x, y, Y),
Z = toCIE1931XYZZFromCIE1931xyY(x, y, Y);
return new Color(X, Y, Z);
}
/**
* Creates a new color from the given RGB components and color space.
*
* @param r The red component of RGB, typically in the range [0, 1].
* @param g The green component of RGB, typically in the range [0, 1].
* @param b The blue component of RGB, typically in the range [0, 1].
* @param colorSpace The RGB color space to use.
*
* @returns The new color.
*/
static fromRGB(r: number, g: number, b: number, colorSpace: RGBColorSpace): Color {
const toLinear = MAP_RGB_TO_LINEAR[colorSpace];
return Color.fromLinearRGB(toLinear(r), toLinear(g), toLinear(b), colorSpace);
}
/**
* Creates a new color from the given hex string representation.
* The string can be in either of the formats listed below:
*
* * `"RGB"`
* * `"#RGB"`
* * `"RRGGBB"`
* * `"#RRGGBB"`
*
* Ignores any following characters. Defaults to 0 if the string/component is invalid.
*
* @param hex The hex string.
* @param colorSpace The RGB color space to use.
*
* @returns A new color.
*/
static fromHexString(hex: string, colorSpace: RGBColorSpace): Color {
return Color.fromRGB(
toRGBRFromHexString(hex),
toRGBGFromHexString(hex),
toRGBBFromHexString(hex),
colorSpace,
);
}
// CIE 1931 xyY
/**
* Creates a new color from the given integer representation in the format `0xRRGGBB`.
* **All other bits will be ignored, including the alpha component.**
*
* @param integer The integer representation.
* @param colorSpace The RGB color space to use.
*
* @returns A new color.
*/
static fromInteger(integer: number, colorSpace: RGBColorSpace): Color {
return Color.fromRGB(
toRGBRFromInteger(integer),
toRGBGFromInteger(integer),
toRGBBFromInteger(integer),
colorSpace,
);
}
/**
* Creates a new color from the given HSV components.
*
* @param h The hue component of HSV, unbounded, in radians.
* @param s The saturation component of HSV, range [0, 1].
* @param v The value component of HSV, range [0, 1].
* @param colorSpace The color space to use.
*
* @returns The new color.
*/
static fromHSV(h: number, s: number, v: number, colorSpace: RGBColorSpace): Color {
return Color.fromRGB(
toRGBRFromHSV(h, s, v),
toRGBGFromHSV(h, s, v),
toRGBBFromHSV(h, s, v),
colorSpace,
);
}
/**
* Creates a new color from the given HSL components.
*
* @param h The hue component of HSL, unbounded, in radians.
* @param s The saturation component of HSL, range [0, 1].
* @param l The value component of HSL, range [0, 1].
* @param colorSpace The color space to use.
*
* @returns The new color.
*/
static fromHSL(h: number, s: number, l: number, colorSpace: RGBColorSpace): Color {
return Color.fromRGB(
toRGBRFromHSL(h, s, l),
toRGBGFromHSL(h, s, l),
toRGBBFromHSL(h, s, l),
colorSpace,
);
}
// RGB
/**
* Creates a new color from the given HSI components.
*
* @param h The hue component of HSI, unbounded, in radians.
* @param s The saturation component of HSI, range [0, 1].
* @param i The value component of HSI, range [0, 1].
* @param colorSpace The color space to use.
*
* @returns The new color.
*/
static fromHSI(h: number, s: number, i: number, colorSpace: RGBColorSpace): Color {
return Color.fromRGB(
toRGBRFromHSI(h, s, i),
toRGBGFromHSI(h, s, i),
toRGBBFromHSI(h, s, i),
colorSpace,
);
}
/**
* Creates a new color from the given linear RGB components.
*
* @param lr The red component of linear RGB, range [0, 1].
* @param lg The green component of linear RGB, range [0, 1].
* @param lb The blue component of linear RGB, range [0, 1].
* @param colorSpace The color space to use.
*
* @return The new color.
*/
static fromLinearRGB(lr: number, lg: number, lb: number, colorSpace: RGBColorSpace): Color {
const [tr, tg, tb] = MAP_LINEAR_TO_CIE_1931_XYZ[colorSpace];
return new Color(
tr(lr, lg, lb),
tg(lr, lg, lb),
tb(lr, lg, lb),
);
}
/**
* Creates a new color from the given LAB components.
*
* @param l The luminance component of LAB, range [0, 1].
* @param a The a component of LAB, unbounded.
* @param b The b component of LAB, unbounded.
* @param colorSpace The color space to use.
*
* @return The new color.
*/
static fromLAB(l: number, a: number, b: number, colorSpace: PerceptualColorSpace): Color {
if(colorSpace === "Ok") {
const _l = toLMSComponentFromLMSDashComponent(toLMSDashLFromOklab(l, a, b));
const _m = toLMSComponentFromLMSDashComponent(toLMSDashMFromOklab(l, a, b));
const _s = toLMSComponentFromLMSDashComponent(toLMSDashSFromOklab(l, a, b));
return new Color(
toCIE1931XYZXFromLMS(_l, _m, _s),
toCIE1931XYZYFromLMS(_l, _m, _s),
toCIE1931XYZZFromLMS(_l, _m, _s),
);
}
return new Color(
toCIE1931XYZXFromCIELAB(l, a),
toCIE1931XYZYFromCIELAB(l),
toCIE1931XYZZFromCIELAB(l, b),
);
}
/**
* Creates a new color from the given LCH components.
*
* @param l The luminance component of LCH, range [0, 1].
* @param c The chromaticity component of LCH, unbounded.
* @param h The hue component of LCH, unbounded, in radians.
* @param colorSpace The color space to use.
*
* @returns The new color.
*/
static fromLCH(l: number, c: number, h: number, colorSpace: PerceptualColorSpace): Color {
return Color.fromLAB(
l,
toLABAFromLCH(c, h),
toLABBFromLCH(c, h),
colorSpace,
);
}
/**
* Calculates the X component of the color in the CIE 1931 XYZ color space.
*/
X(): number {
return this._X;
}
/**
* Calculates the Y component of the color in the CIE 1931 XYZ color space.
*/
Y(): number {
return this._Y;
}
/**
* Calculates the Z component of the color in the CIE 1931 XYZ color space.
*/
Z(): number {
return this._Z;
}
/**
* Calculates the x component of the color in the CIE 1931 xyY color space.
*/
x(): number {
return toCIE1931xyYxFromCIE1931XYZ(this._X, this._Y, this._Z);
}
// Cylindrical
/**
* Calculates the y component of the color in the CIE 1931 xyY color space.
*/
y(): number {
return toCIE1931xyYyFromCIE1931XYZ(this._X, this._Y, this._Z);
}
/**
* Calculates the red component of the color in the RGB color model.
* @param colorSpace The color space to use.
*/
r(colorSpace: RGBColorSpace): number {
return MAP_LINEAR_TO_RGB[colorSpace](this.lr(colorSpace));
}
/**
* Calculates the green component of the color in the RGB color model.
* @param colorSpace The color space to use.
*/
g(colorSpace: RGBColorSpace): number {
return MAP_LINEAR_TO_RGB[colorSpace](this.lg(colorSpace));
}
/**
* Calculates the blue component of the color in the RGB color model.
* @param colorSpace The color space to use.
*/
b(colorSpace: RGBColorSpace): number {
return MAP_LINEAR_TO_RGB[colorSpace](this.lb(colorSpace));
}
/**
* Calculates the hex string representation in the format `"RRGGBB"` of the color in RGB.
* **Every component, including alpha, will be clamped to the range [0, 1] before processing.**
* If an alpha value is specified, the format will be `"RRGGBBAA"`.
*
* Uses {@link toHexStringFromRGB `toHexStringFromRGB(...)`} internally.
*
* @param colorSpace The color space to use.
* @param alpha - An optional alpha component, range [0, 1].
*
* @returns The hexadecimal representation of the color.
*/
hex(colorSpace: RGBColorSpace, alpha?: number): string {
return toHexStringFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
alpha,
);
}
/**
* Calculates the integer representation in the format `0xAARRGGBB` of the color in RGB.
* **Every component, including alpha, will be clamped to the range [0, 1] before processing.**
*
* Uses {@link toIntegerFromRGB `toIntegerFromRGB(...)`} internally.
*
* @param colorSpace The RGB color space to use.
* @param alpha The alpha value to use, range [0, 1], defaults to 0.
*
* @returns The integer representation of the color.
*/
int(colorSpace: RGBColorSpace, alpha: number = 0): number {
return toIntegerFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
alpha,
);
}
/**
* Calculates the shared hue component of the current color in the HSL/HSV color model.
* @param colorSpace The color space to use.
*/
h(colorSpace: RGBColorSpace): number {
return toSharedHueFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the hue component of the color in the HSI color model.
* @param colorSpace The color space to use.
*/
h2(colorSpace: RGBColorSpace): number {
return toHSIHFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the saturation component of the color in the HSL color model.
* @param colorSpace The color model to use.
*/
sl(colorSpace: RGBColorSpace): number {
return toHSLLFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the saturation component of the color in the HSV color model.
* @param colorSpace The color space to use.
*/
sv(colorSpace: RGBColorSpace): number {
return toHSVSFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the saturation component of the color in the HSI color model.
* @param colorSpace The color space to use.
*/
si(colorSpace: RGBColorSpace): number {
return toHSISFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
// Linear RGB
/**
* Calculates the lightness component of the color in the HSL color model.
* @param colorSpace The color space to use.
*/
l(colorSpace: RGBColorSpace): number {
return toHSLLFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the value component of the color in the HSV color model.
* @param colorSpace The color space to use.
*/
v(colorSpace: RGBColorSpace): number {
return toHSVVFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the intensity component of the color in the HSI color model.
* @param colorSpace The color space to use.
*/
i(colorSpace: RGBColorSpace): number {
return toHSIIFromRGB(
this.r(colorSpace),
this.g(colorSpace),
this.b(colorSpace),
);
}
/**
* Calculates the red component of the color in linear RGB.
* @param colorSpace The color space to use.
*/
lr(colorSpace: RGBColorSpace): number {
return MAP_CIE_1931_XYZ_TO_LINEAR_RGB_R[colorSpace](this._X, this._Y, this._Z);
}
// LAB / LCH
/**
* Calculates the green component of the color in linear RGB.
* @param colorSpace The color space to use.
*/
lg(colorSpace: RGBColorSpace): number {
return MAP_CIE_1931_XYZ_TO_LINEAR_RGB_G[colorSpace](this._X, this._Y, this._Z);
}
/**
* Calculates the blue component of the color in linear RGB.
* @param colorSpace The color space to use.
*/
lb(colorSpace: RGBColorSpace): number {
return MAP_CIE_1931_XYZ_TO_LINEAR_RGB_B[colorSpace](this._X, this._Y, this._Z);
}
/**
* Calculates the shared luminance component of the color in the LAB/LCH color model.
* @param colorSpace The color space to use.
*/
pl(colorSpace: PerceptualColorSpace): number {
if(colorSpace === "Ok") {
const _l = toLMSDashComponentFromLMSComponent(toLMSLFromCIE1931XYZ(this._X, this._Y, this._Z)),
_m = toLMSDashComponentFromLMSComponent(toLMSMFromCIE1931XYZ(this._X, this._Y, this._Z)),
_s = toLMSDashComponentFromLMSComponent(toLMSSFromCIE1931XYZ(this._X, this._Y, this._Z));
return toOklabLFromLMSDash(_l, _m, _s);
}
return toCIELABLFromCIE1931XYZ(this._Y);
}
/**
* Calculates the a component of the color in the LAB color model.
* @param colorSpace The color space to use.
*/
pa(colorSpace: PerceptualColorSpace): number {
if(colorSpace === "Ok") {
const _l = toLMSDashComponentFromLMSComponent(toLMSLFromCIE1931XYZ(this._X, this._Y, this._Z)),
_m = toLMSDashComponentFromLMSComponent(toLMSMFromCIE1931XYZ(this._X, this._Y, this._Z)),
_s = toLMSDashComponentFromLMSComponent(toLMSSFromCIE1931XYZ(this._X, this._Y, this._Z));
return toOklabAFromLMSDash(_l, _m, _s);
}
return toCIELABAFromCIE1931XYZ(this._X, this._Y);
}
/**
* Calculates the b component of the color in the LAB color model.
* @param colorSpace The color space to use
*/
pb(colorSpace: PerceptualColorSpace): number {
if(colorSpace === "Ok") {
const _l = toLMSDashComponentFromLMSComponent(toLMSLFromCIE1931XYZ(this._X, this._Y, this._Z)),
_m = toLMSDashComponentFromLMSComponent(toLMSMFromCIE1931XYZ(this._X, this._Y, this._Z)),
_s = toLMSDashComponentFromLMSComponent(toLMSSFromCIE1931XYZ(this._X, this._Y, this._Z));
return toOklabBFromLMSDash(_l, _m, _s);
}
return toCIELABBFromCIE1931XYZ(this._Y, this._Z);
}
/**
* Calculates the chromaticity component of the color in the LCH color model.
* @param colorSpace The color space to use.
*/
pc(colorSpace: PerceptualColorSpace): number {
return toLCHCFromLAB(this.pa(colorSpace), this.pb(colorSpace));
}
/**
* Calculates the hue component of the color in the LCH color model.
* @param colorSpace The color space to use.
*/
ph(colorSpace: PerceptualColorSpace): number {
return toLCHHFromLAB(this.pa(colorSpace), this.pb(colorSpace));
}
// Common
/**
* Calculates the CSS representation of the color.
*
* Uses {@link toCSSFromCIE1931XYZ `toCSSFromCIE1931XYZ(...)`} internally.
*
* @param alpha The alpha component, optional, range [0, 1].
*
* @returns The CSS representation of the color.
*/
css(alpha?: number): string {
return toCSSFromCIE1931XYZ(this._X, this._Y, this._Z, alpha);
}
}