diff options
author | Mattias Andrée <maandree@kth.se> | 2016-12-20 19:50:24 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2016-12-20 19:50:24 +0100 |
commit | 97b7af4ac979d2450364d10770b83ec94406ce31 (patch) | |
tree | 3b23affe6e1c994453c432c9f864571ef99c77e7 /src/convert.c | |
parent | CIELChuv: measure hue in degrees, but add parameter to change this (diff) | |
download | libcolour-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>
Diffstat (limited to '')
-rw-r--r-- | src/convert.c | 154 |
1 files changed, 108 insertions, 46 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; } |