UNPKG

allc

Version:

A small typescript package for color conversion.

676 lines (615 loc) 22 kB
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); } }