From aac416b4b5acfa0a35804eae7b93775250a9f0c3 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 10 Dec 2016 23:56:44 +0100 Subject: misc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/libcolour.c | 808 ++++++++++++++++++++++++++++++++++++++++++-------------- src/libcolour.h | 156 ++++++++--- 2 files changed, 721 insertions(+), 243 deletions(-) diff --git a/src/libcolour.c b/src/libcolour.c index e613280..32ef6c8 100644 --- a/src/libcolour.c +++ b/src/libcolour.c @@ -18,6 +18,8 @@ #include #include +#include +#include #include @@ -52,33 +54,72 @@ static void ciexyz_to_rgb(const libcolour_ciexyz_t* restrict from, libcolour_rgb static void to_rgb(const libcolour_colour_t* restrict from, libcolour_rgb_t* restrict to) { int have_gamma = 0, with_gamma = to->with_gamma; - libcolour_colour_t tmp; + libcolour_ciexyz_t tmp; switch (from->model) { case LIBCOLOUR_CIEXYZ: ciexyz_to_rgb(&from->ciexyz, to); break; case LIBCOLOUR_RGB: - if (!memcmp(from->M, to->M, sizeof(double[3][3]))) { - have_gamma = from->with_gamma; - *to = *from; + if (!memcmp(from->rgb.M, to->M, sizeof(double[3][3]))) { + have_gamma = from->rgb.with_gamma; + *to = from->rgb; break; } /* fall through */ default: tmp.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(from, &tmp.ciexyz); - ciexyz_to_rgb(&tmp.ciexyz, to); + to_ciexyz(from, &tmp); + ciexyz_to_rgb(&tmp, to); break; } + if (have_gamma != with_gamma) { if (with_gamma) { - to->R = to->regular_gamma ? pow(to->R, 1 / to->gamma) : (to->to_encoded_red)(to->R); - to->G = to->regular_gamma ? pow(to->G, 1 / to->gamma) : (to->to_encoded_green)(to->G); - to->B = to->regular_gamma ? pow(to->B, 1 / to->gamma) : (to->to_encoded_blue)(to->B); + 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->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; + 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(); + } } else { - to->R = to->regular_gamma ? pow(to->R, to->gamma) : (to->to_decoded_red)(to->R); - to->G = to->regular_gamma ? pow(to->G, to->gamma) : (to->to_decoded_green)(to->G); - to->B = to->regular_gamma ? pow(to->B, to->gamma) : (to->to_decoded_blue)(to->B); + 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->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); + 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(); + } } } } @@ -97,13 +138,13 @@ static void srgb_to_srgb(const libcolour_srgb_t* restrict from, libcolour_srgb_t if (from->with_gamma == to->with_gamma) { *to = *from; } else if (to->with_gamma) { - from->R = libcolour_srgb_encode(to->R); - from->G = libcolour_srgb_encode(to->G); - from->B = libcolour_srgb_encode(to->B); + to->R = libcolour_srgb_encode(from->R); + to->G = libcolour_srgb_encode(from->G); + to->B = libcolour_srgb_encode(from->B); } else { - from->R = libcolour_srgb_decode(to->R); - from->G = libcolour_srgb_decode(to->G); - from->B = libcolour_srgb_decode(to->B); + to->R = libcolour_srgb_decode(from->R); + to->G = libcolour_srgb_decode(from->G); + to->B = libcolour_srgb_decode(from->B); } } @@ -141,10 +182,10 @@ static void ycgco_to_srgb(const libcolour_ycgco_t* restrict from, libcolour_srgb static void other_to_srgb(const libcolour_colour_t* restrict from, libcolour_srgb_t* restrict to) { - libcolour_colour_t tmp; + libcolour_ciexyz_t tmp; tmp.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(from, &tmp.ciexyz); - ciexyz_to_srgb(&tmp.ciexyz, to); + to_ciexyz(from, &tmp); + ciexyz_to_srgb(&tmp, to); } static void to_srgb(const libcolour_colour_t* restrict from, libcolour_srgb_t* restrict to) @@ -175,7 +216,7 @@ static void to_srgb(const libcolour_colour_t* restrict from, libcolour_srgb_t* r } if (to->with_gamma) { tmp = *to; - tmp->with_gamma = 0; + tmp.with_gamma = 0; srgb_to_srgb(&tmp, to); } } @@ -192,39 +233,39 @@ static void ciexyz_to_ciexyy(const libcolour_ciexyz_t* restrict from, libcolour_ to->x = to->y = 0; } +static void other_to_ciexyy(const libcolour_colour_t* restrict from, libcolour_ciexyy_t* restrict to) +{ + libcolour_ciexyz_t tmp; + tmp.model = LIBCOLOUR_CIEXYZ; + to_ciexyz(from, &tmp); + ciexyz_to_ciexyy(&tmp, to); +} + static void srgb_to_ciexyy(const libcolour_srgb_t* restrict from, libcolour_ciexyy_t* restrict to) { - libcolour_colour_t tmp; + libcolour_srgb_t tmp; tmp.model = LIBCOLOUR_SRGB; if (from->with_gamma) { - tmp.srgb.with_gamma = 0; - to_srgb((const libcolour_colour_t *)from, &tmp.srgb); + tmp.with_gamma = 0; + to_srgb((const libcolour_colour_t*)from, &tmp); } else { - tmp.srgb = *from; + tmp = *from; } if (tmp.R == 0 && tmp.G == 0 && tmp.B == 0) { to->x = 0.31272660439158; to->y = 0.32902315240275; to->Y = 0; } else { - other_to_ciexyy(&tmp, to); + other_to_ciexyy((const libcolour_colour_t*)&tmp, to); } } -static void other_to_ciexyy(const libcolour_colour_t* restrict from, libcolour_ciexyy_t* restrict to) -{ - libcolour_colour_t tmp; - tmp.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(from, &tmp.ciexyz); - ciexyz_to_ciexyy(&tmp.ciexyz, to); -} - static void to_ciexyy(const libcolour_colour_t* restrict from, libcolour_ciexyy_t* restrict to) { switch (from->model) { case LIBCOLOUR_CIEXYY: - *to = *from; - return + *to = from->ciexyy; + return; case LIBCOLOUR_CIEXYZ: ciexyz_to_ciexyy(&from->ciexyz, to); return; @@ -240,29 +281,29 @@ static void to_ciexyy(const libcolour_colour_t* restrict from, libcolour_ciexyy_ static void rgb_to_ciexyz(const libcolour_rgb_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; + libcolour_rgb_t tmp; double R, G, B; if (from->with_gamma) { tmp = *from; - tmp.rgb.with_gamma = 0; - to_rgb(from, &tmp); + tmp.with_gamma = 0; + to_rgb((const libcolour_colour_t*)from, &tmp); R = tmp.R, G = tmp.G, B = tmp.B; } else { R = from->R, G = from->G, B = from->B; } - to->X = to->M[0][0] * R + to->M[0][1] * G + to->M[0][2] * B; - to->Y = to->M[1][0] * R + to->M[1][1] * G + to->M[1][2] * B; - to->Z = to->M[2][0] * R + to->M[2][1] * G + to->M[2][2] * B; + to->X = from->M[0][0] * R + from->M[0][1] * G + from->M[0][2] * B; + to->Y = from->M[1][0] * R + from->M[1][1] * G + from->M[1][2] * B; + to->Z = from->M[2][0] * R + from->M[2][1] * G + from->M[2][2] * B; } static void srgb_to_ciexyz(const libcolour_srgb_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; + libcolour_srgb_t tmp; double R, G, B; if (from->with_gamma) { tmp.model = LIBCOLOUR_SRGB; - tmp.srgb.with_gamma = 0; - to_srgb(from, &tmp); + tmp.with_gamma = 0; + to_srgb((const libcolour_colour_t*)from, &tmp); R = tmp.R, G = tmp.G, B = tmp.B; } else { R = from->R, G = from->G, B = from->B; @@ -281,7 +322,7 @@ static void ciexyy_to_ciexyz(const libcolour_ciexyy_t* restrict from, libcolour_ } else { to->X = x * Yy; to->Y = Y; - to->Z = (1 - x - y) * Yy + to->Z = (1 - x - y) * Yy; } } @@ -321,19 +362,19 @@ static void cieluv_to_ciexyz(const libcolour_cieluv_t* restrict from, libcolour_ static void cielch_to_ciexyz(const libcolour_cielch_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; - tmp.model = LIBCOLOUR_YUV; - tmp.yuv.white = from.white; - to_yuv((const libcolour_colour_t*)from, &tmp.yuv); - yuv_to_ciexyz(&tmp.yuv, to); + libcolour_cieluv_t tmp; + tmp.model = LIBCOLOUR_CIELUV; + tmp.white = from->white; + to_cieluv((const libcolour_colour_t*)from, &tmp); + cieluv_to_ciexyz(&tmp, to); } static void yuv_to_ciexyz(const libcolour_yuv_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; + libcolour_ydbdr_t tmp; tmp.model = LIBCOLOUR_YDBDR; - to_ydbdr((const libcolour_colour_t*)from, &tmp.ydbdr); - ydbdr_to_ciexyz(&tmp.ydbdr, to); + to_ydbdr((const libcolour_colour_t*)from, &tmp); + to_ciexyz((const libcolour_colour_t*)&tmp, to); } static void cie1960ucs_to_ciexyz(const libcolour_cie1960ucs_t* restrict from, libcolour_ciexyz_t* restrict to) @@ -346,19 +387,19 @@ static void cie1960ucs_to_ciexyz(const libcolour_cie1960ucs_t* restrict from, li static void cieuvw_to_ciexyz(const libcolour_cieuvw_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; - tmp.model = LIBCOLOUR_CIE1969UCS; - to_cie1960ucs((const libcolour_cieuvw_t*)from, &tmp.cie1960ucs); - cie1960ucs_to_ciexyz(&tmp.cie1960ucs, to); + libcolour_cie1960ucs_t tmp; + tmp.model = LIBCOLOUR_CIE1960UCS; + to_cie1960ucs((const libcolour_colour_t*)from, &tmp); + cie1960ucs_to_ciexyz(&tmp, to); } static void other_to_ciexyz(const libcolour_colour_t* restrict from, libcolour_ciexyz_t* restrict to) { - libcolour_colour_t tmp; + libcolour_srgb_t tmp; tmp.model = LIBCOLOUR_SRGB; - tmp.srgb.with_gamma = 0; - to_srgb(from, &tmp.srgb); - srgb_to_ciexyz(&tmp.srgb, to); + tmp.with_gamma = 0; + to_srgb(from, &tmp); + srgb_to_ciexyz(&tmp, to); } static void to_ciexyz(const libcolour_colour_t* restrict from, libcolour_ciexyz_t* restrict to) @@ -366,7 +407,7 @@ static void to_ciexyz(const libcolour_colour_t* restrict from, libcolour_ciexyz_ switch (from->model) { case LIBCOLOUR_RGB: rgb_to_ciexyz(&from->rgb, to); - return + return; case LIBCOLOUR_SRGB: srgb_to_ciexyz(&from->srgb, to); return; @@ -374,7 +415,7 @@ static void to_ciexyz(const libcolour_colour_t* restrict from, libcolour_ciexyz_ ciexyy_to_ciexyz(&from->ciexyy, to); return; case LIBCOLOUR_CIEXYZ: - *to = *from + *to = from->ciexyz; return; case LIBCOLOUR_CIELAB: cielab_to_ciexyz(&from->cielab, to); @@ -419,10 +460,10 @@ static void ciexyz_to_cielab(const libcolour_ciexyz_t* restrict from, libcolour_ static void other_to_cielab(const libcolour_colour_t* restrict from, libcolour_cielab_t* restrict to) { - libcolour_colour_t tmp; + libcolour_ciexyz_t tmp; tmp.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(from, &tmp.ciexyz); - ciexyz_to_cielab(&tmp.ciexyz, to); + to_ciexyz(from, &tmp); + ciexyz_to_cielab(&tmp, to); } static void to_cielab(const libcolour_colour_t* restrict from, libcolour_cielab_t* restrict to) @@ -432,7 +473,7 @@ static void to_cielab(const libcolour_colour_t* restrict from, libcolour_cielab_ ciexyz_to_cielab(&from->ciexyz, to); return; case LIBCOLOUR_CIELAB: - *to = *from; + *to = from->cielab; return; default: other_to_cielab(from, to); @@ -443,21 +484,14 @@ static void to_cielab(const libcolour_colour_t* restrict from, libcolour_cielab_ static void ciexyz_to_cieluv(const libcolour_ciexyz_t* restrict from, libcolour_cieluv_t* restrict to) { - libcolour_ciexyz_t white; double t, u, v, y, y2; - if (to->white.model == LIBCOLOUR_CIEXYZ) { - white = to->white.ciexyz; - } else { - white.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(&to->white, &white); - } - t = white.X + 15 * white.Y + 3 * white.Z; - u = 4 * white.x / t; - v = 9 * white.y / t; + t = to->white.X + 15 * to->white.Y + 3 * to->white.Z; + u = 4 * to->white.X / t; + v = 9 * to->white.Y / t; t = from->X + 15 * from->Y + 4 * from->Z; - u = 4 * from->x / t - u; - v = 9 * from->y / t - v; - y = from->Y = white.Y; + u = 4 * from->X / t - u; + v = 9 * from->Y / t - v; + y = from->Y / to->white.Y; y2 = y * 24389; y = y2 <= 216 ? y2 / 27 : cbrt(y) * 116 - 16; to->L = y; @@ -468,28 +502,16 @@ static void ciexyz_to_cieluv(const libcolour_ciexyz_t* restrict from, libcolour_ static void cielch_to_cieluv(const libcolour_cielch_t* restrict from, libcolour_cieluv_t* restrict to) { - libcolour_ciexyz_t from_white, to_white; - libcolour_colour_t tmp, tmp2; + libcolour_ciexyz_t tmp; + libcolour_cielch_t tmp2; double L, C, h; - if (from->white.model == LIBCOLOUR_CIEXYZ) { - from_white = from->white.ciexyz; - } else { - from_white.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(&from->white, &from_white); - } - if (to->white.model == LIBCOLOUR_CIEXYZ) { - to_white = to->white.ciexyz; - } else { - to_white.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(&to->white, &to_white); - } - if (to_white.X != from_white.X || to_white.Y != from_white.Y || to_white.Z != from_white.Z) { + if (to->white.X != from->white.X || to->white.Y != from->white.Y || to->white.Z != from->white.Z) { tmp.model = LIBCOLOUR_CIEXYZ; tmp2.model = LIBCOLOUR_CIELCH; - tmp2.cielch.white.ciexyz = to_white; - to_ciexyz(from, &tmp.ciexyz); - to_cielch(&tmp, &tmp2.cielch); - L = tmp2.cielch.L, C = tmp2.cielch.C, h = tmp2.cielch.h; + tmp2.white = to->white; + to_ciexyz((const libcolour_colour_t*)from, &tmp); + to_cielch((const libcolour_colour_t*)&tmp, &tmp2); + L = tmp2.L, C = tmp2.C, h = tmp2.h; } else { L = from->L, C = from->C, h = from->h; } @@ -500,25 +522,23 @@ static void cielch_to_cieluv(const libcolour_cielch_t* restrict from, libcolour_ static void other_to_cieluv(const libcolour_colour_t* restrict from, libcolour_cieluv_t* restrict to) { - libcolour_colour_t tmp; + libcolour_ciexyz_t tmp; tmp.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(from, &tmp.ciexyz); - ciexyz_to_cieluv(&tmp.ciexyz, to); + to_ciexyz(from, &tmp); + ciexyz_to_cieluv(&tmp, to); } static void to_cieluv(const libcolour_colour_t* restrict from, libcolour_cieluv_t* restrict to) { switch (from->model) { case LIBCOLOUR_CIELCH: - cielch_to_cielab(&from->cielch, to); + cielch_to_cieluv(&from->cielch, to); return; case LIBCOLOUR_CIELUV: - if (to->cieluv.model == LIBCOLOUR_CIEXYZ && - from->cieluv.model == LIBCOLOUR_CIEXYZ && - to->cieluv.white.X == from->cieluv.white.X && - to->cieluv.white.Y == from->cieluv.white.Y && - to->cieluv.white.Z == from->cieluv.white.Z) { - *to = *from; + if (to->white.X == from->cieluv.white.X && + to->white.Y == from->cieluv.white.Y && + to->white.Z == from->cieluv.white.Z) { + *to = from->cieluv; return; } /* fall through */ @@ -531,25 +551,12 @@ static void to_cieluv(const libcolour_colour_t* restrict from, libcolour_cieluv_ static void cieluv_to_cielch(const libcolour_cieluv_t* restrict from, libcolour_cielch_t* restrict to) { - libcolour_ciexyz_t from_white, to_white; libcolour_cieluv_t tmp; double L, u, v; - if (from->white.model == LIBCOLOUR_CIEXYZ) { - from_white = from->white.ciexyz; - } else { - from_white.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(&from->white, &from_white); - } - if (to->white.model == LIBCOLOUR_CIEXYZ) { - to_white = to->white.ciexyz; - } else { - to_white.model = LIBCOLOUR_CIEXYZ; - to_ciexyz(&to->white, &to_white); - } - if (to_white.X != from_white.X || to_white.Y != from_white.Y || to_white.Z != from_white.Z) { + if (to->white.X != from->white.X || to->white.Y != from->white.Y || to->white.Z != from->white.Z) { tmp.model = LIBCOLOUR_CIELUV; - tmp.white.ciexyz = to_white; - to_cieluv(from, &tmp); + tmp.white = to->white; + to_cieluv((const libcolour_colour_t*)from, &tmp); L = tmp.L, u = tmp.u, v = tmp.v; } else { L = from->L, u = from->u, v = from->u; @@ -561,11 +568,11 @@ static void cieluv_to_cielch(const libcolour_cieluv_t* restrict from, libcolour_ static void other_to_cielch(const libcolour_colour_t* restrict from, libcolour_cielch_t* restrict to) { - libcolour_colour_t tmp; + libcolour_cieluv_t tmp; tmp.model = LIBCOLOUR_CIELUV; - tmp.white = to.white; - to_cieluv(from, &tmp.cieluv); - cieluv_to_cielch(&tmp.cieluv, to); + tmp.white = to->white; + to_cieluv(from, &tmp); + cieluv_to_cielch(&tmp, to); } static void to_cielch(const libcolour_colour_t* restrict from, libcolour_cielch_t* restrict to) @@ -575,12 +582,10 @@ static void to_cielch(const libcolour_colour_t* restrict from, libcolour_cielch_ cieluv_to_cielch(&from->cieluv, to); return; case LIBCOLOUR_CIELCH: - if (to->cielch.model == LIBCOLOUR_CIEXYZ && - from->cielch.model == LIBCOLOUR_CIEXYZ && - to->cielch.white.X == from->cielcg.white.X && - to->cielch.white.Y == from->cielch.white.Y && - to->cielch.white.Z == from->cielch.white.Z) { - *to = *from; + if (to->white.X == from->cielch.white.X && + to->white.Y == from->cielch.white.Y && + to->white.Z == from->cielch.white.Z) { + *to = from->cielch; return; } /* fall through */ @@ -597,16 +602,16 @@ static void to_yiq(const libcolour_colour_t* restrict from, libcolour_yiq_t* res libcolour_colour_t tmp = *from; switch (from->model) { case LIBCOLOUR_YIQ: - *to = *from; + *to = from->yiq; return; default: tmp.model = LIBCOLOUR_SRGB; to_srgb(from, &tmp.srgb); /* fall through */ case LIBCOLOUR_SRGB: - r = tmp->srgb.R; - g = tmp->srgb.G; - b = tmp->srgb.B; + 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; @@ -621,25 +626,26 @@ static void to_ydbdr(const libcolour_colour_t* restrict from, libcolour_ydbdr_t* libcolour_colour_t tmp = *from; switch (from->model) { case LIBCOLOUR_YDBDR: - *to = *from; + *to = from->ydbdr; return; case LIBCOLOUR_YUV: - to->Y = tmp->yuv.Y; - to->Db = tmp->yuv.U * 3.069; - to->Dr = -tmp->yuv.V * 2.169; + to->Y = tmp.yuv.Y; + to->Db = tmp.yuv.U * 3.069; + to->Dr = -tmp.yuv.V * 2.169; return; default: tmp.model = LIBCOLOUR_SRGB; to_srgb(from, &tmp.srgb); /* fall through */ case LIBCOLOUR_SRGB: - r = tmp->srgb.R; - g = tmp->srgb.G; - b = tmp->srgb.B; + r = tmp.srgb.R; + g = tmp.srgb.G; + b = tmp.srgb.B; to->Y = r * 0.299 + g * 0.587 + b * 0.114; to->Db = -r * 0.450 - g * 0.883 + b * 1.333; to->Dr = -r * 1.333 + g * 1.116 + b * 0.217; return; + } } @@ -648,7 +654,7 @@ static void to_yuv(const libcolour_colour_t* restrict from, libcolour_yuv_t* res libcolour_colour_t tmp = *from; switch (from->model) { case LIBCOLOUR_YUV: - *to = *from; + *to = from->yuv; return; default: tmp.model = LIBCOLOUR_YDBDR; @@ -659,6 +665,7 @@ static void to_yuv(const libcolour_colour_t* restrict from, libcolour_yuv_t* res to->U = tmp.ydbdr.Db / 3.069; to->V = -tmp.ydbdr.Dr / 2.169; return; + } } @@ -667,7 +674,7 @@ static void to_ypbpr(const libcolour_colour_t* restrict from, libcolour_ypbpr_t* libcolour_colour_t tmp = *from; switch (from->model) { case LIBCOLOUR_YPBPR: - *to = *from; + *to = from->ypbpr; return; default: tmp.model = LIBCOLOUR_SRGB; @@ -678,6 +685,7 @@ static void to_ypbpr(const libcolour_colour_t* restrict from, libcolour_ypbpr_t* to->Pb = tmp.srgb.B - to->Y; to->Pr = tmp.srgb.R - to->Y; return; + } } @@ -686,7 +694,7 @@ static void to_ycgco(const libcolour_colour_t* restrict from, libcolour_ycgco_t* libcolour_colour_t tmp = *from; switch (from->model) { case LIBCOLOUR_YCGCO: - *to = *from; + *to = from->ycgco; return; default: tmp.model = LIBCOLOUR_SRGB; @@ -697,6 +705,7 @@ static void to_ycgco(const libcolour_colour_t* restrict from, libcolour_ycgco_t* to->Cg = -tmp.srgb.R / 4 + tmp.srgb.G / 2 - tmp.srgb.B / 4; to->Co = tmp.srgb.R / 2 - tmp.srgb.B / 2; return; + } } @@ -706,7 +715,7 @@ static void to_cie1960ucs(const libcolour_colour_t* restrict from, libcolour_cie double u, v, w, y; switch (from->model) { case LIBCOLOUR_CIE1960UCS: - *to = *from; + *to = from->cie1960ucs; return; case LIBCOLOUR_CIEUVW: u = from->cieuvw.U, v = from->cieuvw.V, w = from->cieuvw.W; @@ -819,22 +828,22 @@ int libcolour_convert(const libcolour_colour_t* restrict from, libcolour_colour_ double libcolour_srgb_encode(double x) { - return x <= 0.0031308 ? 12.92 * x : 1.055 * pow(x, 1 / 2.4) - 0.055; + return x <= 0.0031306684425217108 ? 12.92 * x : 1.055 * pow(x, 1 / 2.4) - 0.055; } double libcolour_srgb_decode(double x) { - return x <= 0.04045 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); + return x <= 0.040448236277380506 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); } int libcolour_delta_e(const libcolour_colour_t* a, const libcolour_colour_t* b, double* e) { - libcolour_colour_t u, v; + libcolour_cielab_t u, v; u.model = v.model = LIBCOLOUR_CIELAB; - if (libcolour_convert(a, &u)) + if (libcolour_convert(a, (libcolour_colour_t*)&u)) return -1; - if (libcolour_convert(b, &v)) + if (libcolour_convert(b, (libcolour_colour_t*)&v)) return -1; u.L -= v.L, u.L *= u.L; u.a -= v.a, u.a *= u.a; @@ -890,59 +899,35 @@ static int eliminate(double** M, size_t n, size_t m) int libcolour_proper(libcolour_colour_t* colour) { libcolour_colour_t tmp, r, g, b; - double m[3][4] + double m[3][4]; switch (colour->model) { + case LIBCOLOUR_CIELUV: + colour->cieluv.white.model = LIBCOLOUR_CIEXYZ; + break; + case LIBCOLOUR_CIELCH: + colour->cielch.white.model = LIBCOLOUR_CIEXYZ; + break; case LIBCOLOUR_RGB: - if (colour->rgb.red.model != LIBCOLOUR_CIEXYY) { - tmp.model = LIBCOLOUR_CIEXYY; - libcolour_convert(&colour->rgb.red, &tmp); - colour->rgb.red = tmp; - } - if (colour->rgb.green.model != LIBCOLOUR_CIEXYY) { - tmp.model = LIBCOLOUR_CIEXYY; - libcolour_convert(&colour->rgb.green, &tmp); - colour->rgb.green = tmp; - } - if (colour->rgb.blue.model != LIBCOLOUR_CIEXYY) { - tmp.model = LIBCOLOUR_CIEXYY; - libcolour_convert(&colour->rgb.blue, &tmp); - colour->rgb.blue = tmp; - } - if (colour->rgb.white.model != LIBCOLOUR_CIEXYY) { - tmp.model = LIBCOLOUR_CIEXYY; - libcolour_convert(&colour->rgb.white, &tmp); - colour->rgb.white = tmp; - } - colour->rgb.red.ciexyy.Y = 1; - colour->rgb.green.ciexyy.Y = 1; - colour->rgb.blue.ciexyy.Y = 1; + colour->rgb.red.model = LIBCOLOUR_CIEXYY; + colour->rgb.green.model = LIBCOLOUR_CIEXYY; + colour->rgb.blue.model = LIBCOLOUR_CIEXYY; + colour->rgb.white.model = LIBCOLOUR_CIEXYY; + colour->rgb.red.Y = 1; + colour->rgb.green.Y = 1; + colour->rgb.blue.Y = 1; r.model = g.model = b.model = tmp.model = LIBCOLOUR_CIEXYZ; - libcolour_convert(&colour->rgb.red, &r); - libcolour_convert(&colour->rgb.green, &g); - libcolour_convert(&colour->rgb.blue, &b); - libcolour_convert(&colour->rgb.white, &tmp); + libcolour_convert((const libcolour_colour_t*)&colour->rgb.red, &r); + libcolour_convert((const libcolour_colour_t*)&colour->rgb.green, &g); + libcolour_convert((const libcolour_colour_t*)&colour->rgb.blue, &b); + libcolour_convert((const libcolour_colour_t*)&colour->rgb.white, &tmp); m[0][0] = r.ciexyz.X, m[0][1] = g.ciexyz.X, m[0][2] = b.ciexyz.X, m[0][3] = tmp.ciexyz.X; m[1][0] = r.ciexyz.Y, m[1][1] = g.ciexyz.Y, m[1][2] = b.ciexyz.Y, m[1][3] = tmp.ciexyz.Y; m[2][0] = r.ciexyz.Z, m[2][1] = g.ciexyz.Z, m[2][2] = b.ciexyz.Z, m[2][3] = tmp.ciexyz.Z; - if (eliminate(m, 3, 4)) + if (eliminate((double**)m, 3, 4)) return -1; - colour->rgb.red.ciexyy.Y = m[0][3]; - colour->rgb.green.ciexyy.Y = m[1][3]; - colour->rgb.blue.ciexyy.Y = m[2][3]; - break; - case LIBCOLOUR_CIELUV: - if (colour->cieluv.white.model != LIBCOLOUR_CIEXYZ) { - tmp.model = LIBCOLOUR_CIEXYZ; - libcolour_convert(&colour->cieluv.white, &tmp); - colour->cieluv.white = tmp; - } - break; - case LIBCOLOUR_CIELCH: - if (colour->cielch.white.model != LIBCOLOUR_CIEXYZ) { - tmp.model = LIBCOLOUR_CIEXYZ; - libcolour_convert(&colour->cielch.white, &tmp); - colour->cielch.white = tmp; - } + colour->rgb.red.Y = m[0][3]; + colour->rgb.green.Y = m[1][3]; + colour->rgb.blue.Y = m[2][3]; break; default: break; @@ -950,3 +935,420 @@ int libcolour_proper(libcolour_colour_t* colour) return 0; } + +static int get_primaries(libcolour_rgb_t* cs) +{ + libcolour_colour_t r, g, b, w; + double Sr, Sg, Sb; + double M[3][6]; + + r.model = g.model = b.model = w.model = LIBCOLOUR_CIEXYZ; + r.ciexyz.Y = 1; + g.ciexyz.Y = 1; + b.ciexyz.Y = 1; + + Sr = cs->M[1][0] * cs->white_r; + Sg = cs->M[1][1] * cs->white_g; + Sb = cs->M[1][2] * cs->white_b; + + r.ciexyz.X = cs->M[0][0] / Sr, r.ciexyz.Z = cs->M[2][0] / Sr; + g.ciexyz.X = cs->M[0][1] / Sg, g.ciexyz.Z = cs->M[2][1] / Sg; + b.ciexyz.X = cs->M[0][2] / Sb, b.ciexyz.Z = cs->M[2][2] / Sb; + + M[0][0] = r.ciexyz.X, M[0][1] = g.ciexyz.X, M[0][2] = b.ciexyz.X, M[0][3] = 1, M[0][4] = 0, M[0][5] = 0; + M[1][0] = r.ciexyz.Y, M[1][1] = g.ciexyz.Y, M[1][2] = b.ciexyz.Y, M[1][3] = 0, M[1][4] = 1, M[1][5] = 0; + M[2][0] = r.ciexyz.Z, M[2][1] = g.ciexyz.Z, M[2][2] = b.ciexyz.Z, M[2][3] = 0, M[2][4] = 0, M[2][5] = 1; + + if (eliminate((double**)M, 3, 6)) + return -1; + + memcpy(M[0], M[0] + 3, 3 * sizeof(double)), M[0][3] = Sr; + memcpy(M[1], M[1] + 3, 3 * sizeof(double)), M[1][3] = Sg; + memcpy(M[2], M[2] + 3, 3 * sizeof(double)), M[2][3] = Sb; + + if (eliminate((double**)M, 3, 4)) + return -1; + + w.ciexyz.X = M[0][3]; + w.ciexyz.Y = M[1][3]; + w.ciexyz.Z = M[2][3]; + + cs->red.model = LIBCOLOUR_CIEXYY; + cs->green.model = LIBCOLOUR_CIEXYY; + cs->blue.model = LIBCOLOUR_CIEXYY; + cs->white.model = LIBCOLOUR_CIEXYY; + + libcolour_convert(&r, (libcolour_colour_t*)&cs->red); + libcolour_convert(&g, (libcolour_colour_t*)&cs->green); + libcolour_convert(&b, (libcolour_colour_t*)&cs->blue); + libcolour_convert(&w, (libcolour_colour_t*)&cs->white); + + return 0; +} + + +static int get_matrices(libcolour_rgb_t* cs) +{ + libcolour_colour_t r, g, b, w; + double M[3][6]; + double Sr, Sg, Sb; + + r.model = g.model = b.model = LIBCOLOUR_CIEXYZ; + w.model = LIBCOLOUR_CIEXYY; + libcolour_convert((const libcolour_colour_t*)&cs->red, &w), w.ciexyy.Y = 1, libcolour_convert(&w, &r); + libcolour_convert((const libcolour_colour_t*)&cs->green, &w), w.ciexyy.Y = 1, libcolour_convert(&w, &g); + libcolour_convert((const libcolour_colour_t*)&cs->blue, &w), w.ciexyy.Y = 1, libcolour_convert(&w, &b); + w.model = LIBCOLOUR_CIEXYZ; + libcolour_convert((const libcolour_colour_t*)&cs->white, &w); + + M[0][0] = r.ciexyz.X, M[0][1] = g.ciexyz.X, M[0][2] = b.ciexyz.X, M[0][3] = 1, M[0][4] = 0, M[0][5] = 0; + M[1][0] = r.ciexyz.Y, M[1][1] = g.ciexyz.Y, M[1][2] = b.ciexyz.Y, M[1][3] = 0, M[1][4] = 1, M[1][5] = 0; + M[2][0] = r.ciexyz.Z, M[2][1] = g.ciexyz.Z, M[2][2] = b.ciexyz.Z, M[2][3] = 0, M[2][4] = 0, M[2][5] = 1; + + if (eliminate((double**)M, 3, 6)) + return -1; + + Sr = M[0][3] * w.ciexyz.X + M[0][4] * w.ciexyz.Y + M[0][5] * w.ciexyz.Z; + Sg = M[1][3] * w.ciexyz.X + M[1][4] * w.ciexyz.Y + M[1][5] * w.ciexyz.Z; + Sb = M[2][3] * w.ciexyz.X + M[2][4] * w.ciexyz.Y + M[2][5] * w.ciexyz.Z; + + Sr /= cs->white_r; + Sg /= cs->white_g; + Sb /= cs->white_b; + + cs->M[0][0] = Sr * r.ciexyz.X, cs->M[0][1] = Sg * g.ciexyz.X, cs->M[0][2] = Sb * b.ciexyz.X; + cs->M[1][0] = Sr * r.ciexyz.Y, cs->M[1][1] = Sg * g.ciexyz.Y, cs->M[1][2] = Sb * b.ciexyz.Y; + cs->M[2][0] = Sr * r.ciexyz.Z, cs->M[2][1] = Sg * g.ciexyz.Z, cs->M[2][2] = Sb * b.ciexyz.Z; + + memcpy(M[0], cs->M[0], 3 * sizeof(double)), M[0][3] = 1, M[0][4] = 0, M[0][5] = 0; + memcpy(M[1], cs->M[1], 3 * sizeof(double)), M[1][3] = 0, M[1][4] = 1, M[1][5] = 0; + memcpy(M[2], cs->M[2], 3 * sizeof(double)), M[2][3] = 0, M[2][4] = 0, M[2][5] = 1; + + if (eliminate((double**)M, 3, 6)) + return -1; + + memcpy(cs->Minv[0], M[0] + 3, 3 * sizeof(double)); + memcpy(cs->Minv[1], M[1] + 3, 3 * sizeof(double)); + memcpy(cs->Minv[2], M[2] + 3, 3 * sizeof(double)); + + return 0; +} + + +static int invert(double **Minv, double **M, size_t n) +{ + double J[3][6]; + size_t i; + for (i = 0; i < n; i++) { + memcpy(J[i], M[i], n * sizeof(double)); + memset(J[i] + n, 0, n * sizeof(double)); + J[i][n + i] = 1; + } + if (eliminate((double**)J, n, 2 * n)) + return -1; + for (i = 0; i < n; i++) + memcpy(M[i], J[i] + n, n * sizeof(double)); + return 0; +} + + +int libcolour_get_rgb_colour_space(libcolour_colour_t* cs_, libcolour_rgb_colour_space_t space) +{ +#define XYY(XVALUE, YVALUE) (libcolour_ciexyy_t){ .model = LIBCOLOUR_CIEXYY, .x = XVALUE, .y = YVALUE, .Y = 1} + + libcolour_rgb_t* cs = &cs_->rgb; + + switch (space) { + case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MEASUREMENTS: + if (get_matrices(cs)) + return -1; + return 0; + + case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MATRIX: + if (invert((double**)(cs->Minv), (double**)(cs->M), 3) || get_primaries(cs)) + return -1; + return 0; + + case LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_INV_MATRIX: + if (invert((double**)(cs->M), (double**)(cs->Minv), 3) || get_primaries(cs)) + return -1; + return 0; + + case LIBCOLOUR_RGB_COLOUR_SPACE_SRGB: + cs->red = XYY(0.6400, 0.3300); + cs->green = XYY(0.3000, 0.6000); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->offset = 0.055; + cs->gamma = 2.4; + cs->slope = 12.92; + cs->transition = 0.0031306684425217108; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ADOBE_RGB: + cs->red = XYY(0.6400, 0.3300); + cs->green = XYY(0.2100, 0.7100); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_APPLE_RGB: + cs->red = XYY(0.6250, 0.3400); + cs->green = XYY(0.2800, 0.5950); + cs->blue = XYY(0.1550, 0.0700); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 1.8; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_BEST_RGB: + cs->red = XYY(0.7347, 0.2653); + cs->green = XYY(0.2150, 0.7750); + cs->blue = XYY(0.1300, 0.0350); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_BETA_RGB: + cs->red = XYY(0.6888, 0.3112); + cs->green = XYY(0.1986, 0.7551); + cs->blue = XYY(0.1265, 0.0352); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_BRUCE_RGB: + cs->red = XYY(0.6400, 0.3300); + cs->green = XYY(0.2800, 0.6500); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_CIE_RGB: + cs->red = XYY(0.7350, 0.2650); + cs->green = XYY(0.2640, 0.7170); + cs->blue = XYY(0.1670, 0.0090); + cs->white = LIBCOLOUR_ILLUMINANT_E; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_COLORMATCH_RGB: + cs->red = XYY(0.6300, 0.3400); + cs->green = XYY(0.2950, 0.6050); + cs->blue = XYY(0.1500, 0.0750); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 1.8; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_D65: + cs->red = XYY(0.6380, 0.3200); + cs->green = XYY(0.2650, 0.6900); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.6; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_THEATER: + cs->red = XYY(0.6380, 0.3200); + cs->green = XYY(0.2650, 0.6900); + cs->blue = XYY(0.1500, 0.0600); + cs->white = XYY(0.314, 0.351); + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.6; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_DON_RGB_4: + cs->red = XYY(0.6960, 0.3000); + cs->green = XYY(0.2150, 0.7650); + cs->blue = XYY(0.1300, 0.0350); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ECI_RGB_V2: + cs->red = XYY(0.6700, 0.3300); + cs->green = XYY(0.2100, 0.7100); + cs->blue = XYY(0.1400, 0.0800); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_CUSTOM; /* TODO L* */ + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_EKTA_SPACE_PS5: + cs->red = XYY(0.6950, 0.3050); + cs->green = XYY(0.2600, 0.7000); + cs->blue = XYY(0.1100, 0.0050); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.2; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_625_LINE: + cs->red = XYY(0.6400, 0.3300); + cs->green = XYY(0.2900, 0.6000); + cs->blue = XYY(0.1500, 0.0060); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_525_LINE: + cs->red = XYY(0.6300, 0.3400); + cs->green = XYY(0.3100, 0.5950); + cs->blue = XYY(0.1550, 0.0700); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_709: + cs->red = XYY(0.6300, 0.3300); + cs->green = XYY(0.3000, 0.6000); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2020: + cs->red = XYY(0.7080, 0.2920); + cs->green = XYY(0.1700, 0.7970); + cs->blue = XYY(0.1310, 0.0460); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_PQ: + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_PQ: + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_PQ: + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_HLG: + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_HLG: + case LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_HLG: + cs->red = XYY(0.7080, 0.2920); + cs->green = XYY(0.1700, 0.7970); + cs->blue = XYY(0.1310, 0.0460); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_CUSTOM; + /* TODO http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-0-201607-I!!PDF-E.pdf */ + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_LIGHTROOM_RGB: + cs->red = XYY(0.7347, 0.2653); + cs->green = XYY(0.1596, 0.8404); + cs->blue = XYY(0.0366, 0.0001); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_LINEAR; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_NTSC_RGB: + cs->red = XYY(0.6700, 0.3300); + cs->green = XYY(0.2100, 0.7100); + cs->blue = XYY(0.1400, 0.0800); + cs->white = LIBCOLOUR_ILLUMINANT_C; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_PAL_SECAM_RGB: + cs->red = XYY(0.6400, 0.3300); + cs->green = XYY(0.2900, 0.6000); + cs->blue = XYY(0.1500, 0.0600); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_PROPHOTO_RGB: + cs->red = XYY(0.7347, 0.2653); + cs->green = XYY(0.1596, 0.8404); + cs->blue = XYY(0.0366, 0.0001); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 1.8; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_SGI_RGB: + cs->red = XYY(0.6250, 0.3400); + cs->green = XYY(0.2800, 0.5950); + cs->blue = XYY(0.1550, 0.0700); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 1.47; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_240M_RGB: + cs->red = XYY(0.6300, 0.3400); + cs->green = XYY(0.3100, 0.5950); + cs->blue = XYY(0.1550, 0.0700); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.1115721957735072; + cs->slope = 4.0; + cs->transition = 0.022821585552393633; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_C_RGB: + cs->red = XYY(0.6300, 0.3400); + cs->green = XYY(0.3100, 0.5950); + cs->blue = XYY(0.1550, 0.0700); + cs->white = LIBCOLOUR_ILLUMINANT_D65; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_REGULAR; + cs->gamma = 1 / 0.45; + cs->offset = 0.09929682680944; + cs->slope = 4.5; + cs->transition = 0.018053968510807; + break; + + case LIBCOLOUR_RGB_COLOUR_SPACE_WIDE_GAMUT_RGB: + cs->red = XYY(0.7350, 0.2650); + cs->green = XYY(0.1150, 0.8260); + cs->blue = XYY(0.1570, 0.0180); + cs->white = LIBCOLOUR_ILLUMINANT_D50; + cs->encoding_type = LIBCOLOUR_ENCODING_TYPE_SIMPLE; + cs->gamma = 2.19921875; + break; + + default: + errno = EINVAL; + return -1; + } + if (cs->encoding_type == LIBCOLOUR_ENCODING_TYPE_REGULAR) + cs->transitioninv = cs->transition * cs->slope; + cs->colour_space = space; + cs->white_r = cs->white_g = cs->white_b = 1; + if (get_matrices(cs) || libcolour_proper(cs_)) + return -1; + return 0; + +#undef XYY +} diff --git a/src/libcolour.h b/src/libcolour.h index f579dfb..b780c71 100644 --- a/src/libcolour.h +++ b/src/libcolour.h @@ -22,6 +22,28 @@ union libcolour_colour; +#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} + + typedef enum libcolour_model { LIBCOLOUR_RGB, LIBCOLOUR_SRGB, @@ -39,34 +61,52 @@ typedef enum libcolour_model { LIBCOLOUR_CIEUVW } libcolour_model_t; +typedef enum libcolour_encoding_type { + LIBCOLOUR_ENCODING_TYPE_LINEAR, + LIBCOLOUR_ENCODING_TYPE_SIMPLE, + LIBCOLOUR_ENCODING_TYPE_REGULAR, + LIBCOLOUR_ENCODING_TYPE_CUSTOM +} libcolour_encoding_type; + typedef enum libcolour_rgb_colour_space { + LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MEASUREMENTS, + LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_MATRIX, + LIBCOLOUR_RGB_COLOUR_SPACE_CUSTOM_FROM_INV_MATRIX, + LIBCOLOUR_RGB_COLOUR_SPACE_SRGB, + LIBCOLOUR_RGB_COLOUR_SPACE_ADOBE_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_APPLE_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_BEST_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_BETA_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_BRUCE_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_CIE_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_COLORMATCH_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_D65, + LIBCOLOUR_RGB_COLOUR_SPACE_DCI_P3_THEATER, + LIBCOLOUR_RGB_COLOUR_SPACE_DON_RGB_4, + LIBCOLOUR_RGB_COLOUR_SPACE_ECI_RGB_V2, + LIBCOLOUR_RGB_COLOUR_SPACE_EKTA_SPACE_PS5, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_625_LINE, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_601_525_LINE, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_709, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2020, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_PQ, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_PQ, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_PQ, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_EOTF_HLG, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OOTF_HLG, + LIBCOLOUR_RGB_COLOUR_SPACE_ITU_R_BT_2100_OETF_HLG, + LIBCOLOUR_RGB_COLOUR_SPACE_LIGHTROOM_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_NTSC_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_PAL_SECAM_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_PROPHOTO_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_SGI_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_240M_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_SMPTE_C_RGB, + LIBCOLOUR_RGB_COLOUR_SPACE_WIDE_GAMUT_RGB } libcolour_rgb_colour_space_t; -typedef struct libcolour_rgb { - enum libcolour_model model; - double R; - double G; - double B; - int with_gamma; - int regular_gamma; - double gamma; - union libcolour_colour red; - union libcolour_colour green; - union libcolour_colour blue; - union libcolour_colour white; - double (*to_encoded_red)(double); - double (*to_decoded_red)(double); - double (*to_encoded_green)(double); - double (*to_decoded_green)(double); - double (*to_encoded_blue)(double); - double (*to_decoded_blue)(double); - double M[3][3]; - double Minv[3][3]; - enum libcolour_rgb_colour_space colour_space; -} libcolour_srgb_t; - typedef struct libcolour_srgb { enum libcolour_model model; double R; @@ -93,25 +133,9 @@ typedef struct libcolour_cielab { enum libcolour_model model; double L; double a; - double n; + double b; } libcolour_cielab_t; -typedef struct libcolour_cieluv { - enum libcolour_model model; - double L; - double u; - double v; - union libcolour_colour white; -} libcolour_cieluv_t; - -typedef struct libcolour_cielch { - enum libcolour_model model; - double L; - double C; - double h; - union libcolour_colour white; -} libcolour_cielch_t; - typedef struct libcolour_yiq { enum libcolour_model model; double Y; @@ -163,6 +187,56 @@ typedef struct libcolour_cieuvw { double v0; } libcolour_cieuvw_t; +typedef struct libcolour_cieluv { + enum libcolour_model model; + double L; + double u; + double v; + struct libcolour_ciexyz white; +} libcolour_cieluv_t; + +typedef struct libcolour_cielch { + enum libcolour_model model; + double L; + double C; + double h; + struct libcolour_ciexyz white; +} libcolour_cielch_t; + +typedef struct libcolour_rgb { + enum libcolour_model model; + double R; + double G; + double B; + int with_gamma; + enum libcolour_encoding_type encoding_type; + double gamma; + double offset; + double slope; + double transition; + double transitioninv; + struct libcolour_ciexyy red; + struct libcolour_ciexyy green; + struct libcolour_ciexyy blue; + struct libcolour_ciexyy white; + double (*to_encoded_red)(double); + double (*to_decoded_red)(double); + double (*to_encoded_green)(double); + double (*to_decoded_green)(double); + double (*to_encoded_blue)(double); + double (*to_decoded_blue)(double); + double M[3][3]; + double Minv[3][3]; + double white_r; + double white_g; + double white_b; + enum libcolour_rgb_colour_space colour_space; +} libcolour_rgb_t; + +/* TODO LMS, L'M'S', ICtCp */ +/* TODO generic additive colour space */ +/* TODO generic subtractive colour space */ + typedef union libcolour_colour { enum libcolour_model model; @@ -189,6 +263,8 @@ double libcolour_srgb_encode(double); double libcolour_srgb_decode(double); int libcolour_delta_e(const libcolour_colour_t*, const libcolour_colour_t*, double*); int libcolour_proper(libcolour_colour_t*); +int libcolour_get_rgb_colour_space(libcolour_colour_t*, libcolour_rgb_colour_space_t); +/* TODO (un)marshal */ -- cgit v1.2.3-70-g09d2