aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2016-12-10 23:56:44 +0100
committerMattias Andrée <maandree@kth.se>2016-12-10 23:56:44 +0100
commitaac416b4b5acfa0a35804eae7b93775250a9f0c3 (patch)
tree4742e144c3ff73cb080920468fd1514695c23909 /src
parentbeginning (diff)
downloadlibcolour-aac416b4b5acfa0a35804eae7b93775250a9f0c3.tar.gz
libcolour-aac416b4b5acfa0a35804eae7b93775250a9f0c3.tar.bz2
libcolour-aac416b4b5acfa0a35804eae7b93775250a9f0c3.tar.xz
misc
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r--src/libcolour.c808
-rw-r--r--src/libcolour.h156
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 */