-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Expand file tree
/
Copy pathcolor_conversion.js
More file actions
269 lines (241 loc) · 6.24 KB
/
color_conversion.js
File metadata and controls
269 lines (241 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/**
* @module Color
* @submodule Color Conversion
* @for p5
*/
/**
* Conversions adapted from <http://www.easyrgb.com/en/math.php>.
*
* In these functions, hue is always in the range [0, 1], just like all other
* components are in the range [0, 1]. 'Brightness' and 'value' are used
* interchangeably.
*/
import p5 from '../core/main';
p5.ColorConversion = {
/**
* Convert an HSBA array to HSLA.
*/
_hsbaToHSLA(hsba) {
const hue = hsba[0];
let sat = hsba[1];
const val = hsba[2];
// Calculate lightness.
const li = (2 - sat) * val / 2;
// Convert saturation.
if (li !== 0) {
if (li === 1) {
sat = 0;
} else if (li < 0.5) {
sat = sat / (2 - sat);
} else {
sat = sat * val / (2 - li * 2);
}
}
// Hue and alpha stay the same.
return [hue, sat, li, hsba[3]];
},
/**
* Convert an HSBA array to RGBA.
*/
_hsbaToRGBA(hsba) {
const hue = hsba[0] * 6; // We will split hue into 6 sectors.
const sat = hsba[1];
const val = hsba[2];
let RGBA = [];
if (sat === 0) {
RGBA = [val, val, val, hsba[3]]; // Return early if grayscale.
} else {
const sector = Math.floor(hue);
const tint1 = val * (1 - sat);
const tint2 = val * (1 - sat * (hue - sector));
const tint3 = val * (1 - sat * (1 + sector - hue));
let red, green, blue;
if (sector === 1) {
// Yellow to green.
red = tint2;
green = val;
blue = tint1;
} else if (sector === 2) {
// Green to cyan.
red = tint1;
green = val;
blue = tint3;
} else if (sector === 3) {
// Cyan to blue.
red = tint1;
green = tint2;
blue = val;
} else if (sector === 4) {
// Blue to magenta.
red = tint3;
green = tint1;
blue = val;
} else if (sector === 5) {
// Magenta to red.
red = val;
green = tint1;
blue = tint2;
} else {
// Red to yellow (sector could be 0 or 6).
red = val;
green = tint3;
blue = tint1;
}
RGBA = [red, green, blue, hsba[3]];
}
return RGBA;
},
/**
* Convert an HSLA array to HSBA.
*/
_hslaToHSBA(hsla) {
const hue = hsla[0];
let sat = hsla[1];
const li = hsla[2];
// Calculate brightness.
let val;
if (li < 0.5) {
val = (1 + sat) * li;
} else {
val = li + sat - li * sat;
}
// Convert saturation.
sat = 2 * (val - li) / val;
// Hue and alpha stay the same.
return [hue, sat, val, hsla[3]];
},
/**
* Convert an HSLA array to RGBA.
*
* We need to change basis from HSLA to something that can be more easily be
* projected onto RGBA. We will choose hue and brightness as our first two
* components, and pick a convenient third one ('zest') so that we don't need
* to calculate formal HSBA saturation.
*/
_hslaToRGBA(hsla) {
const hue = hsla[0] * 6; // We will split hue into 6 sectors.
const sat = hsla[1];
const li = hsla[2];
let RGBA = [];
if (sat === 0) {
RGBA = [li, li, li, hsla[3]]; // Return early if grayscale.
} else {
// Calculate brightness.
let val;
if (li < 0.5) {
val = (1 + sat) * li;
} else {
val = li + sat - li * sat;
}
// Define zest.
const zest = 2 * li - val;
// Implement projection (project onto green by default).
const hzvToRGB = (hue, zest, val) => {
if (hue < 0) {
// Hue must wrap to allow projection onto red and blue.
hue += 6;
} else if (hue >= 6) {
hue -= 6;
}
if (hue < 1) {
// Red to yellow (increasing green).
return zest + (val - zest) * hue;
} else if (hue < 3) {
// Yellow to cyan (greatest green).
return val;
} else if (hue < 4) {
// Cyan to blue (decreasing green).
return zest + (val - zest) * (4 - hue);
} else {
// Blue to red (least green).
return zest;
}
};
// Perform projections, offsetting hue as necessary.
RGBA = [
hzvToRGB(hue + 2, zest, val),
hzvToRGB(hue, zest, val),
hzvToRGB(hue - 2, zest, val),
hsla[3]
];
}
return RGBA;
},
/**
* Convert an RGBA array to HSBA.
*/
_rgbaToHSBA(rgba) {
const red = rgba[0];
const green = rgba[1];
const blue = rgba[2];
const val = Math.max(red, green, blue);
const chroma = val - Math.min(red, green, blue);
let hue, sat;
if (chroma === 0) {
// Return early if grayscale.
hue = 0;
sat = 0;
} else {
sat = chroma / val;
if (red === val) {
// Magenta to yellow.
hue = (green - blue) / chroma;
} else if (green === val) {
// Yellow to cyan.
hue = 2 + (blue - red) / chroma;
} else if (blue === val) {
// Cyan to magenta.
hue = 4 + (red - green) / chroma;
}
if (hue < 0) {
// Confine hue to the interval [0, 1).
hue += 6;
} else if (hue >= 6) {
hue -= 6;
}
}
return [hue / 6, sat, val, rgba[3]];
},
/**
* Convert an RGBA array to HSLA.
*/
_rgbaToHSLA(rgba) {
const red = rgba[0];
const green = rgba[1];
const blue = rgba[2];
const val = Math.max(red, green, blue);
const min = Math.min(red, green, blue);
const li = val + min; // We will halve this later.
const chroma = val - min;
let hue, sat;
if (chroma === 0) {
// Return early if grayscale.
hue = 0;
sat = 0;
} else {
if (li < 1) {
sat = chroma / li;
} else {
sat = chroma / (2 - li);
}
if (red === val) {
// Magenta to yellow.
hue = (green - blue) / chroma;
} else if (green === val) {
// Yellow to cyan.
hue = 2 + (blue - red) / chroma;
} else if (blue === val) {
// Cyan to magenta.
hue = 4 + (red - green) / chroma;
}
if (hue < 0) {
// Confine hue to the interval [0, 1).
hue += 6;
} else if (hue >= 6) {
hue -= 6;
}
}
return [hue / 6, sat, li / 2, rgba[3]];
}
};
export default p5.ColorConversion;