From 01d93dc231148cf30fadad041e1ca7c726948e5a Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Mon, 3 Jan 2022 17:29:07 +0100 Subject: [PATCH] feat(color): update ChannelSpec and hue-based modes - add `hue` flag for channel spec - update `.clamp()` impl to wrap hue in [0..1] interval - add/update LCH conversion paths --- packages/color/src/api.ts | 7 +++++++ packages/color/src/defcolor.ts | 7 ++++++- packages/color/src/hcy/hcy.ts | 6 +++++- packages/color/src/hsi/hsi.ts | 6 +++++- packages/color/src/hsl/hsl.ts | 11 ++++++++++- packages/color/src/hsv/hsv.ts | 11 ++++++++++- packages/color/src/lch/lch.ts | 1 + 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/color/src/api.ts b/packages/color/src/api.ts index c9a2e8cd73..efb29273f6 100644 --- a/packages/color/src/api.ts +++ b/packages/color/src/api.ts @@ -64,9 +64,16 @@ export interface IColor { export interface ChannelSpec { /** * Acceptable value range for this channel. Used by {@link TypedColor.clamp}. + * * @defaultValue [0,1] */ range?: Range; + /** + * If true, this channel is used to store normalized hue values. + * + * @defaultValue false + */ + hue?: boolean; } export interface ColorSpec { diff --git a/packages/color/src/defcolor.ts b/packages/color/src/defcolor.ts index c84fa97607..38b714129c 100644 --- a/packages/color/src/defcolor.ts +++ b/packages/color/src/defcolor.ts @@ -5,6 +5,7 @@ import { isNumber } from "@thi.ng/checks/is-number"; import { isString } from "@thi.ng/checks/is-string"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { EPS } from "@thi.ng/math/api"; +import { fract } from "@thi.ng/math/prec"; import type { IRandom } from "@thi.ng/random"; import { vector } from "@thi.ng/strings/vector"; import { mapStridedBuffer } from "@thi.ng/vectors/buffer"; @@ -58,6 +59,8 @@ export const defColor = ( const maxR = set4([], max); minR[numChannels - 1] = 1; + const hueChanID = order.findIndex((id) => !!channels[id]!.hue); + const $Color = class implements TypedColor<$DefColor> { buf: NumericArray; [id: number]: number; @@ -114,7 +117,9 @@ export const defColor = ( } clamp() { - return clamp4(null, this, min, max); + hueChanID >= 0 && (this[hueChanID] = fract(this[hueChanID])); + clamp4(null, this, min, max); + return this; } eqDelta(o: $DefColor, eps = EPS): boolean { diff --git a/packages/color/src/hcy/hcy.ts b/packages/color/src/hcy/hcy.ts index 69b5ade46f..dc092fed0c 100644 --- a/packages/color/src/hcy/hcy.ts +++ b/packages/color/src/hcy/hcy.ts @@ -2,7 +2,10 @@ import type { NumericArray } from "@thi.ng/api"; import type { IRandom } from "@thi.ng/random"; import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api.js"; import { defColor } from "../defcolor.js"; +import { lchLab } from "../lab/lab-lch.js"; +import { labRgb } from "../lab/lab-rgb.js"; import { rgbHcy } from "../rgb/rgb-hcy.js"; +import { rgbSrgb } from "../rgb/rgb-srgb.js"; import { hcyRgb } from "./hcy-rgb.js"; export declare class HCY implements TypedColor { @@ -31,7 +34,8 @@ export declare class HCY implements TypedColor { export const hcy = >defColor({ mode: "hcy", + channels: { h: { hue: true } }, order: ["h", "c", "y", "alpha"], - from: { rgb: rgbHcy, srgb: rgbHcy }, + from: { rgb: rgbHcy, srgb: rgbHcy, lch: [lchLab, labRgb, rgbSrgb, rgbHcy] }, toRgb: hcyRgb, }); diff --git a/packages/color/src/hsi/hsi.ts b/packages/color/src/hsi/hsi.ts index e8e7b7f03c..55d0c11b6b 100644 --- a/packages/color/src/hsi/hsi.ts +++ b/packages/color/src/hsi/hsi.ts @@ -2,7 +2,10 @@ import type { NumericArray } from "@thi.ng/api"; import type { IRandom } from "@thi.ng/random"; import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api.js"; import { defColor } from "../defcolor.js"; +import { lchLab } from "../lab/lab-lch.js"; +import { labRgb } from "../lab/lab-rgb.js"; import { rgbHsi } from "../rgb/rgb-hsi.js"; +import { rgbSrgb } from "../rgb/rgb-srgb.js"; import { hsiRgb } from "./hsi-rgb.js"; export declare class HSI implements TypedColor { @@ -31,7 +34,8 @@ export declare class HSI implements TypedColor { export const hsi = >defColor({ mode: "hsi", + channels: { h: { hue: true } }, order: ["h", "s", "i", "alpha"], - from: { rgb: rgbHsi, srgb: rgbHsi }, + from: { rgb: rgbHsi, srgb: rgbHsi, lch: [lchLab, labRgb, rgbSrgb, rgbHsi] }, toRgb: hsiRgb, }); diff --git a/packages/color/src/hsl/hsl.ts b/packages/color/src/hsl/hsl.ts index 432b44aca7..b30b76ab03 100644 --- a/packages/color/src/hsl/hsl.ts +++ b/packages/color/src/hsl/hsl.ts @@ -3,7 +3,10 @@ import type { IRandom } from "@thi.ng/random"; import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api.js"; import { defColor } from "../defcolor.js"; import { hsvHsl } from "../hsv/hsv-hsl.js"; +import { lchLab } from "../lab/lab-lch.js"; +import { labRgb } from "../lab/lab-rgb.js"; import { rgbHsl } from "../rgb/rgb-hsl.js"; +import { rgbSrgb } from "../rgb/rgb-srgb.js"; import { hslRgb } from "./hsl-rgb.js"; export declare class HSL implements TypedColor { @@ -32,7 +35,13 @@ export declare class HSL implements TypedColor { export const hsl = >defColor({ mode: "hsl", + channels: { h: { hue: true } }, order: ["h", "s", "l", "alpha"], - from: { rgb: rgbHsl, srgb: rgbHsl, hsv: hsvHsl }, + from: { + rgb: rgbHsl, + srgb: rgbHsl, + hsv: hsvHsl, + lch: [lchLab, labRgb, rgbSrgb, rgbHsl], + }, toRgb: hslRgb, }); diff --git a/packages/color/src/hsv/hsv.ts b/packages/color/src/hsv/hsv.ts index 2b30cfdffb..df4ee0a253 100644 --- a/packages/color/src/hsv/hsv.ts +++ b/packages/color/src/hsv/hsv.ts @@ -3,7 +3,10 @@ import type { IRandom } from "@thi.ng/random"; import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api.js"; import { defColor } from "../defcolor.js"; import { hslHsv } from "../hsl/hsl-hsv.js"; +import { lchLab } from "../lab/lab-lch.js"; +import { labRgb } from "../lab/lab-rgb.js"; import { rgbHsv } from "../rgb/rgb-hsv.js"; +import { rgbSrgb } from "../rgb/rgb-srgb.js"; import { hsvRgb } from "./hsv-rgb.js"; export declare class HSV implements TypedColor { @@ -32,7 +35,13 @@ export declare class HSV implements TypedColor { export const hsv = >defColor({ mode: "hsv", + channels: { h: { hue: true } }, order: ["h", "s", "v", "alpha"], - from: { rgb: rgbHsv, srgb: rgbHsv, hsl: hslHsv }, + from: { + rgb: rgbHsv, + srgb: rgbHsv, + hsl: hslHsv, + lch: [lchLab, labRgb, rgbSrgb, rgbHsv], + }, toRgb: hsvRgb, }); diff --git a/packages/color/src/lch/lch.ts b/packages/color/src/lch/lch.ts index e22855b680..e67522f4e5 100644 --- a/packages/color/src/lch/lch.ts +++ b/packages/color/src/lch/lch.ts @@ -41,6 +41,7 @@ export const lch = >defColor({ mode: "lch", channels: { c: { range: [0, 1.312] }, + h: { hue: true }, }, order: ["l", "c", "h", "alpha"], from: {