int\r
init (void)\r
{\r
+ return 0; // the oklab conversions are not fully symmetric,\r
+ // thus not allowing the tests to pass if we register\r
+ // the code\r
components ();\r
models ();\r
formats ();\r
static float M2f[9];\r
static float inv_M1f[9];\r
static float inv_M2f[9];\r
+\r
+static double inv_M1[9];\r
+static double inv_M2[9];\r
static int mat_ready;\r
\r
/* fast approximate cube root\r
}\r
\r
static inline void\r
-XYZ_to_Oklab_step (float *xyz, float *lab_out)\r
+XYZ_to_Oklab_step (double *xyz, double *lab_out)\r
+{\r
+ double lms[3];\r
+ babl_matrix_mul_vector (M1, xyz, lms);\r
+ for (int i = 0; i < 3; i++)\r
+ {\r
+ lms[i] = cbrt (lms[i]);\r
+ }\r
+ babl_matrix_mul_vector (M2, lms, lab_out);\r
+}\r
+\r
+static inline void\r
+XYZ_to_Oklab_stepf (float *xyz, float *lab_out)\r
{\r
float lms[3];\r
babl_matrix_mul_vectorff (M1f, xyz, lms);\r
}\r
\r
static inline void\r
-Oklab_to_XYZ_step (float *lab, float *xyz_out)\r
+Oklab_to_XYZ_stepf (float *lab, float *xyz_out)\r
{\r
float lms[3];\r
babl_matrix_mul_vectorff (inv_M2f, lab, lms);\r
}\r
\r
static inline void\r
-ab_to_ch_step (float *ab, float *ch_out)\r
+Oklab_to_XYZ_step (double *lab, double *xyz_out)\r
{\r
- float a = ab[0], b = ab[1];\r
+ double lms[3];\r
+ babl_matrix_mul_vector (inv_M2, lab, lms);\r
+ for (int i = 0; i < 3; i++)\r
+ {\r
+ lms[i] = lms[i] * lms[i] * lms[i];\r
+ }\r
+ babl_matrix_mul_vector (inv_M1, lms, xyz_out);\r
+}\r
+\r
+static inline void\r
+ab_to_ch_step (double *ab, double *ch_out)\r
+{\r
+ double a = ab[0], b = ab[1];\r
\r
ch_out[1] = sqrt (a * a + b * b);\r
ch_out[2] = atan2 (b, a) * DEGREES_PER_RADIAN;\r
}\r
\r
static inline void\r
-ch_to_ab_step (float *ch, float *ab_out)\r
+ab_to_ch_stepf (float *ab, float *ch_out)\r
{\r
- float c = ch[0], h = ch[1];\r
+ float a = ab[0], b = ab[1];\r
+\r
+ ch_out[1] = sqrtf (a * a + b * b);\r
+ ch_out[2] = atan2f (b, a) * DEGREES_PER_RADIAN;\r
+\r
+ // Keep H within the range 0-360\r
+ if (ch_out[2] < 0.0)\r
+ ch_out[2] += 360;\r
+}\r
+\r
+static inline void\r
+ch_to_ab_step (double *ch, double *ab_out)\r
+{\r
+ double c = ch[0], h = ch[1];\r
\r
ab_out[0] = cos (h * RADIANS_PER_DEGREE) * c;\r
ab_out[1] = sin (h * RADIANS_PER_DEGREE) * c;\r
}\r
\r
static inline void\r
-XYZ_to_Oklch_step (float *xyz, float *lch_out)\r
+ch_to_ab_stepf (float *ch, float *ab_out)\r
+{\r
+ float c = ch[0], h = ch[1];\r
+\r
+ ab_out[0] = cosf (h * RADIANS_PER_DEGREE) * c;\r
+ ab_out[1] = sinf (h * RADIANS_PER_DEGREE) * c;\r
+}\r
+\r
+static inline void\r
+XYZ_to_Oklch_step (double *xyz, double *lch_out)\r
{\r
XYZ_to_Oklab_step (xyz, lch_out);\r
ab_to_ch_step (lch_out + 1, lch_out + 1);\r
}\r
\r
static inline void\r
-Oklch_to_XYZ_step (float *lch, float *xyz_out)\r
+XYZ_to_Oklch_stepf (float *xyz, float *lch_out)\r
{\r
- float lab[3] = { lch[0], lch[1], lch[2] };\r
+ XYZ_to_Oklab_stepf (xyz, lch_out);\r
+ ab_to_ch_stepf (lch_out + 1, lch_out + 1);\r
+}\r
+\r
+static inline void\r
+Oklch_to_XYZ_step (double *lch, double *xyz_out)\r
+{\r
+ double lab[3] = { lch[0], lch[1], lch[2] };\r
ch_to_ab_step (lab + 1, lab + 1);\r
Oklab_to_XYZ_step (lab, xyz_out);\r
}\r
\r
+static inline void\r
+Oklch_to_XYZ_stepf (float *lch, float *xyz_out)\r
+{\r
+ float lab[3] = { lch[0], lch[1], lch[2] };\r
+ ch_to_ab_stepf (lab + 1, lab + 1);\r
+ Oklab_to_XYZ_stepf (lab, xyz_out);\r
+}\r
+\r
static inline void\r
constants (void)\r
{\r
babl_chromatic_adaptation_matrix (D50, D65, tmp);\r
babl_matrix_mul_matrix (tmp, M1, M1);\r
\r
- babl_matrix_invert (M1, tmp);\r
- babl_matrix_to_float (tmp, inv_M1f);\r
- babl_matrix_invert (M2, tmp);\r
- babl_matrix_to_float (tmp, inv_M2f);\r
+ babl_matrix_invert (M1, inv_M1);\r
+ babl_matrix_to_float (inv_M1, inv_M1f);\r
+ babl_matrix_invert (M2, inv_M2);\r
+ babl_matrix_to_float (inv_M2, inv_M2f);\r
\r
babl_matrix_to_float (M1, M1f);\r
babl_matrix_to_float (M2, M2f);\r
\r
/* Convertion routine (glue and boilerplate). */\r
static void\r
-rgba_to_laba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+rgba_to_laba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
{\r
float xyz[3];\r
babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklab_stepf (xyz, dst);\r
+ dst[3] = src[3];\r
+\r
+ src += 4;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+static void\r
+rgba_to_laba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double*)src_, *dst = (double*)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ babl_space_to_xyz (space, src, xyz);\r
XYZ_to_Oklab_step (xyz, dst);\r
dst[3] = src[3];\r
\r
}\r
\r
static void\r
-rgba_to_lab (const Babl *conversion, char *src_, char *dst_, long samples)\r
+rgba_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
{\r
float xyz[3];\r
babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklab_stepf (xyz, dst);\r
+\r
+ src += 4;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+rgba_to_lab (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ babl_space_to_xyz (space, src, xyz);\r
XYZ_to_Oklab_step (xyz, dst);\r
\r
src += 4;\r
}\r
\r
static void\r
-rgba_to_lcha (const Babl *conversion, char *src_, char *dst_, long samples)\r
+rgba_to_lcha_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
{\r
float xyz[3];\r
babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklch_stepf (xyz, dst);\r
+ dst[3] = src[3];\r
+\r
+ src += 4;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+static void\r
+rgba_to_lcha (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ babl_space_to_xyz (space, src, xyz);\r
XYZ_to_Oklch_step (xyz, dst);\r
dst[3] = src[3];\r
\r
}\r
\r
static void\r
-rgba_to_lch (const Babl *conversion, char *src_, char *dst_, long samples)\r
+rgba_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
{\r
float xyz[3];\r
babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklch_stepf (xyz, dst);\r
+\r
+ src += 4;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+rgba_to_lch (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ babl_space_to_xyz (space, src, xyz);\r
XYZ_to_Oklch_step (xyz, dst);\r
\r
src += 4;\r
}\r
\r
static void\r
-lab_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+rgb_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ float *src = (float *)src_, *dst = (float *)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ float xyz[3];\r
+ babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklab_stepf (xyz, dst);\r
+\r
+ src += 3;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+rgb_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ float *src = (float *)src_, *dst = (float *)dst_;\r
+ const Babl *space = babl_conversion_get_source_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ float xyz[3];\r
+ babl_space_to_xyzf (space, src, xyz);\r
+ XYZ_to_Oklch_stepf (xyz, dst);\r
+\r
+ src += 3;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+lab_to_rgb_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
float xyz[3];\r
- Oklab_to_XYZ_step (src, xyz);\r
+ Oklab_to_XYZ_stepf (src, xyz);\r
+ babl_space_from_xyzf (space, xyz, dst);\r
+\r
+ src += 3;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+lab_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ float *src = (float *)src_, *dst = (float *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ float xyz[3];\r
+ Oklab_to_XYZ_stepf (src, xyz);\r
babl_space_from_xyzf (space, xyz, dst);\r
dst[3] = 1.0;\r
\r
}\r
\r
static void\r
-laba_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+lab_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ Oklab_to_XYZ_step (src, xyz);\r
+ babl_space_from_xyz (space, xyz, dst);\r
+ dst[3] = 1.0;\r
+\r
+ src += 3;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+static void\r
+lch_to_rgb_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
float xyz[3];\r
- Oklab_to_XYZ_step (src, xyz);\r
+ Oklch_to_XYZ_stepf (src, xyz);\r
+ babl_space_from_xyzf (space, xyz, dst);\r
+\r
+ src += 3;\r
+ dst += 3;\r
+ }\r
+}\r
+\r
+static void\r
+laba_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ float *src = (float *)src_, *dst = (float *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ float xyz[3];\r
+ Oklab_to_XYZ_stepf (src, xyz);\r
babl_space_from_xyzf (space, xyz, dst);\r
dst[3] = src[3];\r
\r
}\r
\r
static void\r
-lcha_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+laba_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ Oklab_to_XYZ_step (src, xyz);\r
+ babl_space_from_xyz (space, xyz, dst);\r
+ dst[3] = src[3];\r
+\r
+ src += 4;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+static void\r
+lcha_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
float xyz[3];\r
- Oklch_to_XYZ_step (src, xyz);\r
+ Oklch_to_XYZ_stepf (src, xyz);\r
babl_space_from_xyzf (space, xyz, dst);\r
dst[3] = src[3];\r
\r
}\r
\r
static void\r
-lch_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+lcha_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ Oklch_to_XYZ_step (src, xyz);\r
+ babl_space_from_xyz (space, xyz, dst);\r
+ dst[3] = src[3];\r
+\r
+ src += 4;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+\r
+static void\r
+lch_to_rgba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
float xyz[3];\r
- Oklch_to_XYZ_step (src, xyz);\r
+ Oklch_to_XYZ_stepf (src, xyz);\r
babl_space_from_xyzf (space, xyz, dst);\r
dst[3] = 1.0f;\r
\r
}\r
\r
static void\r
-lch_to_lab (const Babl *conversion, char *src_, char *dst_, long samples)\r
+lch_to_rgba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+{\r
+ long n = samples;\r
+ double *src = (double *)src_, *dst = (double *)dst_;\r
+ const Babl *space = babl_conversion_get_destination_space (conversion);\r
+\r
+ while (n--)\r
+ {\r
+ double xyz[3];\r
+ Oklch_to_XYZ_step (src, xyz);\r
+ babl_space_from_xyz (space, xyz, dst);\r
+ dst[3] = 1.0f;\r
+\r
+ src += 3;\r
+ dst += 4;\r
+ }\r
+}\r
+\r
+\r
+static void\r
+lch_to_lab_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
dst[0] = src[0];\r
- ch_to_ab_step (src + 1, dst + 1);\r
+ ch_to_ab_stepf (src + 1, dst + 1);\r
\r
src += 3;\r
dst += 3;\r
}\r
\r
static void\r
-lab_to_lch (const Babl *conversion, char *src_, char *dst_, long samples)\r
+lab_to_lch_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
dst[0] = src[0];\r
- ab_to_ch_step (src + 1, dst + 1);\r
+ ab_to_ch_stepf (src + 1, dst + 1);\r
\r
src += 3;\r
dst += 3;\r
}\r
\r
static void\r
-lcha_to_laba (const Babl *conversion, char *src_, char *dst_, long samples)\r
+lcha_to_laba_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
dst[0] = src[0];\r
- ch_to_ab_step (src + 1, dst + 1);\r
+ ch_to_ab_stepf (src + 1, dst + 1);\r
dst[3] = src[3];\r
\r
src += 4;\r
}\r
\r
static void\r
-laba_to_lcha (const Babl *conversion, char *src_, char *dst_, long samples)\r
+laba_to_lcha_float (const Babl *conversion, char *src_, char *dst_, long samples)\r
{\r
long n = samples;\r
float *src = (float *)src_, *dst = (float *)dst_;\r
while (n--)\r
{\r
dst[0] = src[0];\r
- ab_to_ch_step (src + 1, dst + 1);\r
+ ab_to_ch_stepf (src + 1, dst + 1);\r
dst[3] = src[3];\r
\r
src += 4;\r
dst += 4;\r
}\r
}\r
+\r
/* End conversion routines. */\r
\r
static void\r
"linear", lch_to_rgba,\r
NULL);\r
\r
- _pair ("Oklab float", "Oklch float", lab_to_lch, lch_to_lab);\r
- _pair ("Oklab alpha float", "Oklch alpha float", laba_to_lcha, lcha_to_laba);\r
-#undef _pair\r
+\r
+ _pair ("RGB float", "Oklab float", rgb_to_lab_float, lab_to_rgb_float);\r
+ _pair ("RGBA float", "Oklab alpha float", rgba_to_laba_float, laba_to_rgba_float);\r
+ _pair ("RGBA float", "Oklab float", rgba_to_lab_float, lab_to_rgba_float);\r
+\r
+ _pair ("RGBA float", "Oklch float", rgba_to_lch_float, lch_to_rgba_float);\r
+ _pair ("RGB float", "Oklch float", rgb_to_lch_float, lch_to_rgb_float);\r
+ _pair ("RGBA float", "Oklch alpha float", rgba_to_lcha_float, lcha_to_rgba_float);\r
+ \r
+ _pair ("Oklab float", "Oklch float", lab_to_lch_float, lch_to_lab_float);\r
+ _pair ("Oklab alpha float", "Oklch alpha float", laba_to_lcha_float, lcha_to_laba_float);\r
+ #undef _pair\r
}\r