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/>.
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
31 rgba_to_hsla (const Babl
*conversion
,
36 hsla_to_rgba (const Babl
*conversion
,
41 rgba_to_hsl (const Babl
*conversion
,
46 hsl_to_rgba (const Babl
*conversion
,
52 rgb_to_hsl_step (double *src
,
56 hsl_to_rgb_step (double *src
,
64 /* Defined through macros below */
67 rgb_nonlinear_to_hsl_step_double (double *src
,
70 hsl_to_rgb_nonlinear_step_double (double *src
,
74 rgb_nonlinear_to_hsl_step_float (float *src
,
77 hsl_to_rgb_nonlinear_step_float (float *src
,
80 /* Non-Linear RGB conversion: double variants */
83 rgba_nonlinear_to_hsla (const Babl
*conversion
,
88 hsla_to_rgba_nonlinear (const Babl
*conversion
,
93 /* Non-Linear RGB conversion: float variants */
96 rgba_nonlinear_to_hsla_float (const Babl
*conversion
,
101 hsla_to_rgba_nonlinear_float (const Babl
*conversion
,
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"),
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"),
133 babl_conversion_new (babl_model ("RGBA"),
135 "linear", rgba_to_hsla
,
137 babl_conversion_new (babl_model ("RGBA"),
139 "linear", rgba_to_hsl
,
141 babl_conversion_new (babl_model ("HSLA"),
143 "linear", hsla_to_rgba
,
145 babl_conversion_new (babl_model ("HSL"),
147 "linear", hsl_to_rgba
,
150 babl_conversion_new (babl_model ("R'G'B'A"),
152 "linear", rgba_nonlinear_to_hsla
,
155 babl_conversion_new (babl_model ("HSLA"),
156 babl_model ("R'G'B'A"),
157 "linear", hsla_to_rgba_nonlinear
,
160 babl_format_new ("name", "HSLA float",
163 babl_component ("hue"),
164 babl_component ("saturation"),
165 babl_component ("lightness"),
166 babl_component ("alpha"),
168 babl_format_new ("name", "HSL float",
171 babl_component ("hue"),
172 babl_component ("saturation"),
173 babl_component ("lightness"),
176 babl_conversion_new (babl_format ("R'G'B'A float"),
177 babl_format ("HSLA float"),
178 "linear", rgba_nonlinear_to_hsla_float
,
180 babl_conversion_new (babl_format ("HSLA float"),
181 babl_format ("R'G'B'A float"),
182 "linear", hsla_to_rgba_nonlinear_float
,
188 #define DEFINE_RGB_NL_TO_HSL_STEP(ctype) \
190 rgb_nonlinear_to_hsl_step_##ctype (ctype* src, \
194 ctype hue, saturation, lightness; \
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) \
206 else if (max - green < EPSILON) \
211 lightness = (max + min) / 2.0; \
213 if (max - min < EPSILON) \
215 hue = saturation = 0; \
219 ctype diff = max - min; \
220 ctype sum = max + min; \
221 saturation = lightness > 0.5 ? diff / (2.0 - sum) : diff / sum; \
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; \
234 dst[1] = saturation; \
235 dst[2] = lightness; \
238 DEFINE_RGB_NL_TO_HSL_STEP(double)
239 DEFINE_RGB_NL_TO_HSL_STEP(float)
242 rgb_to_hsl_step (double* src
,
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
);
256 rgba_to_hsla (const Babl
*conversion
,
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);
278 rgba_to_hsl (const Babl
*conversion
,
287 rgb_to_hsl_step ((double *) src
, (double *) dst
);
289 src
+= 4 * sizeof (double);
290 dst
+= 3 * sizeof (double);
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;
309 #define DEFINE_HSL_TO_RBG_NONLINEAR_STEP(ctype) \
311 hsl_to_rgb_nonlinear_step_##ctype (ctype *src, \
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; \
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); \
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)
343 hsl_to_rgb_step (double *src
,
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]);
355 hsla_to_rgba (const Babl
*conversion
,
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);
377 hsl_to_rgba (const Babl
*conversion
,
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);
396 rgba_nonlinear_to_hsla (const Babl
*conversion
,
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);
417 hsla_to_rgba_nonlinear (const Babl
*conversion
,
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 **/
440 rgba_nonlinear_to_hsla_float (const Babl
*conversion
,
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);
461 hsla_to_rgba_nonlinear_float (const Babl
*conversion
,
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);