aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2016-12-02 23:33:15 +0100
committerMattias Andrée <maandree@kth.se>2016-12-02 23:33:15 +0100
commitb51a413074a9844e3c045c743dc1ba56414b6263 (patch)
tree77a564ee78eb059d13d45191783857bd87901960
parentAdd new colour spaces (diff)
downloadlibclut-b51a413074a9844e3c045c743dc1ba56414b6263.tar.gz
libclut-b51a413074a9844e3c045c743dc1ba56414b6263.tar.bz2
libclut-b51a413074a9844e3c045c743dc1ba56414b6263.tar.xz
Add libclut_model_rgb_to_ciexyz and libclut_model_ciexyz_to_rgb
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--NEWS6
-rw-r--r--doc/info/chap/colour-spaces.texinfo75
-rw-r--r--src/libclut.c103
-rw-r--r--src/libclut.h80
-rw-r--r--src/test.c77
5 files changed, 308 insertions, 33 deletions
diff --git a/NEWS b/NEWS
index 8f651d3..1cefe93 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,12 @@ libclut NEWS -*- outline -*-
New RGB colour spaces added: ITU-R BT.709 and Lightroom RGB.
+ libclut_model_get_rgb_conversion_matrix accepts NULL as
+ as the first and second argument.
+
+ Add the functions libclut_model_rgb_to_xyz and
+ libclut_model_rgb_to_xyz.
+
* Noteworthy changes in release 1.0 (2016-(12)Dec-02) [stable]
RGB colour space conversion added.
diff --git a/doc/info/chap/colour-spaces.texinfo b/doc/info/chap/colour-spaces.texinfo
index e1dfae1..b190ada 100644
--- a/doc/info/chap/colour-spaces.texinfo
+++ b/doc/info/chap/colour-spaces.texinfo
@@ -895,9 +895,11 @@ This function is not available as a macro, thus, linking with
Parameters:
@table @code
@item const libclut_rgb_colour_space_t* from
-Description of the input colour space.
+Description of the input colour space. CIE XYZ is
+used use if this parameter is @code{NULL}.
@item const libclut_rgb_colour_space_t* to
-Description of the output colour space.
+Description of the output colour space. CIE XYZ is
+used use if this parameter is @code{NULL}.
@item libclut_colour_space_conversion_matrix_t M
Matrix to fill with values so it can be used for
converting from the input colour space to the
@@ -923,7 +925,7 @@ function.
@table @code
@item libclut_model_convert_rgb(r, g, b, M, *out_r, *out_g, *out_b)
Convert a single RGB colour into another RGB colour space.
-The colour space must have same gamma functions as RGB.
+The colour space must have same gamma functions as sRGB.
This macro is also available a function. If the function is
used, linking with @option{-lclut} is required, otherwise,
@@ -949,6 +951,7 @@ Output parameter for the green value of the colour after conversion.
Output parameter for the blue value of the colour after conversion.
@end table
+
@item libclut_convert_rgb_inplace(clut, max, type, m, trunc)
Convert the curves between two RGB colour spaces.
@@ -986,6 +989,7 @@ out of gamut are truncated. (Not necessarily the best
approximation.)
@end table
+
@item libclut_convert_rgb(clut, max, type, m, trunc, out)
Convert the curves between two RGB colour spaces.
@@ -1031,3 +1035,68 @@ the same data type as @code{clut}. And have the same values on
@code{clut}.
@end table
@end table
+
+There is also two functions for converting between a custom RGB
+colour space and CIE XYZ, one function in each direction. Note
+that the three functions above do not work if one of the colour
+spaces is CIE XYZ.
+
+@table @code
+@item libclut_model_rgb_to_ciexyz(r, g, b, M, *X, *Y, *Z)
+Convert a single RGB colour if a custom RGB colour space
+to CIE XYZ.
+
+The RGB colour space must have the same gamma function as sRGB.
+
+This macro is also available a function. If the function is
+used, linking with @option{-lclut} is required, otherwise,
+linking with @option{-lm} is required, or @option{-lclut} if
+@code{libclut_model_standard_to_linear1} is undefined.
+
+Parameters:
+@table @code
+@item double r
+The red component.
+@item double g
+The green component.
+@item double b
+The blue component.
+@item libclut_colour_space_conversion_matrix_t M
+The conversion matrix.
+@item double* X
+Output parameter for the X component.
+@item double* Y
+Output parameter for the Y component.
+@item double* Z
+Output parameter for the Z component.
+@end table
+
+
+@item libclut_model_rgb_to_ciexyz(X, Y, Z, M, *r, *g, *b)
+Convert a single colour from CIE XYZ to a custom RGB colour space.
+
+The RGB colour space must have the same gamma function as sRGB.
+
+This macro is also available a function. If the function is
+used, linking with @option{-lclut} is required, otherwise,
+linking with @option{-lm} is required, or @option{-lclut} if
+@code{libclut_model_linear_to_standard1} is undefined.
+
+Parameters:
+@table @code
+@item double X
+The X component.
+@item double Y
+The Y component.
+@item double Z
+The Z component.
+@item libclut_colour_space_conversion_matrix_t M
+The conversion matrix.
+@item double* r
+Output parameter for the red component.
+@item double* g
+Output parameter for the green component.
+@item double* b
+Output parameter for the blue component.
+@end table
+@end table
diff --git a/src/libclut.c b/src/libclut.c
index 9395c71..52c9615 100644
--- a/src/libclut.c
+++ b/src/libclut.c
@@ -647,8 +647,10 @@ static int get_conversion_matrix(const libclut_rgb_colour_space_t* cs, libclut_c
* Create a matrix for converting values between
* two RGB colour spaces.
*
- * @param from The input colour space, the Y-component is only necessary for the whitepoint.
- * @param to The output colour space, the Y-component is only necessary for the whitepoint.
+ * @param from The input colour space, the Y-component is only necessary
+ * for the white point, `NULL` for CIE XYZ.
+ * @param to The output colour space, the Y-component is only necessary
+ * for the white point, `NULL` for CIE XYZ.
* @param M Output matrix for conversion from `from` to `to`.
* @param Minv Output matrix for conversion from `to` to `from`, may be `NULL`.
* @return Zero on success, -1 on error.
@@ -662,24 +664,44 @@ int libclut_model_get_rgb_conversion_matrix(const libclut_rgb_colour_space_t* fr
{
libclut_colour_space_conversion_matrix_t A, B;
- if (get_conversion_matrix(from, A))
- return -1;
- if (get_conversion_matrix(to, M))
- return -1;
- if (!invert(M, B))
- return errno = EINVAL, -1;
-
- M[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
- M[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
- M[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
-
- M[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
- M[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
- M[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
+ if (from != NULL)
+ {
+ if (get_conversion_matrix(from, A))
+ return -1;
+ }
+ else
+ {
+ A[0][0] = A[1][1] = A[2][2] = 1;
+ A[0][1] = A[1][0] = A[2][0] = 0;
+ A[0][2] = A[1][2] = A[2][1] = 0;
+ }
- M[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
- M[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
- M[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
+ if (to != NULL)
+ {
+ if (get_conversion_matrix(to, M))
+ return -1;
+ if (!invert(M, B))
+ return errno = EINVAL, -1;
+
+ if (from != NULL)
+ {
+ M[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
+ M[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
+ M[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
+
+ M[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
+ M[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
+ M[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
+
+ M[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
+ M[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
+ M[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
+ }
+ else
+ memcpy(M, B, sizeof(B));
+ }
+ else
+ memcpy(M, A, sizeof(A));
if (Minv != NULL)
{
@@ -694,9 +716,8 @@ int libclut_model_get_rgb_conversion_matrix(const libclut_rgb_colour_space_t* fr
/**
* Convert an RGB colour into another RGB colour space.
- * None of the parameter may have side-effects.
*
- * Both RGB colour space must have same gamma functions as RGB.
+ * Both RGB colour spaces must have same gamma functions as sRGB.
*
* @param r The red component of the colour to convert.
* @param g The green component of the colour to convert.
@@ -712,3 +733,43 @@ void (libclut_model_convert_rgb)(double r, double g, double b, libclut_colour_sp
libclut_model_convert_rgb(r, g, b, M, out_r, out_g, out_b);
}
+
+/**
+ * Convert an RGB colour of a custom RGB colour space to CIE XYZ.
+ *
+ * The RGB colour space must have same gamma functions as sRGB.
+ *
+ * @param r The red component.
+ * @param g The green component.
+ * @param b The blue component.
+ * @param M Conversion matrix, create with `libclut_model_get_rgb_conversion_matrix`.
+ * @param x Output parameter for the X component.
+ * @param y Output parameter for the Y component.
+ * @param z Output parameter for the Z component.
+ */
+void (libclut_model_rgb_to_ciexyz)(double r, double g, double b, libclut_colour_space_conversion_matrix_t M,
+ double* x, double* y, double* z)
+{
+ libclut_model_rgb_to_ciexyz(r, g, b, M, x, y, z);
+}
+
+
+/**
+ * Convert a CIE XYZ colour to a custom RGB colour space.
+ *
+ * The RGB colour space must have same gamma functions as sRGB.
+ *
+ * @param x The X component.
+ * @param y The Y component.
+ * @param z The Z component.
+ * @param M Conversion matrix, create with `libclut_model_get_rgb_conversion_matrix`.
+ * @param r Output parameter for the red component.
+ * @param g Output parameter for the green component
+ * @param b Output parameter for the blue component.
+ */
+void (libclut_model_ciexyz_to_rgb)(double x, double y, double z, libclut_colour_space_conversion_matrix_t M,
+ double* r, double* g, double* b)
+{
+ libclut_model_ciexyz_to_rgb(x, y, z, M, r, g, b);
+}
+
diff --git a/src/libclut.h b/src/libclut.h
index e1601f1..7c0dcd8 100644
--- a/src/libclut.h
+++ b/src/libclut.h
@@ -630,7 +630,7 @@ static inline int libclut_0__(double x) { return libclut_eq__(x, 0); }
/**
* Convert the curves between two RGB colour spaces.
*
- * Both RGB colour space must have same gamma functions as sRGB.
+ * Both RGB colour spaces must have same gamma functions as sRGB.
*
* Requires that `clut->red_size`, `clut->green_size`
* and `clut->blue_size` are equal.
@@ -692,7 +692,7 @@ static inline int libclut_0__(double x) { return libclut_eq__(x, 0); }
/**
* Convert the curves between two RGB colour spaces.
*
- * Both RGB colour space must have same gamma functions as sRGB.
+ * Both RGB colour spaces must have same gamma functions as sRGB.
*
* None of the parameter may have side-effects.
*
@@ -1871,7 +1871,7 @@ void (libclut_model_linear_to_ciexyz)(double, double, double, double*, double*,
/**
- * Convert [0, 1] linear sRGB to CIE xyY.
+ * Convert [0, 1] sRGB to CIE xyY.
*
* The macro variant requires linking with '-lclut'
* if any of `libclut_model_ciexyz_to_ciexyy`,
@@ -2499,8 +2499,10 @@ void (libclut_model_cie_1960_ucs_to_cieuvw)(double, double, double, double, doub
* Create a matrix for converting values between
* two RGB colour spaces.
*
- * @param from The input colour space, the Y-component is only necessary for the whitepoint.
- * @param to The output colour space, the Y-component is only necessary for the whitepoint.
+ * @param from The input colour space, the Y-component is only necessary
+ * for the white point, `NULL` for CIE XYZ.
+ * @param to The output colour space, the Y-component is only necessary
+ * for the white point, `NULL` for CIE XYZ.
* @param M Output matrix for conversion from `from` to `to`.
* @param Minv Output matrix for conversion from `to` to `from`, may be `NULL`.
* @return Zero on success, -1 on error.
@@ -2517,7 +2519,7 @@ int libclut_model_get_rgb_conversion_matrix(const libclut_rgb_colour_space_t*,
/**
* Convert an RGB colour into another RGB colour space.
*
- * Both RGB colour space must have same gamma functions as RGB.
+ * Both RGB colour spaces must have same gamma functions as sRGB.
*
* Requires linking with '-lclut', or '-lm' if
* `libclut_model_standard_to_linear1` or
@@ -2527,7 +2529,7 @@ int libclut_model_get_rgb_conversion_matrix(const libclut_rgb_colour_space_t*,
* @param g The green component of the colour to convert.
* @param b The blue component of the colour to convert.
* @param M Conversion matrix, create with `libclut_model_get_rgb_conversion_matrix`,
- * must not have side-effects (unless libclut_model_convert_rgb1 is undefined).
+ * must not have side-effects.
* @param out_r Output parameter for the new red component.
* @param out_g Output parameter for the new green component.
* @param out_b Output parameter for the new blue component.
@@ -2548,6 +2550,70 @@ void (libclut_model_convert_rgb)(double, double, double, libclut_colour_space_co
while (0)
+/**
+ * Convert an RGB colour of a custom RGB colour space to CIE XYZ.
+ *
+ * The RGB colour space must have same gamma functions as sRGB.
+ *
+ * Requires linking with '-lclut', or '-lm' if
+ * `libclut_model_standard_to_linear1` is not undefined.
+ *
+ * @param r The red component.
+ * @param g The green component.
+ * @param b The blue component.
+ * @param M Conversion matrix, create with `libclut_model_get_rgb_conversion_matrix`,
+ * must not have side-effects.
+ * @param x Output parameter for the X component.
+ * @param y Output parameter for the Y component
+ * @param z Output parameter for the Z component.
+ */
+LIBCLUT_GCC_ONLY__(__attribute__((__leaf__)))
+void (libclut_model_rgb_to_ciexyz)(double, double, double, libclut_colour_space_conversion_matrix_t,
+ double*, double*, double*);
+#define libclut_model_rgb_to_ciexyz(r, g, b, M, x, y, z) \
+ do \
+ { \
+ double r__ = libclut_model_standard_to_linear1(r); \
+ double g__ = libclut_model_standard_to_linear1(g); \
+ double b__ = libclut_model_standard_to_linear1(b); \
+ *(x) = (M)[0][0] * r__ + (M)[0][1] * g__ + (M)[0][2] * b__; \
+ *(y) = (M)[1][0] * r__ + (M)[1][1] * g__ + (M)[1][2] * b__; \
+ *(z) = (M)[2][0] * r__ + (M)[2][1] * g__ + (M)[2][2] * b__; \
+ } \
+ while (0)
+
+
+/**
+ * Convert a CIE XYZ colour to a custom RGB colour space.
+ *
+ * The RGB colour space must have same gamma functions as sRGB.
+ *
+ * Requires linking with '-lclut', or '-lm' if
+ * `libclut_model_linear_to_standard1` is not undefined.
+ *
+ * @param x The X component.
+ * @param y The Y component.
+ * @param z The Z component.
+ * @param M Conversion matrix, create with `libclut_model_get_rgb_conversion_matrix`,
+ * must not have side-effects.
+ * @param r Output parameter for the red component.
+ * @param g Output parameter for the green component
+ * @param b Output parameter for the blue component.
+ */
+LIBCLUT_GCC_ONLY__(__attribute__((__leaf__)))
+void (libclut_model_ciexyz_to_rgb)(double, double, double, libclut_colour_space_conversion_matrix_t,
+ double*, double*, double*);
+#define libclut_model_ciexyz_to_rgb(x, y, z, M, r, g, b) \
+ do \
+ { \
+ double x__ = (x), y__ = (y), z__ = (z); \
+ *(r) = libclut_model_linear_to_standard1((M)[0][0] * x__ + (M)[0][1] * y__ + (M)[0][2] * z__); \
+ *(g) = libclut_model_linear_to_standard1((M)[1][0] * x__ + (M)[1][1] * y__ + (M)[1][2] * z__); \
+ *(b) = libclut_model_linear_to_standard1((M)[2][0] * x__ + (M)[2][1] * y__ + (M)[2][2] * z__); \
+ } \
+ while (0)
+
+
#if defined(__clang__)
# pragma GCC diagnostic pop
diff --git a/src/test.c b/src/test.c
index b4491a8..28e8e7d 100644
--- a/src/test.c
+++ b/src/test.c
@@ -145,7 +145,7 @@ int main(int argc, char *argv[])
struct dclut d1, d2;
size_t i, j;
int rc = 0;
- double param, r, g, b;
+ double param, r, g, b, x, y, z;
t1. red_size = t2. red_size = t3. red_size = d1. red_size = d2. red_size = 256;
t1.green_size = t2.green_size = t3.green_size = d1.green_size = d2.green_size = 256;
@@ -360,11 +360,84 @@ int main(int argc, char *argv[])
libclut_convert_rgb_inplace(&t1, 1, double, M, trunc); /* TODO test */
libclut_convert_rgb(&t1, 1, double, M, trunc, &t2); /* TODO test */
+
+ if (libclut_model_get_rgb_conversion_matrix(&srgb, NULL, M, Minv))
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ libclut_model_rgb_to_ciexyz(0.1, 0.5, 0.9, M, &x, &y, &z);
+ if (0.2227 > x || x > 0.2228 ||
+ 0.2120 > y || y > 0.2121 ||
+ 0.7739 > z || z > 0.7741)
+ {
+ printf("libclut_model_get_rgb_conversion_matrix or libclut_model_rgb_to_ciexyz failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ libclut_model_ciexyz_to_rgb(x, y, z, Minv, &r, &g, &b);
+ if (0.0999 > r || r > 1.0001 ||
+ 0.4999 > g || g > 0.5001 ||
+ 0.8999 > b || b > 0.9001)
+ {
+ printf("libclut_model_get_rgb_conversion_matrix or libclut_model_ciexyz_to_rgb failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
- rgb_conversion_done:
+
+ if (libclut_model_get_rgb_conversion_matrix(NULL, &srgb, Minv, M))
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ libclut_model_rgb_to_ciexyz(0.1, 0.5, 0.9, M, &r, &g, &b);
+ libclut_model_ciexyz_to_rgb(r, g, b, Minv, &r, &g, &b);
+ if (0.0999 > r || r > 1.0001 ||
+ 0.4999 > g || g > 0.5001 ||
+ 0.8999 > b || b > 0.9001)
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ if (libclut_model_get_rgb_conversion_matrix(NULL, NULL, M, Minv))
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ if (0.999999 > M[0][0] || M[0][0] > 1.000001 ||
+ -.999999 > M[0][1] || M[0][1] > 0.000001 ||
+ -.999999 > M[0][2] || M[0][2] > 0.000001 ||
+ -.999999 > M[1][0] || M[1][0] > 0.000001 ||
+ 0.999999 > M[1][1] || M[1][1] > 1.000001 ||
+ -.999999 > M[1][2] || M[1][2] > 0.000001 ||
+ -.999999 > M[2][0] || M[2][0] > 0.000001 ||
+ -.999999 > M[2][1] || M[2][1] > 0.000001 ||
+ 0.999999 > M[2][2] || M[2][2] > 1.000001)
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+ if (0.999999 > Minv[0][0] || Minv[0][0] > 1.000001 ||
+ -.999999 > Minv[0][1] || Minv[0][1] > 0.000001 ||
+ -.999999 > Minv[0][2] || Minv[0][2] > 0.000001 ||
+ -.999999 > Minv[1][0] || Minv[1][0] > 0.000001 ||
+ 0.999999 > Minv[1][1] || Minv[1][1] > 1.000001 ||
+ -.999999 > Minv[1][2] || Minv[1][2] > 0.000001 ||
+ -.999999 > Minv[2][0] || Minv[2][0] > 0.000001 ||
+ -.999999 > Minv[2][1] || Minv[2][1] > 0.000001 ||
+ 0.999999 > Minv[2][2] || Minv[2][2] > 1.000001)
+ {
+ printf("libclut_model_get_rgb_conversion_matrix failed\n"), rc = 1;
+ goto rgb_conversion_done;
+ }
+
+
+ libclut_model_get_rgb_conversion_matrix(&srgb, &wgrgb, M, NULL); /* Just testing that we don't get a segfault. */
+ rgb_conversion_done:
+
+
libclut_model_ciexyz_to_cieluv(1, 1, 1, 1, 1, 1, &r, &g, &b); /* TODO test */
libclut_model_cieluv_to_ciexyz(1, 1, 1, 1, 1, 1, &r, &g, &b); /* TODO test */
libclut_model_cielch_to_cieluv(1, 1, &r, &g); /* TODO test */