babl: fix some annotation to make the function usable in bindings.
[babl.git] / extensions / oklab.c
blob4add977b502901150f82753103f8abcd6eff1f36
1 /* babl - dynamically extendable universal pixel conversion library.
2 * Copyright (C) 2005, 2014, 2019 Øyvind Kolås.
3 * Copyright (C) 2014, 2019 Elle Stone
4 * Copyright (C) 2009, Martin Nordholts
5 * Copyright (C) 2021, Mingye Wang <arthur2e5@aosc.io>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see
19 * <https://www.gnu.org/licenses/>.
23 * Björn Ottosson (2020). Oklab, a perceptual color space for image
24 * processing. https://bottosson.github.io/posts/oklab/
27 #include "config.h"
29 #include <math.h>
30 #include <string.h>
32 #include "babl-internal.h"
33 #include "babl-matrix.h"
34 #include "babl.h"
35 #include "base/util.h"
37 #define DEGREES_PER_RADIAN (180 / 3.14159265358979323846)
38 #define RADIANS_PER_DEGREE (1 / DEGREES_PER_RADIAN)
40 static void components (void);
41 static void models (void);
42 static void conversions (void);
43 static void formats (void);
45 int init (void);
47 static int enable_lch = 0;
48 // the Oklch conversions are not fully symmetric,
49 // thus not allowing the tests to pass if we register
50 // the code
52 int
53 init (void)
55 components ();
56 models ();
57 formats ();
58 conversions ();
59 return 0;
62 static void
63 components (void)
65 babl_component_new ("Ok L", "doc", "Luminance, range 0.0-100.0 in float",
66 NULL);
67 babl_component_new ("Ok a", "chroma", "doc",
68 "chroma component 0.0 is no saturation", NULL);
69 babl_component_new ("Ok b", "chroma", "doc",
70 "chroma component 0.0 is no saturation", NULL);
71 babl_component_new ("Ok C", "chroma", "doc", "chrominance/saturation", NULL);
72 babl_component_new ("Ok H", "chroma", "doc", "hue value range 0.0-360.0",
73 NULL);
76 static void
77 models (void)
79 babl_model_new ("name", "Oklab", "doc",
80 "Oklab color model, a perceptually uniform space.",
81 babl_component ("Ok L"), babl_component ("Ok a"),
82 babl_component ("Ok b"), NULL);
84 babl_model_new (
85 "name", "OklabA", "doc", "Oklab color model with separate alpha.",
86 babl_component ("Ok L"), babl_component ("Ok a"),
87 babl_component ("Ok b"), babl_component ("A"), "alpha", NULL);
89 if (enable_lch)
91 babl_model_new ("name", "Oklch", "doc",
92 "Cylindrical representation of Oklab.",
93 babl_component ("Ok L"), babl_component ("Ok C"),
94 babl_component ("Ok H"), NULL);
96 babl_model_new (
97 "name", "OklchA", "doc", "Oklch color model with separate alpha.",
98 babl_component ("Ok L"), babl_component ("Ok C"),
99 babl_component ("Ok H"), babl_component ("A"), "alpha", NULL);
103 static void
104 formats (void)
106 babl_format_new (
107 "name", "Oklab float",
108 babl_model ("Oklab"),
109 babl_type ("float"),
110 babl_component ("Ok L"),
111 babl_component ("Ok a"),
112 babl_component ("Ok b"),
113 NULL
117 babl_format_new (
118 "name", "Oklab alpha float",
119 babl_model ("OklabA"),
120 babl_type ("float"),
121 babl_component ("Ok L"),
122 babl_component ("Ok a"),
123 babl_component ("Ok b"),
124 babl_component ("A"),
125 NULL
128 if (enable_lch)
130 babl_format_new (
131 "name", "Oklch float",
132 babl_model ("Oklch"),
133 babl_type ("float"),
134 babl_component ("Ok L"),
135 babl_component ("Ok C"),
136 babl_component ("Ok H"),
137 NULL
140 babl_format_new (
141 "name", "Oklch alpha float",
142 babl_model ("OklchA"),
143 babl_type ("float"),
144 babl_component ("Ok L"),
145 babl_component ("Ok C"),
146 babl_component ("Ok H"),
147 babl_component ("A"),
148 NULL
153 /* Convertion routine (space definition). */
154 /* It's all float. The original definition is in float. */
155 static double M1[9] = {
156 +0.8189330101, +0.0329845436, +0.0482003018,
157 +0.3618667424, +0.9293118715, +0.2643662691,
158 -0.1288597137, +0.0361456387, +0.6338517070,
161 static double M2[9] = {
162 +0.2104542553, +0.7936177850, - 0.0040720468,
163 +1.9779984951, -2.4285922050, + 0.4505937099,
164 +0.0259040371, +0.7827717662, - 0.8086757660,
167 static float M1f[9];
168 static float M2f[9];
169 static float inv_M1f[9];
170 static float inv_M2f[9];
172 static double inv_M1[9];
173 static double inv_M2[9];
174 static int mat_ready;
176 /* fast approximate cube root
177 * origin: http://www.hackersdelight.org/hdcodetxt/acbrt.c.txt
178 * permissions: http://www.hackersdelight.org/permissions.htm
180 static inline float
181 _cbrtf (float x)
183 union
185 float f;
186 uint32_t i;
187 } u = { x };
189 u.i = u.i / 4 + u.i / 16;
190 u.i = u.i + u.i / 16;
191 u.i = u.i + u.i / 256;
192 u.i = 0x2a5137a0 + u.i;
193 u.f = 0.33333333f * (2.0f * u.f + x / (u.f * u.f));
194 u.f = 0.33333333f * (2.0f * u.f + x / (u.f * u.f));
196 return u.f;
199 static inline void
200 XYZ_to_Oklab_step (double *xyz, double *lab_out)
202 double lms[3];
203 babl_matrix_mul_vector (M1, xyz, lms);
204 for (int i = 0; i < 3; i++)
206 lms[i] = cbrt (lms[i]);
208 babl_matrix_mul_vector (M2, lms, lab_out);
211 static inline void
212 XYZ_to_Oklab_stepf (float *xyz, float *lab_out)
214 float lms[3];
215 babl_matrix_mul_vectorff (M1f, xyz, lms);
216 for (int i = 0; i < 3; i++)
218 lms[i] = _cbrtf (lms[i]);
220 babl_matrix_mul_vectorff (M2f, lms, lab_out);
223 static inline void
224 Oklab_to_XYZ_stepf (float *lab, float *xyz_out)
226 float lms[3];
227 babl_matrix_mul_vectorff (inv_M2f, lab, lms);
228 for (int i = 0; i < 3; i++)
230 lms[i] = lms[i] * lms[i] * lms[i];
232 babl_matrix_mul_vectorff (inv_M1f, lms, xyz_out);
235 static inline void
236 Oklab_to_XYZ_step (double *lab, double *xyz_out)
238 double lms[3];
239 babl_matrix_mul_vector (inv_M2, lab, lms);
240 for (int i = 0; i < 3; i++)
242 lms[i] = lms[i] * lms[i] * lms[i];
244 babl_matrix_mul_vector (inv_M1, lms, xyz_out);
247 static inline void
248 ab_to_ch_step (double *ab, double *ch_out)
250 double a = ab[0], b = ab[1];
252 ch_out[1] = sqrt (a * a + b * b);
253 ch_out[2] = atan2 (b, a) * DEGREES_PER_RADIAN;
255 // Keep H within the range 0-360
256 if (ch_out[2] < 0.0)
257 ch_out[2] += 360;
260 static inline void
261 ab_to_ch_stepf (float *ab, float *ch_out)
263 float a = ab[0], b = ab[1];
265 ch_out[1] = sqrtf (a * a + b * b);
266 ch_out[2] = atan2f (b, a) * DEGREES_PER_RADIAN;
268 // Keep H within the range 0-360
269 if (ch_out[2] < 0.0)
270 ch_out[2] += 360;
273 static inline void
274 ch_to_ab_step (double *ch, double *ab_out)
276 double c = ch[0], h = ch[1];
278 ab_out[0] = cos (h * RADIANS_PER_DEGREE) * c;
279 ab_out[1] = sin (h * RADIANS_PER_DEGREE) * c;
282 static inline void
283 ch_to_ab_stepf (float *ch, float *ab_out)
285 float c = ch[0], h = ch[1];
287 ab_out[0] = cosf (h * RADIANS_PER_DEGREE) * c;
288 ab_out[1] = sinf (h * RADIANS_PER_DEGREE) * c;
291 static inline void
292 XYZ_to_Oklch_step (double *xyz, double *lch_out)
294 XYZ_to_Oklab_step (xyz, lch_out);
295 ab_to_ch_step (lch_out + 1, lch_out + 1);
298 static inline void
299 XYZ_to_Oklch_stepf (float *xyz, float *lch_out)
301 XYZ_to_Oklab_stepf (xyz, lch_out);
302 ab_to_ch_stepf (lch_out + 1, lch_out + 1);
305 static inline void
306 Oklch_to_XYZ_step (double *lch, double *xyz_out)
308 double lab[3] = { lch[0], lch[1], lch[2] };
309 ch_to_ab_step (lab + 1, lab + 1);
310 Oklab_to_XYZ_step (lab, xyz_out);
313 static inline void
314 Oklch_to_XYZ_stepf (float *lch, float *xyz_out)
316 float lab[3] = { lch[0], lch[1], lch[2] };
317 ch_to_ab_stepf (lab + 1, lab + 1);
318 Oklab_to_XYZ_stepf (lab, xyz_out);
321 static inline void
322 constants (void)
324 double tmp[9];
325 double D65[3] = { 0.95047, 1.0, 1.08883 };
326 double D50[3] = { 0.96420288, 1.0, 0.82490540 };
328 if (mat_ready)
329 return;
331 babl_chromatic_adaptation_matrix (D50, D65, tmp);
332 babl_matrix_mul_matrix (tmp, M1, M1);
334 babl_matrix_invert (M1, inv_M1);
335 babl_matrix_invert (M2, inv_M2);
337 babl_matrix_to_float (M1, M1f);
338 babl_matrix_to_float (M2, M2f);
339 babl_matrix_to_float (inv_M1, inv_M1f);
340 babl_matrix_to_float (inv_M2, inv_M2f);
342 mat_ready = 1;
345 /* Convertion routine (glue and boilerplate). */
346 static void
347 rgba_to_laba_float (const Babl *conversion, char *src_, char *dst_, long samples)
349 long n = samples;
350 float *src = (float *)src_, *dst = (float *)dst_;
351 const Babl *space = babl_conversion_get_source_space (conversion);
353 while (n--)
355 float xyz[3];
356 babl_space_to_xyzf (space, src, xyz);
357 XYZ_to_Oklab_stepf (xyz, dst);
358 dst[3] = src[3];
360 src += 4;
361 dst += 4;
365 static void
366 rgba_to_laba (const Babl *conversion, char *src_, char *dst_, long samples)
368 long n = samples;
369 double *src = (double*)src_, *dst = (double*)dst_;
370 const Babl *space = babl_conversion_get_source_space (conversion);
372 while (n--)
374 double xyz[3];
375 babl_space_to_xyz (space, src, xyz);
376 XYZ_to_Oklab_step (xyz, dst);
377 dst[3] = src[3];
379 src += 4;
380 dst += 4;
384 static void
385 rgba_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)
387 long n = samples;
388 float *src = (float *)src_, *dst = (float *)dst_;
389 const Babl *space = babl_conversion_get_source_space (conversion);
391 while (n--)
393 float xyz[3];
394 babl_space_to_xyzf (space, src, xyz);
395 XYZ_to_Oklab_stepf (xyz, dst);
397 src += 4;
398 dst += 3;
402 static void
403 rgba_to_lab (const Babl *conversion, char *src_, char *dst_, long samples)
405 long n = samples;
406 double *src = (double *)src_, *dst = (double *)dst_;
407 const Babl *space = babl_conversion_get_source_space (conversion);
409 while (n--)
411 double xyz[3];
412 babl_space_to_xyz (space, src, xyz);
413 XYZ_to_Oklab_step (xyz, dst);
415 src += 4;
416 dst += 3;
420 static void
421 rgba_to_lcha_float (const Babl *conversion, char *src_, char *dst_, long samples)
423 long n = samples;
424 float *src = (float *)src_, *dst = (float *)dst_;
425 const Babl *space = babl_conversion_get_source_space (conversion);
427 while (n--)
429 float xyz[3];
430 babl_space_to_xyzf (space, src, xyz);
431 XYZ_to_Oklch_stepf (xyz, dst);
432 dst[3] = src[3];
434 src += 4;
435 dst += 4;
439 static void
440 rgba_to_lcha (const Babl *conversion, char *src_, char *dst_, long samples)
442 long n = samples;
443 double *src = (double *)src_, *dst = (double *)dst_;
444 const Babl *space = babl_conversion_get_source_space (conversion);
446 while (n--)
448 double xyz[3];
449 babl_space_to_xyz (space, src, xyz);
450 XYZ_to_Oklch_step (xyz, dst);
451 dst[3] = src[3];
453 src += 4;
454 dst += 4;
458 static void
459 rgba_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)
461 long n = samples;
462 float *src = (float *)src_, *dst = (float *)dst_;
463 const Babl *space = babl_conversion_get_source_space (conversion);
465 while (n--)
467 float xyz[3];
468 babl_space_to_xyzf (space, src, xyz);
469 XYZ_to_Oklch_stepf (xyz, dst);
471 src += 4;
472 dst += 3;
476 static void
477 rgba_to_lch (const Babl *conversion, char *src_, char *dst_, long samples)
479 long n = samples;
480 double *src = (double *)src_, *dst = (double *)dst_;
481 const Babl *space = babl_conversion_get_source_space (conversion);
483 while (n--)
485 double xyz[3];
486 babl_space_to_xyz (space, src, xyz);
487 XYZ_to_Oklch_step (xyz, dst);
489 src += 4;
490 dst += 3;
494 static void
495 rgb_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)
497 long n = samples;
498 float *src = (float *)src_, *dst = (float *)dst_;
499 const Babl *space = babl_conversion_get_source_space (conversion);
501 while (n--)
503 float xyz[3];
504 babl_space_to_xyzf (space, src, xyz);
505 XYZ_to_Oklab_stepf (xyz, dst);
507 src += 3;
508 dst += 3;
512 static void
513 rgb_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)
515 long n = samples;
516 float *src = (float *)src_, *dst = (float *)dst_;
517 const Babl *space = babl_conversion_get_source_space (conversion);
519 while (n--)
521 float xyz[3];
522 babl_space_to_xyzf (space, src, xyz);
523 XYZ_to_Oklch_stepf (xyz, dst);
525 src += 3;
526 dst += 3;
530 static void
531 lab_to_rgb_float (const Babl *conversion, char *src_, char *dst_, long samples)
533 long n = samples;
534 float *src = (float *)src_, *dst = (float *)dst_;
535 const Babl *space = babl_conversion_get_destination_space (conversion);
537 while (n--)
539 float xyz[3];
540 Oklab_to_XYZ_stepf (src, xyz);
541 babl_space_from_xyzf (space, xyz, dst);
543 src += 3;
544 dst += 3;
548 static void
549 lab_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)
551 long n = samples;
552 float *src = (float *)src_, *dst = (float *)dst_;
553 const Babl *space = babl_conversion_get_destination_space (conversion);
555 while (n--)
557 float xyz[3];
558 Oklab_to_XYZ_stepf (src, xyz);
559 babl_space_from_xyzf (space, xyz, dst);
560 dst[3] = 1.0;
562 src += 3;
563 dst += 4;
567 static void
568 lab_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)
570 long n = samples;
571 double *src = (double *)src_, *dst = (double *)dst_;
572 const Babl *space = babl_conversion_get_destination_space (conversion);
574 while (n--)
576 double xyz[3];
577 Oklab_to_XYZ_step (src, xyz);
578 babl_space_from_xyz (space, xyz, dst);
579 dst[3] = 1.0;
581 src += 3;
582 dst += 4;
586 static void
587 lch_to_rgb_float (const Babl *conversion, char *src_, char *dst_, long samples)
589 long n = samples;
590 float *src = (float *)src_, *dst = (float *)dst_;
591 const Babl *space = babl_conversion_get_destination_space (conversion);
593 while (n--)
595 float xyz[3];
596 Oklch_to_XYZ_stepf (src, xyz);
597 babl_space_from_xyzf (space, xyz, dst);
599 src += 3;
600 dst += 3;
604 static void
605 laba_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)
607 long n = samples;
608 float *src = (float *)src_, *dst = (float *)dst_;
609 const Babl *space = babl_conversion_get_destination_space (conversion);
611 while (n--)
613 float xyz[3];
614 Oklab_to_XYZ_stepf (src, xyz);
615 babl_space_from_xyzf (space, xyz, dst);
616 dst[3] = src[3];
618 src += 4;
619 dst += 4;
623 static void
624 laba_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)
626 long n = samples;
627 double *src = (double *)src_, *dst = (double *)dst_;
628 const Babl *space = babl_conversion_get_destination_space (conversion);
630 while (n--)
632 double xyz[3];
633 Oklab_to_XYZ_step (src, xyz);
634 babl_space_from_xyz (space, xyz, dst);
635 dst[3] = src[3];
637 src += 4;
638 dst += 4;
642 static void
643 lcha_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)
645 long n = samples;
646 float *src = (float *)src_, *dst = (float *)dst_;
647 const Babl *space = babl_conversion_get_destination_space (conversion);
649 while (n--)
651 float xyz[3];
652 Oklch_to_XYZ_stepf (src, xyz);
653 babl_space_from_xyzf (space, xyz, dst);
654 dst[3] = src[3];
656 src += 4;
657 dst += 4;
661 static void
662 lcha_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)
664 long n = samples;
665 double *src = (double *)src_, *dst = (double *)dst_;
666 const Babl *space = babl_conversion_get_destination_space (conversion);
668 while (n--)
670 double xyz[3];
671 Oklch_to_XYZ_step (src, xyz);
672 babl_space_from_xyz (space, xyz, dst);
673 dst[3] = src[3];
675 src += 4;
676 dst += 4;
681 static void
682 lch_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)
684 long n = samples;
685 float *src = (float *)src_, *dst = (float *)dst_;
686 const Babl *space = babl_conversion_get_destination_space (conversion);
688 while (n--)
690 float xyz[3];
691 Oklch_to_XYZ_stepf (src, xyz);
692 babl_space_from_xyzf (space, xyz, dst);
693 dst[3] = 1.0f;
695 src += 3;
696 dst += 4;
700 static void
701 lch_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)
703 long n = samples;
704 double *src = (double *)src_, *dst = (double *)dst_;
705 const Babl *space = babl_conversion_get_destination_space (conversion);
707 while (n--)
709 double xyz[3];
710 Oklch_to_XYZ_step (src, xyz);
711 babl_space_from_xyz (space, xyz, dst);
712 dst[3] = 1.0f;
714 src += 3;
715 dst += 4;
720 static void
721 lch_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)
723 long n = samples;
724 float *src = (float *)src_, *dst = (float *)dst_;
726 while (n--)
728 dst[0] = src[0];
729 ch_to_ab_stepf (src + 1, dst + 1);
731 src += 3;
732 dst += 3;
736 static void
737 lab_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)
739 long n = samples;
740 float *src = (float *)src_, *dst = (float *)dst_;
742 while (n--)
744 dst[0] = src[0];
745 ab_to_ch_stepf (src + 1, dst + 1);
747 src += 3;
748 dst += 3;
752 static void
753 lcha_to_laba_float (const Babl *conversion, char *src_, char *dst_, long samples)
755 long n = samples;
756 float *src = (float *)src_, *dst = (float *)dst_;
758 while (n--)
760 dst[0] = src[0];
761 ch_to_ab_stepf (src + 1, dst + 1);
762 dst[3] = src[3];
764 src += 4;
765 dst += 4;
769 static void
770 laba_to_lcha_float (const Babl *conversion, char *src_, char *dst_, long samples)
772 long n = samples;
773 float *src = (float *)src_, *dst = (float *)dst_;
775 while (n--)
777 dst[0] = src[0];
778 ab_to_ch_stepf (src + 1, dst + 1);
779 dst[3] = src[3];
781 src += 4;
782 dst += 4;
786 /* End conversion routines. */
788 static void
789 conversions (void)
791 constants ();
793 #define _pair(f1, f2, fwd, rev) \
794 do \
796 babl_conversion_new (babl_format (f1), babl_format (f2), "linear", fwd, \
797 NULL); \
798 babl_conversion_new (babl_format (f2), babl_format (f1), "linear", rev, \
799 NULL); \
801 while (0)
803 babl_conversion_new (babl_model("RGBA"),
804 babl_model("OklabA"),
805 "linear", rgba_to_laba,
806 NULL);
807 babl_conversion_new (babl_model("OklabA"),
808 babl_model("RGBA"),
809 "linear", laba_to_rgba,
810 NULL);
812 babl_conversion_new (babl_model("RGBA"),
813 babl_model("Oklab"),
814 "linear", rgba_to_lab,
815 NULL);
816 babl_conversion_new (babl_model("Oklab"),
817 babl_model("RGBA"),
818 "linear", lab_to_rgba,
819 NULL);
821 _pair ("RGB float", "Oklab float", rgb_to_lab_float, lab_to_rgb_float);
822 _pair ("RGBA float", "Oklab alpha float", rgba_to_laba_float, laba_to_rgba_float);
823 _pair ("RGBA float", "Oklab float", rgba_to_lab_float, lab_to_rgba_float);
825 if (enable_lch)
827 babl_conversion_new (babl_model("RGBA"),
828 babl_model("OklchA"),
829 "linear", rgba_to_lcha,
830 NULL);
831 babl_conversion_new (babl_model("OklchA"),
832 babl_model("RGBA"),
833 "linear", lcha_to_rgba,
834 NULL);
836 babl_conversion_new (babl_model("RGBA"),
837 babl_model("Oklch"),
838 "linear", rgba_to_lch,
839 NULL);
840 babl_conversion_new (babl_model("Oklch"),
841 babl_model("RGBA"),
842 "linear", lch_to_rgba,
843 NULL);
844 _pair ("RGBA float", "Oklch float", rgba_to_lch_float, lch_to_rgba_float);
845 _pair ("RGB float", "Oklch float", rgb_to_lch_float, lch_to_rgb_float);
846 _pair ("RGBA float", "Oklch alpha float", rgba_to_lcha_float, lcha_to_rgba_float);
848 _pair ("Oklab float", "Oklch float", lab_to_lch_float, lch_to_lab_float);
849 _pair ("Oklab alpha float", "Oklch alpha float", laba_to_lcha_float, lcha_to_laba_float);
851 #undef _pair