tangled
alpha
login
or
join now
quilling.dev
/
social-app
7
fork
atom
An ATproto social media client -- with an independent Appview.
7
fork
atom
overview
issues
pulls
pipelines
feat: color representation conversion
serenity
6 months ago
764b0e51
19e4ea2c
+220
1 changed file
expand all
collapse all
unified
split
src
alf
util
colors
converstion.ts
+220
src/alf/util/colors/converstion.ts
···
1
1
+
export interface HslColor {
2
2
+
h: number
3
3
+
s: number
4
4
+
l: number
5
5
+
}
6
6
+
7
7
+
export interface RgbColor {
8
8
+
r: number
9
9
+
g: number
10
10
+
b: number
11
11
+
}
12
12
+
13
13
+
export type HexCode = `#${string}` | string
14
14
+
15
15
+
/**
16
16
+
* Converts a hexcode string in the format `"#RRGGBB"` to a `HslColor` object (`{ h: number, s: number, l: number }`).
17
17
+
* @param {HexCode} hex - A hexcode string in the format `#RRGGBB`. The leading "#" symbol is optional.
18
18
+
* @returns{HslColor} A HSL colour object.
19
19
+
*/
20
20
+
export const hexToHsl = (hex: HexCode): HslColor => {
21
21
+
hex = hex.replace('#', '')
22
22
+
23
23
+
const r = parseInt(hex.substring(0, 2), 16) / 255
24
24
+
const g = parseInt(hex.substring(2, 4), 16) / 255
25
25
+
const b = parseInt(hex.substring(4, 6), 16) / 255
26
26
+
27
27
+
const max = Math.max(r, g, b)
28
28
+
const min = Math.min(r, g, b)
29
29
+
const diff = max - min
30
30
+
31
31
+
let h = 0,
32
32
+
s,
33
33
+
l
34
34
+
35
35
+
l = (max + min) / 2
36
36
+
37
37
+
if (diff === 0) {
38
38
+
h = s = 0
39
39
+
} else {
40
40
+
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min)
41
41
+
42
42
+
switch (max) {
43
43
+
case r:
44
44
+
h = (g - b) / diff + (g < b ? 6 : 0)
45
45
+
break
46
46
+
case g:
47
47
+
h = (b - r) / diff + 2
48
48
+
break
49
49
+
case b:
50
50
+
h = (r - g) / diff + 4
51
51
+
break
52
52
+
}
53
53
+
h /= 6
54
54
+
}
55
55
+
56
56
+
return {
57
57
+
h: h * 360,
58
58
+
s: s * 100,
59
59
+
l: l * 100,
60
60
+
}
61
61
+
}
62
62
+
63
63
+
/**
64
64
+
* Converts a `HslColor` object (`{ h: number, s: number, l: number }`) to a hexcode string in the format `"#RRGGBB"`.
65
65
+
* @param {HslColor} hsl - A HSL colour object.
66
66
+
* @param {boolean} appendSymbol - Whether to append "#" to the start of the hex string. Defaults to true.
67
67
+
* @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional.
68
68
+
*/
69
69
+
export const hslToHex = (
70
70
+
{h, s, l}: HslColor,
71
71
+
appendSymbol: boolean = true,
72
72
+
): HexCode => {
73
73
+
h = (h % 360) / 360
74
74
+
s = Math.max(0, Math.min(1, s / 100))
75
75
+
l = Math.max(0, Math.min(1, l / 100))
76
76
+
77
77
+
let m2: number, m1: number
78
78
+
79
79
+
if (l <= 0.5) {
80
80
+
m2 = l * (s + 1)
81
81
+
} else {
82
82
+
m2 = l + s - l * s
83
83
+
}
84
84
+
85
85
+
m1 = l * 2 - m2
86
86
+
87
87
+
function hue(hueValue: number) {
88
88
+
hueValue =
89
89
+
hueValue < 0 ? hueValue + 1 : hueValue > 1 ? hueValue - 1 : hueValue
90
90
+
91
91
+
if (hueValue * 6 < 1) {
92
92
+
return m1 + (m2 - m1) * hueValue * 6
93
93
+
} else if (hueValue * 2 < 1) {
94
94
+
return m2
95
95
+
} else if (hueValue * 3 < 2) {
96
96
+
return m1 + (m2 - m1) * (2 / 3 - hueValue) * 6
97
97
+
} else {
98
98
+
return m1
99
99
+
}
100
100
+
}
101
101
+
102
102
+
const r = hue(h + 1 / 3) * 255
103
103
+
const g = hue(h) * 255
104
104
+
const b = hue(h - 1 / 3) * 255
105
105
+
106
106
+
return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}`
107
107
+
}
108
108
+
109
109
+
/**
110
110
+
* Converts an `RgbColor` object (`{ r: number, g: number, b: number }`) to a hexcode string in the format `"#RRGGBB"`.
111
111
+
* @param {RgbColor} rgb - An RGB colour object.
112
112
+
* @param {boolean} appendSymbol - Whether to append "#" to the start of the hex string. Defaults to true.
113
113
+
* @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional.
114
114
+
*/
115
115
+
export const rgbToHex = (
116
116
+
{r, g, b}: RgbColor,
117
117
+
appendSymbol: boolean = true,
118
118
+
): HexCode => {
119
119
+
return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}`
120
120
+
}
121
121
+
122
122
+
/**
123
123
+
* Converts a hexcode string in the format `"#RRGGBB"` to an `RgbColor` object (`{ r: number, g: number, b: number }`).
124
124
+
* @param {HexCode} hex - A hexcode string in the format `#RRGGBB`. The leading "#" symbol is optional.
125
125
+
* @returns {RgbColor} An RGB colour object.
126
126
+
*/
127
127
+
export const hexToRgb = (hex: HexCode): RgbColor => {
128
128
+
hex = hex.replace('#', '')
129
129
+
const r = parseInt(hex.substring(0, 2), 16) / 255
130
130
+
const g = parseInt(hex.substring(2, 4), 16) / 255
131
131
+
const b = parseInt(hex.substring(4, 6), 16) / 255
132
132
+
return {r, g, b}
133
133
+
}
134
134
+
135
135
+
/**
136
136
+
* Converts an `RgbColor` object (`{ r: number, g: number, b: number }`) to a `HslColor` object (`{ h: number, s: number, l: number }`)
137
137
+
* @param {RgbColor} - An RGB colour object.
138
138
+
* @returns {HslColor} A HSL colour object.
139
139
+
*/
140
140
+
export const rgbToHsl = ({r, g, b}: RgbColor): HslColor => {
141
141
+
r = r / 255
142
142
+
g = g / 255
143
143
+
b = b / 255
144
144
+
const max = Math.max(r, g, b)
145
145
+
const min = Math.min(r, g, b)
146
146
+
const diff = max - min
147
147
+
148
148
+
let h = 0,
149
149
+
s,
150
150
+
l
151
151
+
152
152
+
l = (max + min) / 2
153
153
+
154
154
+
if (diff === 0) {
155
155
+
h = s = 0
156
156
+
} else {
157
157
+
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min)
158
158
+
159
159
+
switch (max) {
160
160
+
case r:
161
161
+
h = (g - b) / diff + (g < b ? 6 : 0)
162
162
+
break
163
163
+
case g:
164
164
+
h = (b - r) / diff + 2
165
165
+
break
166
166
+
case b:
167
167
+
h = (r - g) / diff + 4
168
168
+
break
169
169
+
}
170
170
+
h /= 6
171
171
+
}
172
172
+
173
173
+
return {
174
174
+
h: h * 360,
175
175
+
s: s * 100,
176
176
+
l: l * 100,
177
177
+
}
178
178
+
}
179
179
+
180
180
+
/**
181
181
+
* Converts a `HslColor` object (`{ h: number, s: number, l: number }`) to a `RgbColor` object (`{ r: number, g: number, b: number }`)
182
182
+
* @param {HslColor} - A HSL colour object.
183
183
+
* @returns {RgbColor} An RGB colour object.
184
184
+
*/
185
185
+
export const hslToRgb = ({h, s, l}: HslColor): RgbColor => {
186
186
+
h = (h % 360) / 360
187
187
+
s = Math.max(0, Math.min(1, s / 100))
188
188
+
l = Math.max(0, Math.min(1, l / 100))
189
189
+
190
190
+
let m2: number, m1: number
191
191
+
192
192
+
if (l <= 0.5) {
193
193
+
m2 = l * (s + 1)
194
194
+
} else {
195
195
+
m2 = l + s - l * s
196
196
+
}
197
197
+
198
198
+
m1 = l * 2 - m2
199
199
+
200
200
+
function hue(hueValue: number) {
201
201
+
hueValue =
202
202
+
hueValue < 0 ? hueValue + 1 : hueValue > 1 ? hueValue - 1 : hueValue
203
203
+
204
204
+
if (hueValue * 6 < 1) {
205
205
+
return m1 + (m2 - m1) * hueValue * 6
206
206
+
} else if (hueValue * 2 < 1) {
207
207
+
return m2
208
208
+
} else if (hueValue * 3 < 2) {
209
209
+
return m1 + (m2 - m1) * (2 / 3 - hueValue) * 6
210
210
+
} else {
211
211
+
return m1
212
212
+
}
213
213
+
}
214
214
+
215
215
+
const r = hue(h + 1 / 3) * 255
216
216
+
const g = hue(h) * 255
217
217
+
const b = hue(h - 1 / 3) * 255
218
218
+
219
219
+
return {r: Math.round(r), g: Math.round(g), b: Math.round(b)}
220
220
+
}