aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2016-12-20 19:50:24 +0100
committerMattias Andrée <maandree@kth.se>2016-12-20 19:50:24 +0100
commit97b7af4ac979d2450364d10770b83ec94406ce31 (patch)
tree3b23affe6e1c994453c432c9f864571ef99c77e7
parentCIELChuv: measure hue in degrees, but add parameter to change this (diff)
downloadlibcolour-97b7af4ac979d2450364d10770b83ec94406ce31.tar.gz
libcolour-97b7af4ac979d2450364d10770b83ec94406ce31.tar.bz2
libcolour-97b7af4ac979d2450364d10770b83ec94406ce31.tar.xz
fix errors and add tests
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--src/convert.c154
-rw-r--r--src/libcolour.c2
-rw-r--r--src/test.c124
3 files changed, 225 insertions, 55 deletions
diff --git a/src/convert.c b/src/convert.c
index 9a2c3d9..a998d66 100644
--- a/src/convert.c
+++ b/src/convert.c
@@ -53,6 +53,106 @@ static void ciexyz_to_rgb(const libcolour_ciexyz_t* restrict from, libcolour_rgb
to->B = to->Minv[2][0] * X + to->Minv[2][1] * Y + to->Minv[2][2] * Z;
}
+#define REGULAR(s, t) ((t) <= (s)->transition ? (s)->slope * (t) : (1 + (s)->offset) * pow((t), 1 / (s)->gamma) - (s)->offset)
+#define INVREGULAR(s, t) ((t) <= (s)->transitioninv ? (t) / (s)->slope : pow(((t) + (s)->offset) / (1 + (s)->offset), (s)->gamma))
+
+static void rgb_encode(libcolour_rgb_t* restrict colour, const libcolour_rgb_t* restrict space)
+{
+ double r_sign = 1, g_sign = 1, b_sign = 1;
+ switch (space->encoding_type) {
+ case LIBCOLOUR_ENCODING_TYPE_LINEAR:
+ break;
+ case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
+ case LIBCOLOUR_ENCODING_TYPE_REGULAR:
+ if (colour->R < 0) r_sign = -1, colour->R = -colour->R;
+ if (colour->G < 0) g_sign = -1, colour->G = -colour->G;
+ if (colour->B < 0) b_sign = -1, colour->B = -colour->B;
+ if (space->encoding_type == LIBCOLOUR_ENCODING_TYPE_SIMPLE) {
+ colour->R = pow(colour->R, 1 / space->gamma);
+ colour->G = pow(colour->G, 1 / space->gamma);
+ colour->B = pow(colour->B, 1 / space->gamma);
+ } else {
+ colour->R = REGULAR(space, colour->R);
+ colour->G = REGULAR(space, colour->G);
+ colour->B = REGULAR(space, colour->B);
+ }
+ colour->R *= r_sign;
+ colour->G *= g_sign;
+ colour->B *= b_sign;
+ break;
+ case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
+ colour->R = (space->to_encoded_red)(colour->R);
+ colour->G = (space->to_encoded_green)(colour->G);
+ colour->B = (space->to_encoded_blue)(colour->B);
+ break;
+ default:
+ fprintf(stderr, "libcolour: invalid encoding type\n");
+ abort();
+ }
+}
+
+static void rgb_decode(libcolour_rgb_t* restrict colour, const libcolour_rgb_t* restrict space)
+{
+ double r_sign = 1, g_sign = 1, b_sign = 1;
+ switch (space->encoding_type) {
+ case LIBCOLOUR_ENCODING_TYPE_LINEAR:
+ break;
+ case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
+ case LIBCOLOUR_ENCODING_TYPE_REGULAR:
+ if (colour->R < 0) r_sign = -1, colour->R = -colour->R;
+ if (colour->G < 0) g_sign = -1, colour->G = -colour->G;
+ if (colour->B < 0) b_sign = -1, colour->B = -colour->B;
+ if (space->encoding_type == LIBCOLOUR_ENCODING_TYPE_SIMPLE) {
+ colour->R = pow(colour->R, space->gamma);
+ colour->G = pow(colour->G, space->gamma);
+ colour->B = pow(colour->B, space->gamma);
+ } else {
+ colour->R = INVREGULAR(space, colour->R);
+ colour->G = INVREGULAR(space, colour->G);
+ colour->B = INVREGULAR(space, colour->B);
+ }
+ colour->R *= r_sign;
+ colour->G *= g_sign;
+ colour->B *= b_sign;
+ break;
+ case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
+ colour->R = (space->to_decoded_red)(colour->R);
+ colour->G = (space->to_decoded_green)(colour->G);
+ colour->B = (space->to_decoded_blue)(colour->B);
+ break;
+ default:
+ fprintf(stderr, "libcolour: invalid encoding type\n");
+ abort();
+ }
+}
+
+#undef REGULAR
+#undef INVREGULAR
+
+static int rgb_same_gamma(const libcolour_rgb_t* restrict a, const libcolour_rgb_t* restrict b)
+{
+ if (a->encoding_type != b->encoding_type)
+ return 0;
+ switch (a->encoding_type) {
+ case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
+ return a->gamma == b->gamma;
+ case LIBCOLOUR_ENCODING_TYPE_REGULAR:
+ return a->gamma == b->gamma &&
+ a->offset == b->offset &&
+ a->slope == b->slope &&
+ a->transition == b->transition;
+ case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
+ return a->to_encoded_red == b->to_encoded_red &&
+ a->to_encoded_green == b->to_encoded_green &&
+ a->to_encoded_blue == b->to_encoded_blue &&
+ a->to_decoded_red == b->to_decoded_red &&
+ a->to_decoded_green == b->to_decoded_green &&
+ a->to_decoded_blue == b->to_decoded_blue;
+ default:
+ return 1;
+ }
+}
+
static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* restrict to)
{
int have_gamma = 0, with_gamma = to->with_gamma;
@@ -64,7 +164,11 @@ static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* res
case LIBCOLOUR_RGB:
if (!memcmp(from->rgb.M, to->M, sizeof(double[3][3]))) {
have_gamma = from->rgb.with_gamma;
- *to = from->rgb;
+ to->R = from->rgb.R;
+ to->G = from->rgb.G;
+ to->B = from->rgb.B;
+ if (have_gamma && with_gamma && !rgb_same_gamma(&from->rgb, to))
+ rgb_decode(to, &from->rgb), have_gamma = 0;
break;
}
/* fall through */
@@ -77,51 +181,9 @@ static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* res
if (have_gamma != with_gamma) {
if (with_gamma) {
- switch (to->encoding_type) {
- case LIBCOLOUR_ENCODING_TYPE_LINEAR:
- break;
- case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
- to->R = pow(to->R, 1 / to->gamma);
- to->G = pow(to->G, 1 / to->gamma);
- to->B = pow(to->B, 1 / to->gamma);
- break;
- case LIBCOLOUR_ENCODING_TYPE_REGULAR:
- to->R = to->R <= to->transition ? to->slope * to->R : (1 + to->offset) * pow(to->R, 1 / to->gamma) - to->offset;
- to->G = to->G <= to->transition ? to->slope * to->G : (1 + to->offset) * pow(to->G, 1 / to->gamma) - to->offset;
- to->B = to->B <= to->transition ? to->slope * to->B : (1 + to->offset) * pow(to->B, 1 / to->gamma) - to->offset;
- break;
- case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
- to->R = (to->to_encoded_red)(to->R);
- to->G = (to->to_encoded_green)(to->G);
- to->B = (to->to_encoded_blue)(to->B);
- break;
- default:
- fprintf(stderr, "libcolour: invalid encoding type\n");
- abort();
- }
+ rgb_encode(to, to);
} else {
- switch (to->encoding_type) {
- case LIBCOLOUR_ENCODING_TYPE_LINEAR:
- break;
- case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
- to->R = pow(to->R, to->gamma);
- to->G = pow(to->G, to->gamma);
- to->B = pow(to->B, to->gamma);
- break;
- case LIBCOLOUR_ENCODING_TYPE_REGULAR:
- to->R = to->R <= to->transitioninv ? to->R * to->slope : pow((to->R + to->offset) / (1 + to->offset), to->gamma);
- to->G = to->G <= to->transitioninv ? to->G * to->slope : pow((to->G + to->offset) / (1 + to->offset), to->gamma);
- to->B = to->B <= to->transitioninv ? to->B * to->slope : pow((to->B + to->offset) / (1 + to->offset), to->gamma);
- break;
- case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
- to->R = (to->to_decoded_red)(to->R);
- to->G = (to->to_decoded_green)(to->G);
- to->B = (to->to_decoded_blue)(to->B);
- break;
- default:
- fprintf(stderr, "libcolour: invalid encoding type\n");
- abort();
- }
+ rgb_decode(to, &from->rgb);
}
}
}
@@ -155,7 +217,7 @@ static inline double srgb_decode(double t)
t = -t;
sign = -1;
}
- t = t <= 0.040448236277380506 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4);
+ t = t <= 0.0031306684425217108 * 12.92 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4);
return t * sign;
}
diff --git a/src/libcolour.c b/src/libcolour.c
index 69014d3..867e280 100644
--- a/src/libcolour.c
+++ b/src/libcolour.c
@@ -44,7 +44,7 @@ double libcolour_srgb_decode(double t)
t = -t;
sign = -1;
}
- t = t <= 0.040448236277380506 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4);
+ t = t <= 0.0031306684425217108 * 12.92 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4);
return t * sign;
}
diff --git a/src/test.c b/src/test.c
index 795333f..4dc649a 100644
--- a/src/test.c
+++ b/src/test.c
@@ -18,6 +18,7 @@
#include <math.h>
#include <stdio.h>
+#include <string.h>
#ifndef SKIP_CONVERT
@@ -319,8 +320,10 @@ static int test_rgb_(enum libcolour_rgb_colour_space colour_space, const char* n
int main(int argc, char* argv[])
{
int r, rc = 0;
- libcolour_colour_t c1, c2;
+ libcolour_colour_t c1, c2, c3, c4;
double t1, t2;
+ size_t n;
+ char buf[sizeof(int) + sizeof(libcolour_rgb_t)];
#ifndef SKIP_CONVERT
r = test_convert_nm_all();
@@ -436,9 +439,6 @@ int main(int argc, char* argv[])
0.294559, 0.228864, 0.742689, 0.294559, 0.228864, 0.742689);
/*
- TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MEASUREMENTS
- TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MATRIX
- TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_INV_MATRIX
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_D65
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_THEATER
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_625_LINE
@@ -453,17 +453,125 @@ int main(int argc, char* argv[])
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_HLG
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_SGI_RGB
TODO test LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_240M_RGB
+
+ TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MEASUREMENTS
+ TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MATRIX
+ TODO test LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_INV_MATRIX
*/
/* TODO test transfer functions more rigorously */
+ c1.model = c2.model = LIBCOLOUR_RGB;
+ c3.model = c4.model = LIBCOLOUR_SRGB;
+ c1.rgb.with_gamma = c3.srgb.with_gamma = 0;
+ c2.rgb.with_gamma = c4.srgb.with_gamma = 1;
+ if (libcolour_get_rgb_colour_space(&c1.rgb, LIBCOLOUR_RGB_COLOUR_SPACE_SRGB))
+ goto fail;
+ if (libcolour_get_rgb_colour_space(&c2.rgb, LIBCOLOUR_RGB_COLOUR_SPACE_SRGB))
+ goto fail;
+ for (t1 = 0; t1 <= 1; t1 += 0.001) {
+ c1.rgb.R = c3.srgb.R = t1 - 1;
+ c1.rgb.G = c3.srgb.G = t1;
+ c1.rgb.B = c3.srgb.B = t1 + 1;
+ if (libcolour_convert(&c1, &c2))
+ goto fail;
+ if (libcolour_convert(&c3, &c4))
+ goto fail;
+ if (!ftest(c2.rgb.R, c4.srgb.R, 0.00000000001) ||
+ !ftest(c2.rgb.G, c4.srgb.G, 0.00000000001) ||
+ !ftest(c2.rgb.B, c4.srgb.B, 0.00000000001) ||
+ !ftest(libcolour_srgb_encode(c1.rgb.R), c2.srgb.R, 0.00000000001) ||
+ !ftest(libcolour_srgb_encode(c1.rgb.G), c2.srgb.G, 0.00000000001) ||
+ !ftest(libcolour_srgb_encode(c1.rgb.B), c2.srgb.B, 0.00000000001)) {
+ printf("libcolour_srgb_encode failed\n"), rc = 0;
+ goto colour_spaces_done;
+ }
+ if (libcolour_convert(&c2, &c1))
+ goto fail;
+ if (libcolour_convert(&c4, &c3))
+ goto fail;
+ if (!ftest(c1.rgb.R, c3.srgb.R, 0.00000000001) ||
+ !ftest(c1.rgb.G, c3.srgb.G, 0.00000000001) ||
+ !ftest(c1.rgb.B, c3.srgb.B, 0.00000000001) ||
+ !ftest(libcolour_srgb_decode(c2.rgb.R), c1.srgb.R, 0.00000000001) ||
+ !ftest(libcolour_srgb_decode(c2.rgb.G), c1.srgb.G, 0.00000000001) ||
+ !ftest(libcolour_srgb_decode(c2.rgb.B), c1.srgb.B, 0.00000000001)) {
+ printf("%.30lf -> %.30lf\n%.30lf -> %.30lf\n%.30lf -> %.30lf\n",
+ c2.rgb.R, c1.rgb.R, c4.srgb.R, c3.srgb.R, c2.rgb.R, libcolour_srgb_decode(c2.rgb.R));
+ printf("libcolour_srgb_decode failed\n"), rc = 0;
+ goto colour_spaces_done;
+ }
+ }
+
+ c1.rgb.encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE;
+ c1.rgb.gamma = 2.2;
+ c1.rgb.with_gamma = 0;
+ c1.rgb.R = 0.25;
+ c1.rgb.G = 0.5;
+ c1.rgb.B = 0.75;
+ c4 = c3 = c2 = c1;
+ c2.rgb.with_gamma = c3.srgb.with_gamma = 1;
+ c3.rgb.gamma = c4.rgb.gamma = 1.8;
+ if (libcolour_convert(&c1, &c2))
+ goto fail;
+ if (libcolour_convert(&c2, &c3))
+ goto fail;
+ if (libcolour_convert(&c3, &c4))
+ goto fail;
+ if (!ftest(c1.rgb.R, c4.srgb.R, 0.0000001) ||
+ !ftest(c1.rgb.G, c4.srgb.G, 0.0000001) ||
+ !ftest(c1.rgb.B, c4.srgb.B, 0.0000001)) {
+ printf("libcolour_convert failed to convert between two transfer functions\n"), rc = 0;
+ goto colour_spaces_done;
+ }
+
+ if (libcolour_convert(&c1, &c4))
+ goto fail;
+ if (!ftest(c1.rgb.R, c4.srgb.R, 0.0000001) ||
+ !ftest(c1.rgb.G, c4.srgb.G, 0.0000001) ||
+ !ftest(c1.rgb.B, c4.srgb.B, 0.0000001)) {
+ printf("libcolour_convert failed to convert when two different transfer functions are not applied\n"), rc = 0;
+ goto colour_spaces_done;
+ }
+
/* TODO test libcolour_convert with single conversions */
colour_spaces_done:
- /* TODO test libcolour_srgb_encode */
- /* TODO test libcolour_srgb_decode */
- /* TODO test libcolour_marshal */
- /* TODO test libcolour_unmarshal */
+ memset(&c1, 0, sizeof(c1));
+ memset(&c2, 0, sizeof(c2));
+ c1.model = LIBCOLOUR_RGB;
+ if (libcolour_get_rgb_colour_space(&c1.rgb, LIBCOLOUR_RGB_COLOUR_SPACE_ECI_RGB_V2))
+ goto fail;
+ c3 = c1;
+ c1.rgb.to_encoded_red = NULL;
+ c1.rgb.to_encoded_green = NULL;
+ c1.rgb.to_encoded_blue = NULL;
+ c1.rgb.to_decoded_red = NULL;
+ c1.rgb.to_decoded_green = NULL;
+ c1.rgb.to_decoded_blue = NULL;
+ if (libcolour_marshal(&c1, NULL) > sizeof(buf)) {
+ printf("libcolour_marshal failed\n"), rc = 0;
+ goto marshal_done;
+ }
+ n = libcolour_marshal(&c1, buf);
+ if (n > sizeof(buf)) {
+ printf("libcolour_marshal failed\n"), rc = 0;
+ goto marshal_done;
+ }
+ if (libcolour_unmarshal(NULL, buf) != n) {
+ printf("libcolour_unmarshal failed\n"), rc = 0;
+ goto marshal_done;
+ }
+ if (libcolour_unmarshal(&c2, buf) != n) {
+ printf("libcolour_unmarshal failed\n"), rc = 0;
+ goto marshal_done;
+ }
+ if (memcmp(&c2, &c3, sizeof(c2))) {
+ printf("libcolour_(un)marshal failed\n"), rc = 0;
+ goto marshal_done;
+ }
+ marshal_done:
+
return rc;
fail:
perror(*argv);