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/
32 #include "babl-internal.h"
33 #include "babl-matrix.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);
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
65 babl_component_new ("Ok L", "doc", "Luminance, range 0.0-100.0 in float",
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",
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
);
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
);
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
);
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
);
107 "name", "Oklab float",
108 babl_model ("Oklab"),
110 babl_component ("Ok L"),
111 babl_component ("Ok a"),
112 babl_component ("Ok b"),
118 "name", "Oklab alpha float",
119 babl_model ("OklabA"),
121 babl_component ("Ok L"),
122 babl_component ("Ok a"),
123 babl_component ("Ok b"),
124 babl_component ("A"),
131 "name", "Oklch float",
132 babl_model ("Oklch"),
134 babl_component ("Ok L"),
135 babl_component ("Ok C"),
136 babl_component ("Ok H"),
141 "name", "Oklch alpha float",
142 babl_model ("OklchA"),
144 babl_component ("Ok L"),
145 babl_component ("Ok C"),
146 babl_component ("Ok H"),
147 babl_component ("A"),
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,
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
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
));
200 XYZ_to_Oklab_step (double *xyz
, double *lab_out
)
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
);
212 XYZ_to_Oklab_stepf (float *xyz
, float *lab_out
)
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
);
224 Oklab_to_XYZ_stepf (float *lab
, float *xyz_out
)
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
);
236 Oklab_to_XYZ_step (double *lab
, double *xyz_out
)
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
);
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
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
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
;
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
;
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);
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);
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
);
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
);
325 double D65
[3] = { 0.95047, 1.0, 1.08883 };
326 double D50
[3] = { 0.96420288, 1.0, 0.82490540 };
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
);
345 /* Convertion routine (glue and boilerplate). */
347 rgba_to_laba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
350 float *src
= (float *)src_
, *dst
= (float *)dst_
;
351 const Babl
*space
= babl_conversion_get_source_space (conversion
);
356 babl_space_to_xyzf (space
, src
, xyz
);
357 XYZ_to_Oklab_stepf (xyz
, dst
);
366 rgba_to_laba (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
369 double *src
= (double*)src_
, *dst
= (double*)dst_
;
370 const Babl
*space
= babl_conversion_get_source_space (conversion
);
375 babl_space_to_xyz (space
, src
, xyz
);
376 XYZ_to_Oklab_step (xyz
, dst
);
385 rgba_to_lab_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
388 float *src
= (float *)src_
, *dst
= (float *)dst_
;
389 const Babl
*space
= babl_conversion_get_source_space (conversion
);
394 babl_space_to_xyzf (space
, src
, xyz
);
395 XYZ_to_Oklab_stepf (xyz
, dst
);
403 rgba_to_lab (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
406 double *src
= (double *)src_
, *dst
= (double *)dst_
;
407 const Babl
*space
= babl_conversion_get_source_space (conversion
);
412 babl_space_to_xyz (space
, src
, xyz
);
413 XYZ_to_Oklab_step (xyz
, dst
);
421 rgba_to_lcha_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
424 float *src
= (float *)src_
, *dst
= (float *)dst_
;
425 const Babl
*space
= babl_conversion_get_source_space (conversion
);
430 babl_space_to_xyzf (space
, src
, xyz
);
431 XYZ_to_Oklch_stepf (xyz
, dst
);
440 rgba_to_lcha (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
443 double *src
= (double *)src_
, *dst
= (double *)dst_
;
444 const Babl
*space
= babl_conversion_get_source_space (conversion
);
449 babl_space_to_xyz (space
, src
, xyz
);
450 XYZ_to_Oklch_step (xyz
, dst
);
459 rgba_to_lch_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
462 float *src
= (float *)src_
, *dst
= (float *)dst_
;
463 const Babl
*space
= babl_conversion_get_source_space (conversion
);
468 babl_space_to_xyzf (space
, src
, xyz
);
469 XYZ_to_Oklch_stepf (xyz
, dst
);
477 rgba_to_lch (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
480 double *src
= (double *)src_
, *dst
= (double *)dst_
;
481 const Babl
*space
= babl_conversion_get_source_space (conversion
);
486 babl_space_to_xyz (space
, src
, xyz
);
487 XYZ_to_Oklch_step (xyz
, dst
);
495 rgb_to_lab_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
498 float *src
= (float *)src_
, *dst
= (float *)dst_
;
499 const Babl
*space
= babl_conversion_get_source_space (conversion
);
504 babl_space_to_xyzf (space
, src
, xyz
);
505 XYZ_to_Oklab_stepf (xyz
, dst
);
513 rgb_to_lch_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
516 float *src
= (float *)src_
, *dst
= (float *)dst_
;
517 const Babl
*space
= babl_conversion_get_source_space (conversion
);
522 babl_space_to_xyzf (space
, src
, xyz
);
523 XYZ_to_Oklch_stepf (xyz
, dst
);
531 lab_to_rgb_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
534 float *src
= (float *)src_
, *dst
= (float *)dst_
;
535 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
540 Oklab_to_XYZ_stepf (src
, xyz
);
541 babl_space_from_xyzf (space
, xyz
, dst
);
549 lab_to_rgba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
552 float *src
= (float *)src_
, *dst
= (float *)dst_
;
553 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
558 Oklab_to_XYZ_stepf (src
, xyz
);
559 babl_space_from_xyzf (space
, xyz
, dst
);
568 lab_to_rgba (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
571 double *src
= (double *)src_
, *dst
= (double *)dst_
;
572 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
577 Oklab_to_XYZ_step (src
, xyz
);
578 babl_space_from_xyz (space
, xyz
, dst
);
587 lch_to_rgb_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
590 float *src
= (float *)src_
, *dst
= (float *)dst_
;
591 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
596 Oklch_to_XYZ_stepf (src
, xyz
);
597 babl_space_from_xyzf (space
, xyz
, dst
);
605 laba_to_rgba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
608 float *src
= (float *)src_
, *dst
= (float *)dst_
;
609 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
614 Oklab_to_XYZ_stepf (src
, xyz
);
615 babl_space_from_xyzf (space
, xyz
, dst
);
624 laba_to_rgba (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
627 double *src
= (double *)src_
, *dst
= (double *)dst_
;
628 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
633 Oklab_to_XYZ_step (src
, xyz
);
634 babl_space_from_xyz (space
, xyz
, dst
);
643 lcha_to_rgba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
646 float *src
= (float *)src_
, *dst
= (float *)dst_
;
647 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
652 Oklch_to_XYZ_stepf (src
, xyz
);
653 babl_space_from_xyzf (space
, xyz
, dst
);
662 lcha_to_rgba (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
665 double *src
= (double *)src_
, *dst
= (double *)dst_
;
666 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
671 Oklch_to_XYZ_step (src
, xyz
);
672 babl_space_from_xyz (space
, xyz
, dst
);
682 lch_to_rgba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
685 float *src
= (float *)src_
, *dst
= (float *)dst_
;
686 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
691 Oklch_to_XYZ_stepf (src
, xyz
);
692 babl_space_from_xyzf (space
, xyz
, dst
);
701 lch_to_rgba (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
704 double *src
= (double *)src_
, *dst
= (double *)dst_
;
705 const Babl
*space
= babl_conversion_get_destination_space (conversion
);
710 Oklch_to_XYZ_step (src
, xyz
);
711 babl_space_from_xyz (space
, xyz
, dst
);
721 lch_to_lab_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
724 float *src
= (float *)src_
, *dst
= (float *)dst_
;
729 ch_to_ab_stepf (src
+ 1, dst
+ 1);
737 lab_to_lch_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
740 float *src
= (float *)src_
, *dst
= (float *)dst_
;
745 ab_to_ch_stepf (src
+ 1, dst
+ 1);
753 lcha_to_laba_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
756 float *src
= (float *)src_
, *dst
= (float *)dst_
;
761 ch_to_ab_stepf (src
+ 1, dst
+ 1);
770 laba_to_lcha_float (const Babl
*conversion
, char *src_
, char *dst_
, long samples
)
773 float *src
= (float *)src_
, *dst
= (float *)dst_
;
778 ab_to_ch_stepf (src
+ 1, dst
+ 1);
786 /* End conversion routines. */
793 #define _pair(f1, f2, fwd, rev) \
796 babl_conversion_new (babl_format (f1), babl_format (f2), "linear", fwd, \
798 babl_conversion_new (babl_format (f2), babl_format (f1), "linear", rev, \
803 babl_conversion_new (babl_model("RGBA"),
804 babl_model("OklabA"),
805 "linear", rgba_to_laba
,
807 babl_conversion_new (babl_model("OklabA"),
809 "linear", laba_to_rgba
,
812 babl_conversion_new (babl_model("RGBA"),
814 "linear", rgba_to_lab
,
816 babl_conversion_new (babl_model("Oklab"),
818 "linear", lab_to_rgba
,
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
);
827 babl_conversion_new (babl_model("RGBA"),
828 babl_model("OklchA"),
829 "linear", rgba_to_lcha
,
831 babl_conversion_new (babl_model("OklchA"),
833 "linear", lcha_to_rgba
,
836 babl_conversion_new (babl_model("RGBA"),
838 "linear", rgba_to_lch
,
840 babl_conversion_new (babl_model("Oklch"),
842 "linear", lch_to_rgba
,
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
);