babl: fix some annotation to make the function usable in bindings.
[babl.git] / extensions / HCY.c
blob46d7a9907afc676eae74948b1160aba6b52c92ed
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)
24 #include "config.h"
26 #include <math.h>
27 #include <string.h>
29 #include "babl.h"
30 #include "base/util.h"
32 #define EPSILON 1e-10
34 static void rgba_to_hcya (const Babl *conversion,
35 char *src,
36 char *dst,
37 long samples);
39 static void hcya_to_rgba (const Babl *conversion,
40 char *src,
41 char *dst,
42 long samples);
44 static void rgba_to_hcy (const Babl *conversion,
45 char *src,
46 char *dst,
47 long samples);
49 static void hcy_to_rgba (const Babl *conversion,
50 char *src,
51 char *dst,
52 long samples);
54 static void
55 rgba_to_hcy_step (char *src,
56 char *dst,
57 const double weights[3]);
59 static void
60 hcy_to_rgba_step (char *src,
61 char *dst,
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);
69 int init (void);
71 int
72 init (void)
74 components ();
75 models ();
76 conversions ();
77 formats ();
79 return 0;
83 static void
84 components (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);
92 static void
93 models (void)
95 babl_model_new (
96 "name", "HCYA",
97 babl_component ("hue"),
98 babl_component ("HCY chroma"),
99 babl_component ("HCY luma"),
100 babl_component ("alpha"),
101 "alpha",
102 NULL
105 babl_model_new (
106 "name", "HCY",
107 babl_component ("hue"),
108 babl_component ("HCY chroma"),
109 babl_component ("HCY luma"),
110 NULL
114 static void
115 conversions (void)
117 babl_conversion_new (
118 babl_model ("RGBA"),
119 babl_model ("HCYA"),
120 "linear", rgba_to_hcya,
121 NULL
124 babl_conversion_new (
125 babl_model ("RGBA"),
126 babl_model ("HCY"),
127 "linear", rgba_to_hcy,
128 NULL
131 babl_conversion_new (
132 babl_model ("HCYA"),
133 babl_model ("RGBA"),
134 "linear", hcya_to_rgba,
135 NULL
138 babl_conversion_new (
139 babl_model ("HCY"),
140 babl_model ("RGBA"),
141 "linear", hcy_to_rgba,
142 NULL
146 static void
147 formats (void)
150 babl_format_new (
151 "name", "HCY float",
152 babl_model ("HCY"),
153 babl_type ("float"),
154 babl_component ("hue"),
155 babl_component ("HCY chroma"),
156 babl_component ("HCY luma"),
157 NULL
160 babl_format_new (
161 "name", "HCYA float",
162 babl_model ("HCYA"),
163 babl_type ("float"),
164 babl_component ("hue"),
165 babl_component ("HCY chroma"),
166 babl_component ("HCY luma"),
167 babl_component ("alpha"),
168 NULL
172 static void
173 rgba_to_hcy_step (char *src,
174 char *dst,
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])};
184 int ix[3] = {0,1,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; }
191 } else {
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.;
211 else
212 chroma = hue = 0.0;
214 ((double *) dst)[0] = hue;
215 ((double *) dst)[1] = chroma;
216 ((double *) dst)[2] = luma;
219 static void
220 hcy_to_rgba_step (char *src,
221 char *dst,
222 const double weights[3])
224 double red, green, blue;
225 double Y_peak = 0., H_insec, X, m;
226 int H_sec;
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;
234 } else {
235 hue = fmod (hue, 1.0);
236 hue += hue < 0.0;
237 hue *= 6.0;
239 H_sec = (int) hue;
241 switch (H_sec)
243 case 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;
250 break;
251 case 1:
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;
258 break;
259 case 2:
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;
266 break;
267 case 3:
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;
274 break;
275 case 4:
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;
282 break;
283 default:
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;
290 break;
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);
299 static void
300 rgba_to_hcya (const Babl *conversion,
301 char *src,
302 char *dst,
303 long samples)
305 const Babl *space = babl_conversion_get_source_space (conversion);
306 long n = samples;
307 double weights[3];
310 babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]);
312 while (n--)
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);
325 static void
326 hcya_to_rgba (const Babl *conversion,char *src,
327 char *dst,
328 long samples)
330 const Babl *space = babl_conversion_get_source_space (conversion);
331 long n = samples;
332 double weights[3];
334 space = babl_conversion_get_source_space (conversion);
335 babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]);
337 while (n--)
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);
350 static void
351 rgba_to_hcy (const Babl *conversion,
352 char *src,
353 char *dst,
354 long samples)
356 const Babl *space = babl_conversion_get_source_space (conversion);
357 long n = samples;
358 double weights[3];
360 space = babl_conversion_get_source_space (conversion);
361 babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]);
363 while (n--)
365 rgba_to_hcy_step (src, dst, weights);
367 src += 4 * sizeof (double);
368 dst += 3 * sizeof (double);
372 static void
373 hcy_to_rgba (const Babl *conversion,
374 char *src,
375 char *dst,
376 long samples)
378 const Babl *space = babl_conversion_get_source_space (conversion);
379 long n = samples;
380 double weights[3];
382 space = babl_conversion_get_source_space (conversion);
383 babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]);
385 while (n--)
387 hcy_to_rgba_step (src, dst, weights);
389 ((double *) dst)[3] = 1.0;
391 src += 3 * sizeof (double);
392 dst += 4 * sizeof (double);