babl: fix some annotation to make the function usable in bindings.
[babl.git] / extensions / HSL.c
blobcdd410ea0d9cc24f6e8ad7c396a74a3e3706cc57
1 /* babl - dynamically extendable universal pixel conversion library.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General
14 * Public License along with this library; if not, see
15 * <https://www.gnu.org/licenses/>.
18 #include "config.h"
20 #include <math.h>
21 #include <string.h>
23 #include "babl.h"
24 #include "base/util.h"
26 #define MIN(a,b) ((a > b) ? b : a)
27 #define MAX(a,b) ((a < b) ? b : a)
28 #define EPSILON 1.0e-10
30 static void
31 rgba_to_hsla (const Babl *conversion,
32 char *src,
33 char *dst,
34 long samples);
35 static void
36 hsla_to_rgba (const Babl *conversion,
37 char *src,
38 char *dst,
39 long samples);
40 static void
41 rgba_to_hsl (const Babl *conversion,
42 char *src,
43 char *dst,
44 long samples);
45 static void
46 hsl_to_rgba (const Babl *conversion,
47 char *src,
48 char *dst,
49 long samples);
51 static void
52 rgb_to_hsl_step (double *src,
53 double *dst);
55 static void
56 hsl_to_rgb_step (double *src,
57 double *dst);
59 static inline double
60 hue2cpn (double p,
61 double q,
62 double hue);
64 /* Defined through macros below */
66 static inline void
67 rgb_nonlinear_to_hsl_step_double (double *src,
68 double *dst);
69 static inline void
70 hsl_to_rgb_nonlinear_step_double (double *src,
71 double *dst);
73 static inline void
74 rgb_nonlinear_to_hsl_step_float (float *src,
75 float *dst);
76 static inline void
77 hsl_to_rgb_nonlinear_step_float (float *src,
78 float *dst);
80 /* Non-Linear RGB conversion: double variants */
82 static void
83 rgba_nonlinear_to_hsla (const Babl *conversion,
84 char *src,
85 char *dst,
86 long samples);
87 static void
88 hsla_to_rgba_nonlinear (const Babl *conversion,
89 char *src,
90 char *dst,
91 long samples);
93 /* Non-Linear RGB conversion: float variants */
95 static void
96 rgba_nonlinear_to_hsla_float (const Babl *conversion,
97 char *src,
98 char *dst,
99 long samples);
100 static void
101 hsla_to_rgba_nonlinear_float (const Babl *conversion,
102 char *src,
103 char *dst,
104 long samples);
107 int init (void);
110 init (void)
112 babl_component_new ("hue", NULL);
113 babl_component_new ("saturation", NULL);
114 babl_component_new ("lightness", NULL);
115 babl_component_new ("alpha", "alpha", NULL);
117 babl_model_new ("name", "HSL",
118 "doc", "HSL - Hue Saturation Lightness, an improvement over HSV; which uses lightness; defined as (MAX(R,G,B) + MIN(R,G,B))/2 for the grayscale axis; better than HSV, but look into the CIE based spaces for better perceptual uniformity. The HSL space is relative to the RGB space associated with the format.",
119 babl_component ("hue"),
120 babl_component ("saturation"),
121 babl_component ("lightness"),
122 NULL);
123 babl_model_new ("name", "HSLA",
124 "doc", "HSL - with separate alpha component.",
125 babl_component ("hue"),
126 babl_component ("saturation"),
127 babl_component ("lightness"),
128 babl_component ("alpha"),
129 "alpha",
130 NULL);
133 babl_conversion_new (babl_model ("RGBA"),
134 babl_model ("HSLA"),
135 "linear", rgba_to_hsla,
136 NULL);
137 babl_conversion_new (babl_model ("RGBA"),
138 babl_model ("HSL"),
139 "linear", rgba_to_hsl,
140 NULL);
141 babl_conversion_new (babl_model ("HSLA"),
142 babl_model ("RGBA"),
143 "linear", hsla_to_rgba,
144 NULL);
145 babl_conversion_new (babl_model ("HSL"),
146 babl_model ("RGBA"),
147 "linear", hsl_to_rgba,
148 NULL);
150 babl_conversion_new (babl_model ("R'G'B'A"),
151 babl_model ("HSLA"),
152 "linear", rgba_nonlinear_to_hsla,
153 NULL);
155 babl_conversion_new (babl_model ("HSLA"),
156 babl_model ("R'G'B'A"),
157 "linear", hsla_to_rgba_nonlinear,
158 NULL);
160 babl_format_new ("name", "HSLA float",
161 babl_model ("HSLA"),
162 babl_type ("float"),
163 babl_component ("hue"),
164 babl_component ("saturation"),
165 babl_component ("lightness"),
166 babl_component ("alpha"),
167 NULL);
168 babl_format_new ("name", "HSL float",
169 babl_model ("HSL"),
170 babl_type ("float"),
171 babl_component ("hue"),
172 babl_component ("saturation"),
173 babl_component ("lightness"),
174 NULL);
176 babl_conversion_new (babl_format ("R'G'B'A float"),
177 babl_format ("HSLA float"),
178 "linear", rgba_nonlinear_to_hsla_float,
179 NULL);
180 babl_conversion_new (babl_format ("HSLA float"),
181 babl_format ("R'G'B'A float"),
182 "linear", hsla_to_rgba_nonlinear_float,
183 NULL);
185 return 0;
188 #define DEFINE_RGB_NL_TO_HSL_STEP(ctype) \
189 static inline void \
190 rgb_nonlinear_to_hsl_step_##ctype (ctype* src, \
191 ctype* dst) \
193 ctype min, max; \
194 ctype hue, saturation, lightness; \
195 int cpn_max; \
197 ctype red = src[0]; \
198 ctype green = src[1]; \
199 ctype blue = src[2]; \
201 max = MAX (red, MAX (green, blue)); \
202 min = MIN (red, MIN (green, blue)); \
204 if (max - red < EPSILON) \
205 cpn_max = 0; \
206 else if (max - green < EPSILON) \
207 cpn_max = 1; \
208 else \
209 cpn_max = 2; \
211 lightness = (max + min) / 2.0; \
213 if (max - min < EPSILON) \
215 hue = saturation = 0; \
217 else \
219 ctype diff = max - min; \
220 ctype sum = max + min; \
221 saturation = lightness > 0.5 ? diff / (2.0 - sum) : diff / sum; \
222 switch (cpn_max) \
224 case 0: hue = (green - blue) / diff + (green < blue ? 6.0 : 0.0); break; \
225 case 1: hue = (blue - red) / diff + 2.0; break; \
226 case 2: hue = (red - green) / diff + 4.0; break; \
227 default: hue = 0.0; \
228 break; \
230 hue /= 6.0; \
233 dst[0] = hue; \
234 dst[1] = saturation; \
235 dst[2] = lightness; \
238 DEFINE_RGB_NL_TO_HSL_STEP(double)
239 DEFINE_RGB_NL_TO_HSL_STEP(float)
241 static inline void
242 rgb_to_hsl_step (double* src,
243 double* dst)
245 double nonlinear_rgb[3];
247 nonlinear_rgb[0] = linear_to_gamma_2_2 (src[0]);
248 nonlinear_rgb[1] = linear_to_gamma_2_2 (src[1]);
249 nonlinear_rgb[2] = linear_to_gamma_2_2 (src[2]);
251 rgb_nonlinear_to_hsl_step_double (nonlinear_rgb, dst);
255 static void
256 rgba_to_hsla (const Babl *conversion,
257 char *src,
258 char *dst,
259 long samples)
261 long n = samples;
263 while (n--)
265 double alpha = ((double *) src)[3];
267 rgb_to_hsl_step ((double *) src, (double *) dst);
269 ((double *) dst)[3] = alpha;
271 src += 4 * sizeof (double);
272 dst += 4 * sizeof (double);
277 static void
278 rgba_to_hsl (const Babl *conversion,
279 char *src,
280 char *dst,
281 long samples)
283 long n = samples;
285 while (n--)
287 rgb_to_hsl_step ((double *) src, (double *) dst);
289 src += 4 * sizeof (double);
290 dst += 3 * sizeof (double);
295 static inline double
296 hue2cpn (double p,
297 double q,
298 double hue)
300 if (hue < 0.0) hue += 1.0;
301 if (hue > 1.0) hue -= 1.0;
302 if (hue < 1.0 / 6.0) return p + (q - p) * 6.0 * hue;
303 if (hue < 1.0 / 2.0) return q;
304 if (hue < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - hue) * 6.0;
305 return p;
309 #define DEFINE_HSL_TO_RBG_NONLINEAR_STEP(ctype) \
310 static inline void \
311 hsl_to_rgb_nonlinear_step_##ctype (ctype *src, \
312 ctype *dst) \
314 ctype hue = src[0]; \
315 ctype saturation = src[1]; \
316 ctype lightness = src[2]; \
318 if (saturation < 1e-7) \
320 dst[0] = dst[1] = dst[2] = lightness; \
322 else \
324 ctype q = lightness < 0.5 ? \
325 lightness * (1 + saturation) : \
326 lightness + saturation - lightness * saturation; \
328 ctype p = 2 * lightness - q; \
330 hue = fmod (hue, 1.0); \
331 hue += hue < 0.0; \
333 dst[0] = hue2cpn (p, q, hue + 1.0/3.0); \
334 dst[1] = hue2cpn (p, q, hue); \
335 dst[2] = hue2cpn (p, q, hue - 1.0/3.0); \
339 DEFINE_HSL_TO_RBG_NONLINEAR_STEP(double)
340 DEFINE_HSL_TO_RBG_NONLINEAR_STEP(float)
342 static void
343 hsl_to_rgb_step (double *src,
344 double *dst)
346 hsl_to_rgb_nonlinear_step_double (src, dst);
348 dst[0] = gamma_2_2_to_linear (dst[0]);
349 dst[1] = gamma_2_2_to_linear (dst[1]);
350 dst[2] = gamma_2_2_to_linear (dst[2]);
354 static void
355 hsla_to_rgba (const Babl *conversion,
356 char *src,
357 char *dst,
358 long samples)
360 long n = samples;
362 while (n--)
364 double alpha = ((double *) src)[3];
366 hsl_to_rgb_step ((double *) src, (double *) dst);
368 ((double *) dst)[3] = alpha;
370 src += 4 * sizeof (double);
371 dst += 4 * sizeof (double);
376 static void
377 hsl_to_rgba (const Babl *conversion,
378 char *src,
379 char *dst,
380 long samples)
382 long n = samples;
384 while (n--)
386 hsl_to_rgb_step ((double *) src, (double *) dst);
388 ((double *) dst)[3] = 1.0;
390 src += 3 * sizeof (double);
391 dst += 4 * sizeof (double);
395 static void
396 rgba_nonlinear_to_hsla (const Babl *conversion,
397 char *src,
398 char *dst,
399 long samples)
401 long n = samples;
403 while (n--)
405 double alpha = ((double *) src)[3];
407 rgb_nonlinear_to_hsl_step_double ((double *) src, (double *) dst);
409 ((double *) dst)[3] = alpha;
411 src += 4 * sizeof (double);
412 dst += 4 * sizeof (double);
416 static void
417 hsla_to_rgba_nonlinear (const Babl *conversion,
418 char *src,
419 char *dst,
420 long samples)
422 long n = samples;
424 while (n--)
426 double alpha = ((double *) src)[3];
428 hsl_to_rgb_nonlinear_step_double ((double *) src, (double *) dst);
430 ((double *) dst)[3] = alpha;
432 src += 4 * sizeof (double);
433 dst += 4 * sizeof (double);
437 /** Float variants **/
439 static void
440 rgba_nonlinear_to_hsla_float (const Babl *conversion,
441 char *src,
442 char *dst,
443 long samples)
445 long n = samples;
447 while (n--)
449 float alpha = ((float *) src)[3];
451 rgb_nonlinear_to_hsl_step_float ((float *) src, (float *) dst);
453 ((float *) dst)[3] = alpha;
455 src += 4 * sizeof (float);
456 dst += 4 * sizeof (float);
460 static void
461 hsla_to_rgba_nonlinear_float (const Babl *conversion,
462 char *src,
463 char *dst,
464 long samples)
466 long n = samples;
468 while (n--)
470 float alpha = ((float *) src)[3];
472 hsl_to_rgb_nonlinear_step_float ((float *) src, (float *) dst);
474 ((float *) dst)[3] = alpha;
476 src += 4 * sizeof (float);
477 dst += 4 * sizeof (float);