@@ -8,7 +8,13 @@ export type Hex = string & { __hex: true };
88 * @property B A number from 0-255 representing blue.
99 * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
1010 */
11- export type Rgb = { R : number ; G : number ; B : number ; a ?: number ; colorspace : 'rgba' } ;
11+ export type Rgb = {
12+ R : number ;
13+ G : number ;
14+ B : number ;
15+ a ?: number ;
16+ colorspace : 'rgba' ;
17+ } ;
1218export type RgbString = string & { __rgba : true } ;
1319
1420/**
@@ -18,7 +24,28 @@ export type RgbString = string & { __rgba: true };
1824 * @property B A number from 0-255 representing blue.
1925 * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
2026 */
21- export type Lrgb = { R : number ; G : number ; B : number ; a ?: number ; colorspace : 'lrgb' } ;
27+ export type Lrgb = {
28+ R : number ;
29+ G : number ;
30+ B : number ;
31+ a ?: number ;
32+ colorspace : 'lrgb' ;
33+ } ;
34+
35+ /**
36+ * CIE XYZ D50 colorspace.
37+ * @property X No idea. I'm sorry.
38+ * @property Y No idea. I'm sorry.
39+ * @property Z No idea. I'm sorry.
40+ * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
41+ */
42+ export type Xyz50 = {
43+ X : number ;
44+ Y : number ;
45+ Z : number ;
46+ a ?: number ;
47+ colorspace : 'xyz50' ;
48+ } ;
2249
2350/**
2451 * hsla() colorspace.
@@ -27,7 +54,13 @@ export type Lrgb = { R: number; G: number; B: number; a?: number; colorspace: 'l
2754 * @property L A number from 0-100 representing lightness.
2855 * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
2956 */
30- export type Hsl = { H : number ; S : number ; L : number ; a ?: number ; colorspace : 'hsla' } ;
57+ export type Hsl = {
58+ H : number ;
59+ S : number ;
60+ L : number ;
61+ a ?: number ;
62+ colorspace : 'hsla' ;
63+ } ;
3164export type HslString = string & { __hsla : true } ;
3265
3366/**
@@ -37,7 +70,13 @@ export type HslString = string & { __hsla: true };
3770 * @property B A number from ~-0.5-~0.5 representing blue (negative) - yellow (positive).
3871 * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
3972 */
40- export type Oklab = { L : number ; A : number ; B : number ; a ?: number ; colorspace : 'oklab' } ;
73+ export type Oklab = {
74+ L : number ;
75+ A : number ;
76+ B : number ;
77+ a ?: number ;
78+ colorspace : 'oklab' ;
79+ } ;
4180
4281/**
4382 * oklch() colorspace.
@@ -46,7 +85,13 @@ export type Oklab = { L: number; A: number; B: number; a?: number; colorspace: '
4685 * @property H A number from 0-360 representing hue angle.
4786 * @property a A number from 0-1 representing alpha. Assumed 1 if not set.
4887 */
49- export type Oklch = { L : number ; C : number ; H : number ; a ?: number ; colorspace : 'oklch' } ;
88+ export type Oklch = {
89+ L : number ;
90+ C : number ;
91+ H : number ;
92+ a ?: number ;
93+ colorspace : 'oklch' ;
94+ } ;
5095export type OklchString = string & { __oklch : string } ;
5196
5297// endregion Types
@@ -66,15 +111,17 @@ export function StringToHex(hex: string): Hex | null {
66111}
67112
68113export function HexToRgb ( hex : Hex ) : Rgb {
69- const hexVal = hex . replace ( / ^ # ? / , '#' ) ;
70- if ( ! StringToHex ( hexVal ) ) return { R : 0 , G : 0 , B : 0 , colorspace : 'rgba' } ;
114+ const hexVal = StringToHex ( hex ) ;
115+ if ( ! hexVal ) return { R : 0 , G : 0 , B : 0 , colorspace : 'rgba' } ;
71116 const isShortHand = hex . length === 3 || hex . length === 4 ;
72117
73- const R = parseInt ( isShortHand ? hexVal . substring ( 1 , 2 ) . repeat ( 2 ) : hexVal . substring ( 1 , 3 ) , 16 ) ;
74- const G = parseInt ( isShortHand ? hexVal . substring ( 2 , 3 ) . repeat ( 2 ) : hexVal . substring ( 3 , 5 ) , 16 ) ;
75- const B = parseInt ( isShortHand ? hexVal . substring ( 3 , 4 ) . repeat ( 2 ) : hexVal . substring ( 5 , 7 ) , 16 ) ;
76- const a = parseInt ( isShortHand ? hexVal . substring ( 4 , 5 ) . repeat ( 2 ) : hexVal . substring ( 7 , 9 ) , 16 ) ;
77- return { colorspace : 'rgba' , R, G, B, ...( a < 255 ? { a : a / 255 } : undefined ) } ;
118+ const R = parseInt ( isShortHand ? hexVal . substring ( 0 , 1 ) . repeat ( 2 ) : hexVal . substring ( 0 , 2 ) , 16 ) ;
119+ const G = parseInt ( isShortHand ? hexVal . substring ( 1 , 2 ) . repeat ( 2 ) : hexVal . substring ( 2 , 4 ) , 16 ) ;
120+ const B = parseInt ( isShortHand ? hexVal . substring ( 2 , 3 ) . repeat ( 2 ) : hexVal . substring ( 4 , 6 ) , 16 ) ;
121+ const a = parseInt ( isShortHand ? hexVal . substring ( 3 , 4 ) . repeat ( 2 ) : hexVal . substring ( 6 , 8 ) , 16 ) ;
122+ const rgba : Rgb = { colorspace : 'rgba' , R, G, B } ;
123+ if ( hex . length === 4 || hex . length === 8 ) rgba . a = a ;
124+ return rgba ;
78125}
79126
80127export function RgbToHex ( { R, G, B, a } : Rgb ) : Hex {
@@ -131,11 +178,34 @@ export function RgbToLrgb({ R, G, B, a }: Rgb): Lrgb {
131178 }
132179 return ( Math . sign ( c ) || 1 ) * Math . pow ( ( abs + 0.055 ) / 1.055 , 2.4 ) ;
133180 } ;
134- const lrgb : Lrgb = { colorspace : 'lrgb' , R : mapper ( R / 255 ) , G : mapper ( G / 255 ) , B : mapper ( B / 255 ) } ;
181+ const lrgb : Lrgb = {
182+ colorspace : 'lrgb' ,
183+ R : mapper ( R / 255 ) ,
184+ G : mapper ( G / 255 ) ,
185+ B : mapper ( B / 255 ) ,
186+ } ;
135187 if ( typeof a === 'number' ) lrgb . a = a ;
136188 return lrgb ;
137189}
138190
191+ export function LrgbToRgb ( { R, G, B, a } : Lrgb ) : Rgb {
192+ const mapper = ( c : number ) : number => {
193+ const abs = Math . abs ( c ) ;
194+ if ( abs > 0.0031308 ) {
195+ return Math . round ( ( Math . sign ( c ) || 1 ) * ( 1.055 * Math . pow ( abs , 1 / 2.4 ) - 0.055 ) * 255 ) ;
196+ }
197+ return Math . round ( c * 12.92 * 255 ) ;
198+ } ;
199+ const rgb : Rgb = {
200+ colorspace : 'rgba' ,
201+ R : mapper ( R ) ,
202+ G : mapper ( G ) ,
203+ B : mapper ( B ) ,
204+ } ;
205+ if ( typeof a === 'number' ) rgb . a = a ;
206+ return rgb ;
207+ }
208+
139209export function LrgbToOklab ( { R, G, B, a } : Lrgb ) : Oklab {
140210 const L = Math . cbrt ( 0.412221469470763 * R + 0.5363325372617348 * G + 0.0514459932675022 * B ) ;
141211 const M = Math . cbrt ( 0.2119034958178252 * R + 0.6806995506452344 * G + 0.1073969535369406 * B ) ;
@@ -152,13 +222,45 @@ export function LrgbToOklab({ R, G, B, a }: Lrgb): Oklab {
152222 return oklab ;
153223}
154224
225+ export function OklabToLrgb ( { L, A, B, a } : Oklab ) : Lrgb {
226+ const l = Math . pow ( L + 0.3963377773761749 * A + 0.2158037573099136 * B , 3 ) ;
227+ const m = Math . pow ( L - 0.1055613458156586 * A - 0.0638541728258133 * B , 3 ) ;
228+ const s = Math . pow ( L - 0.0894841775298119 * A - 1.2914855480194092 * B , 3 ) ;
229+
230+ const lrgb : Lrgb = {
231+ colorspace : 'lrgb' ,
232+ R : 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s ,
233+ G : - 1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s ,
234+ B : - 0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s ,
235+ } ;
236+
237+ if ( typeof a === 'number' ) lrgb . a = a ;
238+ return lrgb ;
239+ }
240+
155241export function OklabToOklch ( { L, A, B, a } : Oklab ) : Oklch {
156242 const C = Math . sqrt ( A ** 2 + B ** 2 ) ;
157- const oklch : Oklch = { colorspace : 'oklch' , L, C, H : C ? normalizeHue ( ( Math . atan2 ( B , A ) * 180 ) / Math . PI ) : 0 } ;
243+ const oklch : Oklch = {
244+ colorspace : 'oklch' ,
245+ L,
246+ C,
247+ H : C ? normalizeHue ( ( Math . atan2 ( B , A ) * 180 ) / Math . PI ) : 0 ,
248+ } ;
158249 if ( typeof a === 'number' ) oklch . a = a ;
159250 return oklch ;
160251}
161252
253+ export function OklchToOklab ( { L, C, H, a } : Oklch ) : Oklab {
254+ const oklab : Oklab = {
255+ colorspace : 'oklab' ,
256+ L,
257+ A : C ? C * Math . cos ( ( H * Math . PI ) / 180 ) : 0 ,
258+ B : C ? C * Math . sin ( ( H * Math . PI ) / 180 ) : 0 ,
259+ } ;
260+ if ( typeof a === 'number' ) oklab . a = a ;
261+ return oklab ;
262+ }
263+
162264export function HexToOklab ( hex : Hex ) : Oklab {
163265 return LrgbToOklab ( RgbToLrgb ( HexToRgb ( hex ) ) ) ;
164266}
@@ -171,6 +273,10 @@ export function HexToOklch(hex: Hex): Oklch {
171273 return RgbToOklch ( HexToRgb ( hex ) ) ;
172274}
173275
276+ export function OklchToHex ( oklch : Oklch ) : Hex {
277+ return RgbToHex ( LrgbToRgb ( OklabToLrgb ( OklchToOklab ( oklch ) ) ) ) ;
278+ }
279+
174280// endregion Conversion Methods
175281
176282/**
0 commit comments