1 /* babl - dynamically extendable universal pixel conversion library.
2 * Copyright (C) 2016, Sirio BolaƱos Puchet <vorstar@mac.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, see
16 * <https://www.gnu.org/licenses/>.
20 * Adding support for HCY colorspace, based on the reference implementation by
21 * Kuzma Shapran (https://code.google.com/archive/p/colour-space-viewer)
30 #include "base/util.h"
34 static void rgba_to_hcya (const Babl
*conversion
,
39 static void hcya_to_rgba (const Babl
*conversion
,
44 static void rgba_to_hcy (const Babl
*conversion
,
49 static void hcy_to_rgba (const Babl
*conversion
,
55 rgba_to_hcy_step (char *src
,
57 const double weights
[3]);
60 hcy_to_rgba_step (char *src
,
62 const double weights
[3]);
64 static void components (void);
65 static void models (void);
66 static void conversions (void);
67 static void formats (void);
86 babl_component_new ("hue", NULL
);
87 babl_component_new ("HCY chroma", "chroma", NULL
);
88 babl_component_new ("HCY luma", "luma", NULL
);
89 babl_component_new ("alpha", "alpha", NULL
);
97 babl_component ("hue"),
98 babl_component ("HCY chroma"),
99 babl_component ("HCY luma"),
100 babl_component ("alpha"),
107 babl_component ("hue"),
108 babl_component ("HCY chroma"),
109 babl_component ("HCY luma"),
117 babl_conversion_new (
120 "linear", rgba_to_hcya
,
124 babl_conversion_new (
127 "linear", rgba_to_hcy
,
131 babl_conversion_new (
134 "linear", hcya_to_rgba
,
138 babl_conversion_new (
141 "linear", hcy_to_rgba
,
154 babl_component ("hue"),
155 babl_component ("HCY chroma"),
156 babl_component ("HCY luma"),
161 "name", "HCYA float",
164 babl_component ("hue"),
165 babl_component ("HCY chroma"),
166 babl_component ("HCY luma"),
167 babl_component ("alpha"),
173 rgba_to_hcy_step (char *src
,
175 const double weights
[3])
177 double hue
, chroma
, luma
;
178 double X
, Y_peak
= 0.;
179 int H_sec
= 4, t
= -1;
181 double rgb
[3] = {linear_to_gamma_2_2 (((double *) src
)[0]),
182 linear_to_gamma_2_2 (((double *) src
)[1]),
183 linear_to_gamma_2_2 (((double *) src
)[2])};
186 if (rgb
[0] < rgb
[1]) {
187 if (rgb
[1] > rgb
[2]) {
188 if (rgb
[0] < rgb
[2]) { ix
[1] = 2; ix
[2] = 1; H_sec
= 2; t
= 1; }
189 else { ix
[0] = 2; ix
[1] = 0; ix
[2] = 1; H_sec
= 2; }
192 if (rgb
[1] < rgb
[2]) {
193 if (rgb
[0] < rgb
[2]) { ix
[0] = 1; ix
[1] = 0; H_sec
= 4; t
= 1; }
194 else { ix
[0] = 1; ix
[1] = 2; ix
[2] = 0; H_sec
= 6; }
195 } else { ix
[0] = 2; ix
[2] = 0; H_sec
= 0; t
= 1; }
198 luma
= weights
[0] * rgb
[0] + weights
[1] * rgb
[1] + weights
[2] * rgb
[2];
199 chroma
= rgb
[ix
[2]] - rgb
[ix
[0]];
201 if (chroma
>= EPSILON
)
203 X
= (rgb
[ix
[1]] - rgb
[ix
[0]]) / chroma
;
205 Y_peak
= weights
[ix
[2]] + X
* weights
[ix
[1]];
206 if (luma
!= 0. && luma
!= 1.)
207 chroma
/= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
209 hue
= (H_sec
+ t
* X
) / 6.;
214 ((double *) dst
)[0] = hue
;
215 ((double *) dst
)[1] = chroma
;
216 ((double *) dst
)[2] = luma
;
220 hcy_to_rgba_step (char *src
,
222 const double weights
[3])
224 double red
, green
, blue
;
225 double Y_peak
= 0., H_insec
, X
, m
;
228 double hue
= ((double *) src
)[0];
229 double chroma
= ((double *) src
)[1];
230 double luma
= ((double *) src
)[2];
232 if(chroma
< EPSILON
) {
233 red
= green
= blue
= luma
;
235 hue
= fmod (hue
, 1.0);
244 H_insec
= hue
- H_sec
;
245 Y_peak
= weights
[0] + H_insec
* weights
[1];
246 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
247 X
= chroma
* H_insec
;
248 m
= luma
- (weights
[0] * chroma
+ weights
[1] * X
);
249 red
= m
+ chroma
; green
= m
+ X
; blue
= m
;
252 H_insec
= 1. - (hue
- H_sec
);
253 Y_peak
= weights
[1] + H_insec
* weights
[0];
254 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
255 X
= chroma
* H_insec
;
256 m
= luma
- (weights
[0] * X
+ weights
[1] * chroma
);
257 red
= m
+ X
; green
= m
+ chroma
; blue
= m
;
260 H_insec
= hue
- H_sec
;
261 Y_peak
= weights
[1] + H_insec
* weights
[2];
262 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
263 X
= chroma
* H_insec
;
264 m
= luma
- (weights
[1] * chroma
+ weights
[2] * X
);
265 red
= m
; green
= m
+ chroma
; blue
= m
+ X
;
268 H_insec
= 1. - (hue
- H_sec
);
269 Y_peak
= weights
[2] + H_insec
* weights
[1];
270 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
271 X
= chroma
* H_insec
;
272 m
= luma
- (weights
[1] * X
+ weights
[2] * chroma
);
273 red
= m
; green
= m
+ X
; blue
= m
+ chroma
;
276 H_insec
= hue
- H_sec
;
277 Y_peak
= weights
[2] + H_insec
* weights
[0];
278 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
279 X
= chroma
* H_insec
;
280 m
= luma
- (weights
[0] * X
+ weights
[2] * chroma
);
281 red
= m
+ X
; green
= m
; blue
= m
+ chroma
;
284 H_insec
= 1. - (hue
- H_sec
);
285 Y_peak
= weights
[0] + H_insec
* weights
[2];
286 chroma
*= luma
< Y_peak
? luma
/Y_peak
: (1. - luma
)/(1. - Y_peak
);
287 X
= chroma
* H_insec
;
288 m
= luma
- (weights
[0] * chroma
+ weights
[2] * X
);
289 red
= m
+ chroma
; green
= m
; blue
= m
+ X
;
294 ((double *) dst
)[0] = gamma_2_2_to_linear (red
);
295 ((double *) dst
)[1] = gamma_2_2_to_linear (green
);
296 ((double *) dst
)[2] = gamma_2_2_to_linear (blue
);
300 rgba_to_hcya (const Babl
*conversion
,
305 const Babl
*space
= babl_conversion_get_source_space (conversion
);
310 babl_space_get_rgb_luminance (space
, &weights
[0], &weights
[1], &weights
[2]);
314 double alpha
= ((double *) src
)[3];
316 rgba_to_hcy_step (src
, dst
, weights
);
318 ((double *) dst
)[3] = alpha
;
320 src
+= 4 * sizeof (double);
321 dst
+= 4 * sizeof (double);
326 hcya_to_rgba (const Babl
*conversion
,char *src
,
330 const Babl
*space
= babl_conversion_get_source_space (conversion
);
334 space
= babl_conversion_get_source_space (conversion
);
335 babl_space_get_rgb_luminance (space
, &weights
[0], &weights
[1], &weights
[2]);
339 double alpha
= ((double *) src
)[3];
341 hcy_to_rgba_step (src
, dst
, weights
);
343 ((double *) dst
)[3] = alpha
;
345 src
+= 4 * sizeof (double);
346 dst
+= 4 * sizeof (double);
351 rgba_to_hcy (const Babl
*conversion
,
356 const Babl
*space
= babl_conversion_get_source_space (conversion
);
360 space
= babl_conversion_get_source_space (conversion
);
361 babl_space_get_rgb_luminance (space
, &weights
[0], &weights
[1], &weights
[2]);
365 rgba_to_hcy_step (src
, dst
, weights
);
367 src
+= 4 * sizeof (double);
368 dst
+= 3 * sizeof (double);
373 hcy_to_rgba (const Babl
*conversion
,
378 const Babl
*space
= babl_conversion_get_source_space (conversion
);
382 space
= babl_conversion_get_source_space (conversion
);
383 babl_space_get_rgb_luminance (space
, &weights
[0], &weights
[1], &weights
[2]);
387 hcy_to_rgba_step (src
, dst
, weights
);
389 ((double *) dst
)[3] = 1.0;
391 src
+= 3 * sizeof (double);
392 dst
+= 4 * sizeof (double);