diff options
| -rw-r--r-- | src/libcolour.c | 808 | ||||
| -rw-r--r-- | 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 <errno.h>  #include <math.h> +#include <stdlib.h> +#include <stdio.h>  #include <string.h> @@ -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 */ | 
