diff options
-rw-r--r-- | doc/info/chap/colour-spaces.texinfo | 13 | ||||
-rw-r--r-- | doc/info/chap/functions.texinfo | 6 | ||||
-rw-r--r-- | src/convert.c | 68 | ||||
-rw-r--r-- | src/libcolour.c | 46 | ||||
-rw-r--r-- | src/libcolour.h | 84 | ||||
-rw-r--r-- | src/test.c | 200 |
6 files changed, 325 insertions, 92 deletions
diff --git a/doc/info/chap/colour-spaces.texinfo b/doc/info/chap/colour-spaces.texinfo index eb26ba0..a214feb 100644 --- a/doc/info/chap/colour-spaces.texinfo +++ b/doc/info/chap/colour-spaces.texinfo @@ -403,21 +403,8 @@ function is available for your use: @table @code @item double libcolour_srgb_encode(double x) Applies the sRGB transfer function. -It's full code is -@example -return x <= 0.0031306684425217108 - ? 12.92 * x - : 1.055 * pow(x, 1 / 2.4) - 0.055; -@end example - @item double libcolour_srgb_decode(double x) Unapplies the sRGB transfer function. -It's full code is -@example -return x <= 0.040448236277380506 - ? x / 12.92 - : pow((x + 0.055) / 1.055, 2.4); -@end example @end table diff --git a/doc/info/chap/functions.texinfo b/doc/info/chap/functions.texinfo index b47a584..9ddefdf 100644 --- a/doc/info/chap/functions.texinfo +++ b/doc/info/chap/functions.texinfo @@ -18,7 +18,11 @@ Described in @ref{sRGB}. @item int libcolour_delta_e(const libcolour_colour_t*, const libcolour_colour_t*, double*) Calculates the @math{\Delta E^*_{ab}} distance -(the distance in CIE L*a*b*) of two colours. +(the distance in CIE L*a*b*) of two colours, +and outputs it to the last parameter. +Returns 0 on success and @math{-1} one error. +This function fails if and only if +@code{libcolour_convert} fails. @item int libcolour_proper(libcolour_colour_t*) Sets any member or submember that may be diff --git a/src/convert.c b/src/convert.c index 0ca9ef1..e229583 100644 --- a/src/convert.c +++ b/src/convert.c @@ -84,9 +84,9 @@ static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* res to->B = pow(to->B, 1 / to->gamma); break; case LIBCOLOUR_ENCODING_TYPE_REGULAR: - to->R <= to->transition ? to->slope * to->R : (1 + to->offset) * pow(to->R, 1 / to->gamma) - to->offset; - to->G <= to->transition ? to->slope * to->G : (1 + to->offset) * pow(to->G, 1 / to->gamma) - to->offset; - to->B <= to->transition ? to->slope * to->B : (1 + to->offset) * pow(to->B, 1 / to->gamma) - to->offset; + 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); @@ -107,9 +107,9 @@ static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* res to->B = pow(to->B, to->gamma); break; case LIBCOLOUR_ENCODING_TYPE_REGULAR: - to->R <= to->transitioninv ? to->R * to->slope : pow((to->R + to->offset) / (1 + to->offset), to->gamma); - to->G <= to->transitioninv ? to->G * to->slope : pow((to->G + to->offset) / (1 + to->offset), to->gamma); - to->B <= to->transitioninv ? to->B * to->slope : pow((to->B + to->offset) / (1 + to->offset), to->gamma); + 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); @@ -128,19 +128,33 @@ static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* res static void ciexyz_to_srgb(const libcolour_ciexyz_t* restrict from, libcolour_srgb_t* restrict to) { double X = from->X, Y = from->Y, Z = from->Z; - to->R = 3.240450 * X + -1.537140 * Y + -0.4985320 * Z; - to->G = -0.969266 * X + 1.876010 * Y + 0.0415561 * Z; - to->B = 0.0556434 * X + -0.204026 * Y + 1.0572300 * Z; +#define MULTIPLY(CX, CY, CZ) ((CX) * X + (CY) * Y + (CZ) * Z) + to->R = MULTIPLY(3.240446254647737500675930277794, -1.537134761820080575134284117667, -0.498530193022728718155178739835); + to->G = MULTIPLY(-0.969266606244679751469561779231, 1.876011959788370209167851498933, 0.041556042214430065351304932619); + to->B = MULTIPLY(0.055643503564352832235773149705, -0.204026179735960239147729566866, 1.057226567722703292062647051353); +#undef MULTIPLY } -static inline double srgb_encode(double x) +static inline double srgb_encode(double t) { - return x <= 0.0031306684425217108 ? 12.92 * x : 1.055 * pow(x, 1 / 2.4) - 0.055; + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.0031306684425217108 ? 12.92 * t : 1.055 * pow(t, 1 / 2.4) - 0.055; + return t * sign; } -static inline double srgb_decode(double x) +static inline double srgb_decode(double t) { - return x <= 0.040448236277380506 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.040448236277380506 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4); + return t * sign; } static void srgb_to_srgb(const libcolour_srgb_t* restrict from, libcolour_srgb_t* restrict to) @@ -161,9 +175,13 @@ static void srgb_to_srgb(const libcolour_srgb_t* restrict from, libcolour_srgb_t static void yiq_to_srgb(const libcolour_yiq_t* restrict from, libcolour_srgb_t* restrict to) { double Y = from->Y, I = from->I, Q = from->Q; - to->R = Y + I * 0.956 + Q * 0.621; - to->G = Y - I * 0.272 - Q * 0.647; - to->B = Y - I * 1.106 + Q * 1.703; + to->R = Y + I * 0.95629483232089407263032398986979387700557708740234 + Q * 0.62102512544472865396727456754888407886028289794922; + to->G = Y - I * 0.27212147408397735492968649850809015333652496337891 - Q * 0.64738095351761570928061928498209454119205474853516; + to->B = Y - I * 1.10698990856712820018969978264067322015762329101562 + Q * 1.70461497549882934343656870623817667365074157714844; + /* ⎛1 1000 cos 33° / 877 1000 sin 33° / 877 ⎞ + ⎜1 9500 sin 33° / 24067 - 299000 * cos 33° / 514799 -9500 cos 33° / 24067 - 299000 * sin 33° / 514799⎟ + ⎝1 -250 sin 33° / 123 250 cos 33° / 123 ⎠ + */ } static void ydbdr_to_srgb(const libcolour_ydbdr_t* restrict from, libcolour_srgb_t* restrict to) @@ -318,9 +336,11 @@ static void srgb_to_ciexyz(const libcolour_srgb_t* restrict from, libcolour_ciex } else { R = from->R, G = from->G, B = from->B; } - to->X = 0.4124564 * R + 0.3575761 * G + 0.1804375 * B; - to->Y = 0.2126729 * R + 0.7151522 * G + 0.0721750 * B; - to->Z = 0.0193339 * R + 0.1191920 * G + 0.9503041 * B; +#define MULTIPLIY(CR, CG, CB) ((CR) * R + (CG) * G + (CB) * B) + to->X = MULTIPLIY(0.412457445582367576708548995157, 0.357575865245515878143578447634, 0.180437247826399665973085006954); + to->Y = MULTIPLIY(0.212673370378408277403536885686, 0.715151730491031756287156895269, 0.072174899130559869164791564344); + to->Z = MULTIPLIY(0.019333942761673460208893260415, 0.119191955081838593666354597644, 0.950302838552371742508739771438); +#undef MULTIPLIY } static void ciexyy_to_ciexyz(const libcolour_ciexyy_t* restrict from, libcolour_ciexyz_t* restrict to) @@ -630,9 +650,13 @@ static void to_yiq(const libcolour_colour_t* restrict from, libcolour_yiq_t* res r = tmp.srgb.R; g = tmp.srgb.G; b = tmp.srgb.B; - to->Y = r * 0.29893602129377540 + g * 0.5870430744511212 + b * 0.11402090425510336; - to->I = r * 0.59594574307079930 - g * 0.2743886357457892 - b * 0.32155710732501010; - to->Q = r * 0.21149734030682846 - g * 0.5229106903029739 + b * 0.31141334999614540; + to->Y = r * 0.299 + g * 0.587 + b * 0.114; + to->I = r * 0.59571613491277464191853141528554260730743408203125 /* (0.877 cos 33°)(1 - 0.299) - (0.492 sin 33°)(-0.299) */ + - g * 0.27445283783925644716106262421817518770694732666016 /* (0.877 cos 33°)(-0.587) - (0.492 sin 33°)(-0.587) */ + - b * 0.32126329707351808373516632855171337723731994628906; /* (0.877 cos 33°)(-0.114) - (0.492 sin 33°)(1 - 0.114) */ + to->Q = r * 0.21145640212011795888713550084503367543220520019531 /* (0.877 sin 33°)(1 - 0.299) + (0.492 cos 33°)(-0.299) */ + - g * 0.52259104529161115593183239980135113000869750976562 /* (0.877 sin 33°)(-0.587) + (0.492 cos 33°)(-0.587) */ + + b * 0.31113464317149330806699936147197149693965911865234; /* (0.877 sin 33°)(-0.114) + (0.492 cos 33°)(1 - 0.114) */ return; } } diff --git a/src/libcolour.c b/src/libcolour.c index 4ccb158..60dab61 100644 --- a/src/libcolour.c +++ b/src/libcolour.c @@ -26,14 +26,26 @@ -double libcolour_srgb_encode(double x) +double libcolour_srgb_encode(double t) { - return x <= 0.0031306684425217108 ? 12.92 * x : 1.055 * pow(x, 1 / 2.4) - 0.055; + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.0031306684425217108 ? 12.92 * t : 1.055 * pow(t, 1 / 2.4) - 0.055; + return t * sign; } -double libcolour_srgb_decode(double x) +double libcolour_srgb_decode(double t) { - return x <= 0.040448236277380506 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.040448236277380506 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4); + return t * sign; } @@ -264,14 +276,24 @@ static int invert_(size_t n, double (*Minvp)[n][n], double (*Mp)[n][n]) static double transfer_function_l_star(double t) { - t = (t > 216. / 24389.) ? cbrt(t) : t * 841. / 108. + 4. / 29.; - return t * 1.16 - 0.16; + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t > 216. / 24389. ? 1.16 * cbrt(t) - 0.16 : t * 24389. / 2700.; + return t * sign; } static double invtransfer_function_l_star(double t) { - t = (t + 0.16) / 1.16; - return (t > 6. / 29.) ? t * t * t : (t - 4. / 29.) * 108 / 841; + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t > 0.08 ? (((1000000. * t + 480000.) * t + 76800.) * t + 4096.) / 1560896.0 : t * 2700. / 24389.; + return t * sign; } @@ -306,16 +328,22 @@ int libcolour_get_rgb_colour_space(libcolour_rgb_t* cs, libcolour_rgb_colour_spa case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MEASUREMENTS: if (get_matrices(cs)) return -1; + if (cs->encoding_type == LIBCOLOUR_ENCODING_TYPE_REGULAR) + cs->transitioninv = cs->transition * cs->slope; return 0; case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MATRIX: if (invert(cs->Minv, cs->M, 3) || get_primaries(cs)) return -1; + if (cs->encoding_type == LIBCOLOUR_ENCODING_TYPE_REGULAR) + cs->transitioninv = cs->transition * cs->slope; return 0; case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_INV_MATRIX: if (invert(cs->M, cs->Minv, 3) || get_primaries(cs)) return -1; + if (cs->encoding_type == LIBCOLOUR_ENCODING_TYPE_REGULAR) + cs->transitioninv = cs->transition * cs->slope; return 0; case LIBCOLOUR_RGB_COLOUR_SPACE_SRGB: @@ -377,7 +405,7 @@ int libcolour_get_rgb_colour_space(libcolour_rgb_t* cs, libcolour_rgb_colour_spa case LIBCOLOUR_RGB_COLOUR_SPACE_CIE_RGB: cs->red = XYY(0.7350, 0.2650); - cs->green = XYY(0.2640, 0.7170); + cs->green = XYY(0.2740, 0.7170); cs->blue = XYY(0.1670, 0.0090); cs->white = LIBCOLOUR_ILLUMINANT_E; cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; diff --git a/src/libcolour.h b/src/libcolour.h index c68cf11..fe53a4e 100644 --- a/src/libcolour.h +++ b/src/libcolour.h @@ -22,47 +22,49 @@ -#define LIBCOLOUR_ILLUMINANT_A (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.44757, .y = 0.40745, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_B (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34842, .y = 0.35161, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_C (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31006, .y = 0.31616, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D50 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34567, .y = 0.35850, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D55 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.33242, .y = 0.34743, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D65 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31271, .y = 0.32902, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D75 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.29902, .y = 0.31485, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_E (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 1. / 3, .y = 1. / 3, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F1 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31310, .y = 0.33727, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F2 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.37208, .y = 0.37529, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F3 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.40910, .y = 0.39430, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F4 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.44018, .y = 0.40329, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F5 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31379, .y = 0.34531, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F6 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.37790, .y = 0.38835, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F7 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31292, .y = 0.32933, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F8 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34588, .y = 0.35875, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F9 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.37417, .y = 0.37281, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F10 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34609, .y = 0.35986, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F11 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.38052, .y = 0.37713, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F12 (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.43695, .y = 0.40441, .Y = 1} - -#define LIBCOLOUR_ILLUMINANT_A_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.45117, .y = 0.40594, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_B_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34980, .y = 0.35270, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_C_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31039, .y = 0.31905, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D50_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34773, .y = 0.35952, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D55_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.33411, .y = 0.34877, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D65_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31382, .y = 0.33100, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_D75_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.29968, .y = 0.31740, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_E_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 1. / 3, .y = 1. / 3, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F1_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31811, .y = 0.33559, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F2_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.37925, .y = 0.36733, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F3_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.41761, .y = 0.38324, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F4_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.44920, .y = 0.39074, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F5_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31975, .y = 0.34246, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F6_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.38660, .y = 0.37847, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F7_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.31569, .y = 0.32960, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F8_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.34902, .y = 0.35939, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F9_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.37829, .y = 0.37045, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F10_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.35090, .y = 0.35444, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F11_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.38541, .y = 0.37123, .Y = 1} -#define LIBCOLOUR_ILLUMINANT_F12_10DEG_OBS (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = 0.44256, .y = 0.39717, .Y = 1} +#define LIBCOLOUR_ILLUMINANT__(x__, y__) (libcolour_ciexyy_t){.model = LIBCOLOUR_CIEXYY, .x = x__, .y = y__, .Y = 1} + +#define LIBCOLOUR_ILLUMINANT_A LIBCOLOUR_ILLUMINANT__(0.447573514098910552050369915378, 0.407439444306660847328060981454) +#define LIBCOLOUR_ILLUMINANT_B LIBCOLOUR_ILLUMINANT__(0.348407693041403399014654951316, 0.351617234807268863594487129376) +#define LIBCOLOUR_ILLUMINANT_C LIBCOLOUR_ILLUMINANT__(0.310058473730255412803558101587, 0.316149707523236456196968902077) +#define LIBCOLOUR_ILLUMINANT_D50 LIBCOLOUR_ILLUMINANT__(0.345668037029273123028616510055, 0.358496838937619077825047497754) +#define LIBCOLOUR_ILLUMINANT_D55 LIBCOLOUR_ILLUMINANT__(0.332424102468830251488896010414, 0.347428039087666229445261478759) +#define LIBCOLOUR_ILLUMINANT_D65 LIBCOLOUR_ILLUMINANT__(0.312726871026564878786047074755, 0.329023206641284038376227272238) +#define LIBCOLOUR_ILLUMINANT_D75 LIBCOLOUR_ILLUMINANT__(0.299022300412497055166483050925, 0.314852737888341893679466920730) +#define LIBCOLOUR_ILLUMINANT_E LIBCOLOUR_ILLUMINANT__(1. / 3, 1. / 3) +#define LIBCOLOUR_ILLUMINANT_F1 LIBCOLOUR_ILLUMINANT__(0.313062433035651010992950205036, 0.337106477918307445573731229160) +#define LIBCOLOUR_ILLUMINANT_F2 LIBCOLOUR_ILLUMINANT__(0.372068154452825539113547392844, 0.375122558203110079144693145281) +#define LIBCOLOUR_ILLUMINANT_F3 LIBCOLOUR_ILLUMINANT__(0.409090035308107391465171076561, 0.394117134255365986206243178458) +#define LIBCOLOUR_ILLUMINANT_F4 LIBCOLOUR_ILLUMINANT__(0.440181095827666568620628595454, 0.403090691158138336724903183494) +#define LIBCOLOUR_ILLUMINANT_F5 LIBCOLOUR_ILLUMINANT__(0.313756583095696484075887155996, 0.345160794752101929283583103825) +#define LIBCOLOUR_ILLUMINANT_F6 LIBCOLOUR_ILLUMINANT__(0.377882361062687466279896852939, 0.388192885537868959122675960316) +#define LIBCOLOUR_ILLUMINANT_F7 LIBCOLOUR_ILLUMINANT__(0.312852472915475354753311876266, 0.329174178033567632617462095368) +#define LIBCOLOUR_ILLUMINANT_F8 LIBCOLOUR_ILLUMINANT__(0.345805753550315952971061506105, 0.358617583214377477762724311106) +#define LIBCOLOUR_ILLUMINANT_F9 LIBCOLOUR_ILLUMINANT__(0.374105245592801061160770359493, 0.372672400924498159469067104510) +#define LIBCOLOUR_ILLUMINANT_F10 LIBCOLOUR_ILLUMINANT__(0.346086913993929323751785886998, 0.358751605952200347537939251197) +#define LIBCOLOUR_ILLUMINANT_F11 LIBCOLOUR_ILLUMINANT__(0.380537485483030235577928124258, 0.376915309293930078649026427229) +#define LIBCOLOUR_ILLUMINANT_F12 LIBCOLOUR_ILLUMINANT__(0.437023901312296902954557253906, 0.404214327891585678553809657387) + +#define LIBCOLOUR_ILLUMINANT_A_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.451173939693730152722395132514, 0.405936604212625562482230634487) +#define LIBCOLOUR_ILLUMINANT_B_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.349819801494100579564161535018, 0.352687989927865819250740742063) +#define LIBCOLOUR_ILLUMINANT_C_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.310388663270034004248998371622, 0.319050711366790695766582075521) +#define LIBCOLOUR_ILLUMINANT_D50_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.347729429961154856698613002663, 0.359522508516545380441442603114) +#define LIBCOLOUR_ILLUMINANT_D55_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.334116336430253457745465084372, 0.348766090975953568786849245953) +#define LIBCOLOUR_ILLUMINANT_D65_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.313823646938709621689866935412, 0.330998985489933561510156323493) +#define LIBCOLOUR_ILLUMINANT_D75_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.299679971345752860223399238748, 0.317403239854836705102769656150) +#define LIBCOLOUR_ILLUMINANT_E_10DEG_OBS LIBCOLOUR_ILLUMINANT__(1. / 3, 1. / 3) +#define LIBCOLOUR_ILLUMINANT_F1_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.318098801070991199502202562144, 0.335489451474129951602520804954) +#define LIBCOLOUR_ILLUMINANT_F2_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.379274832262508854174853922814, 0.367227934400669309145115448700) +#define LIBCOLOUR_ILLUMINANT_F3_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.417644682102624287267644831445, 0.383124504918675723441623404142) +#define LIBCOLOUR_ILLUMINANT_F4_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.449247699162001246087072559021, 0.390605475879083674506375700730) +#define LIBCOLOUR_ILLUMINANT_F5_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.319739939104951298443069163113, 0.342367055369128092667807550242) +#define LIBCOLOUR_ILLUMINANT_F6_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.386626908526034762658696308790, 0.378372201588893453116924092683) +#define LIBCOLOUR_ILLUMINANT_F7_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.315645637312390425766039925293, 0.329508145132134222521358424274) +#define LIBCOLOUR_ILLUMINANT_F8_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.348965563721531868424108324689, 0.359317299140994528272585739614) +#define LIBCOLOUR_ILLUMINANT_F9_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.378258900384649654480284652891, 0.370371375730762564248976786985) +#define LIBCOLOUR_ILLUMINANT_F10_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.350893389986753234666139178444, 0.354302210111646531665030579461) +#define LIBCOLOUR_ILLUMINANT_F11_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.385435391037903751776383387551, 0.371094786781121399599214782938) +#define LIBCOLOUR_ILLUMINANT_F12_10DEG_OBS LIBCOLOUR_ILLUMINANT__(0.442654456042513022584472537346, 0.397060737666593277506166259627) #define LIBCOLOUR_LIST_MODELS\ @@ -16,9 +16,11 @@ */ #include "libcolour.h" +#include <math.h> #include <stdio.h> +#ifndef SKIP_CONVERT static int test_convert(libcolour_colour_t* c1, libcolour_colour_t* c2, libcolour_colour_t* c3) { double ch1, ch2, ch3; @@ -230,6 +232,64 @@ static int test_convert_nm_all(void) return rc; #undef N } +#endif + + +static inline int ftest(double a, double b, double l) +{ + return a - l <= b && b <= a + l; +} + + +#define test_rgb(COLOUR_SPACE, ...) test_rgb_(COLOUR_SPACE, #COLOUR_SPACE, __VA_ARGS__) +static int test_rgb_(enum libcolour_rgb_colour_space colour_space, const char* name, + double r, double g, double b, double x, double y, double z, + double xx, double yy, double zz) +{ + libcolour_colour_t c1, c2; + + c1.model = LIBCOLOUR_RGB; + c2.model = LIBCOLOUR_CIEXYZ; + c1.rgb.with_gamma = 0; + c1.rgb.R = r, c1.rgb.G = g, c1.rgb.B = b; + if (libcolour_get_rgb_colour_space(&c1.rgb, colour_space) || + libcolour_convert(&c1, &c2)) { + printf("%s failed without gamma\n", name); + return 0; + } else if (!ftest(c2.ciexyz.X, x, 0.0001) || + !ftest(c2.ciexyz.Y, y, 0.0001) || + !ftest(c2.ciexyz.Z, z, 0.0001)) { + printf("%s failed without gamma\n", name); + printf("%.6lf, %.6lf, %.6lf\n", c2.ciexyz.X, c2.ciexyz.Y, c2.ciexyz.Z); + return 0; + } + + c1.model = LIBCOLOUR_RGB; + c2.model = LIBCOLOUR_CIEXYZ; + c1.rgb.with_gamma = 1; + c1.rgb.R = r, c1.rgb.G = g, c1.rgb.B = b; + if (libcolour_get_rgb_colour_space(&c1.rgb, colour_space) || + libcolour_convert(&c1, &c2)) { + printf("%s failed with gamma\n", name); + return 0; + } else if (!ftest(c2.ciexyz.X, xx, 0.0001) || + !ftest(c2.ciexyz.Y, yy, 0.0001) || + !ftest(c2.ciexyz.Z, zz, 0.0001)) { + printf("%s failed with gamma\n", name); + printf("%.6lf, %.6lf, %.6lf\n", c2.ciexyz.X, c2.ciexyz.Y, c2.ciexyz.Z); + return 0; + } + + if (libcolour_convert(&c2, &c1) || + !ftest(c1.rgb.R, r, 0.0000001) || + !ftest(c1.rgb.G, g, 0.0000001) || + !ftest(c1.rgb.B, b, 0.0000001)) { + printf("%s failed, encode\n", name); + return 0; + } + + return 1; +} /** @@ -242,23 +302,151 @@ static int test_convert_nm_all(void) int main(int argc, char* argv[]) { int r, rc = 0; + libcolour_colour_t c1, c2; + double t1, t2; +#ifndef SKIP_CONVERT r = test_convert_nm_all(); if (r < 0) goto fail; if (!r) rc = 1; +#else + (void) r; +#endif + + c1.model = LIBCOLOUR_SRGB; + c1.srgb.R = 0.02, c1.srgb.G = 0.5, c1.srgb.B = 0.9; + c1.srgb.with_gamma = 0; + c2.model = LIBCOLOUR_RGB; + c2.rgb.with_gamma = 0; + if (libcolour_get_rgb_colour_space(&c2.rgb, LIBCOLOUR_RGB_COLOUR_SPACE_SRGB)) { + printf("LIBCOLOUR_RGB_COLOUR_SPACE_SRGB failed\n"), rc = 0; + goto colour_spaces_done; + } + if (c2.rgb.white_r != 1 || c2.rgb.white_g != 1 || c2.rgb.white_b != 1 || + c2.rgb.red.model != LIBCOLOUR_CIEXYY || c2.rgb.green.model != LIBCOLOUR_CIEXYY || + c2.rgb.blue.model != LIBCOLOUR_CIEXYY || c2.rgb.white.model != LIBCOLOUR_CIEXYY || + c2.rgb.colour_space != LIBCOLOUR_RGB_COLOUR_SPACE_SRGB || c2.rgb.gamma != 2.4 || + c2.rgb.encoding_type != LIBCOLOUR_ENCODING_TYPE_REGULAR || c2.rgb.slope != 12.92 + || c2.rgb.offset != 0.055 || c2.rgb.transitioninv != c2.rgb.transition * c2.rgb.slope || + !ftest(c2.rgb.transition, 0.00313067, 0.00000001)) { + printf("LIBCOLOUR_RGB_COLOUR_SPACE_SRGB failed\n"), rc = 0; + goto colour_spaces_done; + } + t1 = c2.rgb.transition * c2.rgb.slope; + t2 = (1 + c2.rgb.offset) * pow(c2.rgb.transition, 1 / c2.rgb.gamma) - c2.rgb.offset; + if (!ftest(t1, t2, 0.0000001) || c2.rgb.white.Y != 1 || + c2.rgb.red.x != 0.64 || c2.rgb.red.y != 0.33 || !ftest(c2.rgb.red.Y, 0.21265, 0.00005) || + c2.rgb.green.x != 0.30 || c2.rgb.green.y != 0.60 || !ftest(c2.rgb.green.Y, 0.71515, 0.00005) || + c2.rgb.blue.x != 0.15 || c2.rgb.blue.y != 0.06 || !ftest(c2.rgb.blue.Y, 0.07215, 0.00005) || + !ftest(c2.rgb.white.x, 0.312727, 0.000001) || !ftest(c2.rgb.white.y, 0.329023, 0.000001) || + !ftest(c2.rgb.red.Y + c2.rgb.green.Y + c2.rgb.blue.Y, 1, 0.00000001)) { + printf("LIBCOLOUR_RGB_COLOUR_SPACE_SRGB failed\n"), rc = 0; + goto colour_spaces_done; + } + if (libcolour_convert(&c1, &c2) || + !ftest(c1.srgb.R, c2.rgb.R, 0.0000001) || + !ftest(c1.srgb.G, c2.rgb.G, 0.0000001) || + !ftest(c1.srgb.B, c2.rgb.B, 0.0000001)) { + printf("LIBCOLOUR_RGB_COLOUR_SPACE_SRGB failed\n"), rc = 0; + goto colour_spaces_done; + } + if (libcolour_convert(&c2, &c1) || + !ftest(c1.srgb.R, c2.rgb.R, 0.0000001) || + !ftest(c1.srgb.G, c2.rgb.G, 0.0000001) || + !ftest(c1.srgb.B, c2.rgb.B, 0.0000001)) { + printf("LIBCOLOUR_RGB_COLOUR_SPACE_SRGB failed\n"), rc = 0; + goto colour_spaces_done; + } + + c1.model = c2.model = LIBCOLOUR_CIELAB; + c1.cielab.L = 30, c2.cielab.L = 80; + c1.cielab.a = 40, c2.cielab.a = -10; + c1.cielab.b = -50, c2.cielab.b = -40; + if (libcolour_delta_e(&c1, &c2, &t1) || !ftest(t1, 71.4142842854285, 0.0000001)) + printf("libcolour_delta_e failed\n"), rc = 0; + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_ADOBE_RGB, 0.3, 0.2, 0.9, + 0.379497, 0.282430, 0.914245, 0.195429, 0.098925, 0.790020); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_APPLE_RGB, 0.3, 0.2, 0.9, + 0.364212, 0.282789, 0.866008, 0.221570, 0.134028, 0.773782); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_BEST_RGB, 0.3, 0.2, 0.9, + 0.345007, 0.246779, 0.736029, 0.151406, 0.064655, 0.647212); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_BETA_RGB, 0.3, 0.2, 0.9, + 0.342837, 0.253386, 0.714198, 0.146437, 0.066824, 0.623382); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_BRUCE_RGB, 0.3, 0.2, 0.9, + 0.368857, 0.276910, 0.915272, 0.191184, 0.096699, 0.791486); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_CIE_RGB, 0.3, 0.2, 0.9, + 0.389293, 0.225188, 0.892857, 0.202678, 0.044608, 0.785312); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_COLORMATCH_RGB, 0.3, 0.2, 0.9, + 0.337557, 0.274378, 0.651989, 0.186858, 0.123210, 0.581381); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_DON_RGB_4, 0.3, 0.2, 0.9, + 0.344990, 0.251411, 0.727872, 0.150504, 0.066348, 0.638058); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_ECI_RGB, 0.3, 0.2, 0.9, + 0.353021, 0.286400, 0.695202, 0.196733, 0.134157, 0.630279); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_ECI_RGB_V2, 0.3, 0.2, 0.9, + 0.353021, 0.286400, 0.695202, 0.149594, 0.097238, 0.579927); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_EKTA_SPACE_PS5, 0.3, 0.2, 0.9, + 0.320377, 0.229160, 0.713291, 0.127134, 0.043253, 0.622392); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_NTSC_RGB, 0.3, 0.2, 0.9, + 0.397081, 0.310031, 1.017821, 0.235650, 0.156675, 0.906707); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_PAL_SECAM_RGB, 0.3, 0.2, 0.9, + 0.357972, 0.272130, 0.877151, 0.208580, 0.120322, 0.769056); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_PROPHOTO_RGB, 0.3, 0.2, 0.9, + 0.294559, 0.228864, 0.742689, 0.124735, 0.072340, 0.682655); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_C_RGB, 0.3, 0.2, 0.9, + 0.363595, 0.281822, 0.890350, 0.216773, 0.131311, 0.783348); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_WIDE_GAMUT_RGB, 0.3, 0.2, 0.9, + 0.367485, 0.237631, 0.706442, 0.170318, 0.052665, 0.614915); + + rc &= test_rgb(LIBCOLOUR_RGB_COLOUR_SPACE_LIGHTROOM_RGB, 0.3, 0.2, 0.9, + 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 + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_525_LINE + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_709 + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2020 + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_PQ + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_PQ + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_PQ + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_HLG + TODO test LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_HLG + 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 transfer functions more rigorously */ + + /* TODO test libcolour_convert with single conversions */ + colour_spaces_done: /* TODO test libcolour_srgb_encode */ /* TODO test libcolour_srgb_decode */ - /* TODO test libcolour_srgb -> libcolour_rgb[srgb] */ - /* TODO test libcolour_rgb[srgb] -> libcolour_srgb */ - /* TODO test RGB colour spaces */ - /* TODO test libcolour_delta_e */ /* TODO test libcolour_marshal */ /* TODO test libcolour_unmarshal */ - /* TODO test libcolour_convert with single conversions */ - return rc; fail: perror(*argv); |