/* See LICENSE file for copyright and license details. */
static void to_rgb(const libcolour_colour_t *restrict from, libcolour_rgb_t *restrict to);
static void to_srgb(const libcolour_colour_t *restrict from, libcolour_srgb_t *restrict to);
static void to_ciexyy(const libcolour_colour_t *restrict from, libcolour_ciexyy_t *restrict to);
static void to_ciexyz(const libcolour_colour_t *restrict from, libcolour_ciexyz_t *restrict to);
static void to_cielab(const libcolour_colour_t *restrict from, libcolour_cielab_t *restrict to);
static void to_cieluv(const libcolour_colour_t *restrict from, libcolour_cieluv_t *restrict to);
static void to_cielchuv(const libcolour_colour_t *restrict from, libcolour_cielchuv_t *restrict to);
static void to_yiq(const libcolour_colour_t *restrict from, libcolour_yiq_t *restrict to);
static void to_ydbdr(const libcolour_colour_t *restrict from, libcolour_ydbdr_t *restrict to);
static void to_yuv(const libcolour_colour_t *restrict from, libcolour_yuv_t *restrict to);
static void to_ypbpr(const libcolour_colour_t *restrict from, libcolour_ypbpr_t *restrict to);
static void to_ycgco(const libcolour_colour_t *restrict from, libcolour_ycgco_t *restrict to);
static void to_cie1960ucs(const libcolour_colour_t *restrict from, libcolour_cie1960ucs_t *restrict to);
static void to_cieuvw(const libcolour_colour_t *restrict from, libcolour_cieuvw_t *restrict to);
static void
ciexyz_to_rgb(const libcolour_ciexyz_t *restrict from, libcolour_rgb_t *restrict to)
{
CIEXYZ_TO_RGB(from->X, from->Y, from->Z, to->R, to->G, to->B, to->Minv);
}
static void
rgb_encode(libcolour_rgb_t *restrict colour, const libcolour_rgb_t *restrict space)
{
TYPE r_sign = 1, g_sign = 1, b_sign = 1;
switch (space->encoding_type) {
case LIBCOLOUR_ENCODING_TYPE_LINEAR:
break;
case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
case LIBCOLOUR_ENCODING_TYPE_REGULAR:
if (colour->R < 0) r_sign = -1, colour->R = -colour->R;
if (colour->G < 0) g_sign = -1, colour->G = -colour->G;
if (colour->B < 0) b_sign = -1, colour->B = -colour->B;
if (space->encoding_type == LIBCOLOUR_ENCODING_TYPE_SIMPLE) {
colour->R = xpow(colour->R, 1 / space->GAMMA);
colour->G = xpow(colour->G, 1 / space->GAMMA);
colour->B = xpow(colour->B, 1 / space->GAMMA);
} else {
colour->R = REGULAR(space, colour->R);
colour->G = REGULAR(space, colour->G);
colour->B = REGULAR(space, colour->B);
}
colour->R *= r_sign;
colour->G *= g_sign;
colour->B *= b_sign;
break;
case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
colour->R = (space->TO_ENCODED_RED)(colour->R);
colour->G = (space->TO_ENCODED_GREEN)(colour->G);
colour->B = (space->TO_ENCODED_BLUE)(colour->B);
break;
default:
fprintf(stderr, "libcolour: invalid encoding type\n");
abort();
}
}
static void
rgb_decode(libcolour_rgb_t *restrict colour, const libcolour_rgb_t *restrict space)
{
TYPE r_sign = 1, g_sign = 1, b_sign = 1;
switch (space->encoding_type) {
case LIBCOLOUR_ENCODING_TYPE_LINEAR:
break;
case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
case LIBCOLOUR_ENCODING_TYPE_REGULAR:
if (colour->R < 0) r_sign = -1, colour->R = -colour->R;
if (colour->G < 0) g_sign = -1, colour->G = -colour->G;
if (colour->B < 0) b_sign = -1, colour->B = -colour->B;
if (space->encoding_type == LIBCOLOUR_ENCODING_TYPE_SIMPLE) {
colour->R = xpow(colour->R, space->GAMMA);
colour->G = xpow(colour->G, space->GAMMA);
colour->B = xpow(colour->B, space->GAMMA);
} else {
colour->R = INVREGULAR(space, colour->R);
colour->G = INVREGULAR(space, colour->G);
colour->B = INVREGULAR(space, colour->B);
}
colour->R *= r_sign;
colour->G *= g_sign;
colour->B *= b_sign;
break;
case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
colour->R = (space->TO_DECODED_RED)(colour->R);
colour->G = (space->TO_DECODED_GREEN)(colour->G);
colour->B = (space->TO_DECODED_BLUE)(colour->B);
break;
default:
fprintf(stderr, "libcolour: invalid encoding type\n");
abort();
}
}
static int
rgb_same_transfer(const libcolour_rgb_t *restrict a, const libcolour_rgb_t *restrict b)
{
if (a->encoding_type != b->encoding_type)
return 0;
switch (a->encoding_type) {
case LIBCOLOUR_ENCODING_TYPE_SIMPLE:
return a->GAMMA == b->GAMMA;
case LIBCOLOUR_ENCODING_TYPE_REGULAR:
return a->GAMMA == b->GAMMA &&
a->OFFSET == b->OFFSET &&
a->SLOPE == b->SLOPE &&
a->TRANSITION == b->TRANSITION;
case LIBCOLOUR_ENCODING_TYPE_CUSTOM:
return a->TO_ENCODED_RED == b->TO_ENCODED_RED &&
a->TO_ENCODED_GREEN == b->TO_ENCODED_GREEN &&
a->TO_ENCODED_BLUE == b->TO_ENCODED_BLUE &&
a->TO_DECODED_RED == b->TO_DECODED_RED &&
a->TO_DECODED_GREEN == b->TO_DECODED_GREEN &&
a->TO_DECODED_BLUE == b->TO_DECODED_BLUE;
default:
return 1;
}
}
static void
to_rgb(const libcolour_colour_t *restrict from, libcolour_rgb_t *restrict to)
{
int have_transfer = 0, with_transfer = to->with_transfer;
libcolour_ciexyz_t tmp;
switch (from->model) {
case LIBCOLOUR_CIEXYZ:
ciexyz_to_rgb(&from->ciexyz, to);
break;
case LIBCOLOUR_RGB:
if (!memcmp(from->rgb.M, to->M, sizeof(TYPE[3][3]))) {
have_transfer = from->rgb.with_transfer;
to->R = from->rgb.R;
to->G = from->rgb.G;
to->B = from->rgb.B;
if (have_transfer && with_transfer && !rgb_same_transfer(&from->rgb, to))
rgb_decode(to, &from->rgb), have_transfer = 0;
break;
}
/* fall through */
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp);
ciexyz_to_rgb(&tmp, to);
break;
}
if (have_transfer != with_transfer) {
if (with_transfer)
rgb_encode(to, to);
else
rgb_decode(to, &from->rgb);
}
}
static void
ciexyz_to_srgb(const libcolour_ciexyz_t *restrict from, libcolour_srgb_t *restrict to)
{
CIEXYZ_TO_SRGB(from->X, from->Y, from->Z, to->R, to->G, to->B);
}
static void
srgb_to_srgb(const libcolour_srgb_t *restrict from, libcolour_srgb_t *restrict to)
{
if (from->with_transfer == to->with_transfer) {
*to = *from;
} else if (to->with_transfer) {
to->R = srgb_encode(from->R);
to->G = srgb_encode(from->G);
to->B = srgb_encode(from->B);
} else {
to->R = srgb_decode(from->R);
to->G = srgb_decode(from->G);
to->B = srgb_decode(from->B);
}
}
static void
yiq_to_srgb(const libcolour_yiq_t *restrict from, libcolour_srgb_t *restrict to)
{
YIQ_TO_SRGB(from->Y, from->I, from->Q, to->R, to->G, to->B);
}
static void
ydbdr_to_srgb(const libcolour_ydbdr_t *restrict from, libcolour_srgb_t *restrict to)
{
YDBDR_TO_SRGB(from->Y, from->Db, from->Dr, to->R, to->G, to->B);
}
static void
ypbpr_to_srgb(const libcolour_ypbpr_t *restrict from, libcolour_srgb_t *restrict to)
{
YPBPR_TO_SRGB(from->Y, from->Pb, from->Pr, to->R, to->G, to->B);
}
static void
yuv_to_srgb(const libcolour_yuv_t *restrict from, libcolour_srgb_t *restrict to)
{
YUV_TO_SRGB(from->Y, from->U, from->V, to->R, to->G, to->B);
}
static void
ycgco_to_srgb(const libcolour_ycgco_t *restrict from, libcolour_srgb_t *restrict to)
{
YCGCO_TO_SRGB(from->Y, from->Cg, from->Co, to->R, to->G, to->B);
}
static void
other_to_srgb(const libcolour_colour_t *restrict from, libcolour_srgb_t *restrict to)
{
libcolour_ciexyz_t tmp;
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp);
ciexyz_to_srgb(&tmp, to);
}
static void
to_srgb(const libcolour_colour_t *restrict from, libcolour_srgb_t *restrict to)
{
libcolour_srgb_t tmp;
switch (from->model) {
case LIBCOLOUR_CIEXYZ:
ciexyz_to_srgb(&from->ciexyz, to);
break;
case LIBCOLOUR_SRGB:
srgb_to_srgb(&from->srgb, to);
return;
case LIBCOLOUR_YIQ:
yiq_to_srgb(&from->yiq, to);
break;
case LIBCOLOUR_YDBDR:
ydbdr_to_srgb(&from->ydbdr, to);
break;
case LIBCOLOUR_YPBPR:
ypbpr_to_srgb(&from->ypbpr, to);
break;
case LIBCOLOUR_YUV:
yuv_to_srgb(&from->yuv, to);
break;
case LIBCOLOUR_YCGCO:
ycgco_to_srgb(&from->ycgco, to);
break;
default:
other_to_srgb(from, to);
break;
}
if (to->with_transfer) {
tmp = *to;
tmp.with_transfer = 0;
srgb_to_srgb(&tmp, to);
}
}
static void
ciexyz_to_ciexyy(const libcolour_ciexyz_t *restrict from, libcolour_ciexyy_t *restrict to)
{
CIEXYZ_TO_CIEXYY(from->X, from->Y, from->Z, to->x, to->y, to->Y);
}
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_srgb_t tmp;
tmp.model = LIBCOLOUR_SRGB;
if (from->with_transfer) {
tmp.with_transfer = 0;
to_srgb((const libcolour_colour_t*)from, &tmp);
} else {
tmp = *from;
}
if (tmp.R == 0 && tmp.G == 0 && tmp.B == 0) {
to->x = D(0.31272660439158);
to->y = D(0.32902315240275);
to->Y = 0;
} else {
other_to_ciexyy((const libcolour_colour_t*)&tmp, to);
}
}
static void
to_ciexyy(const libcolour_colour_t *restrict from, libcolour_ciexyy_t *restrict to)
{
switch (from->model) {
case LIBCOLOUR_CIEXYY:
*to = from->ciexyy;
return;
case LIBCOLOUR_CIEXYZ:
ciexyz_to_ciexyy(&from->ciexyz, to);
return;
case LIBCOLOUR_SRGB:
srgb_to_ciexyy(&from->srgb, to);
return;
default:
other_to_ciexyy(from, to);
return;
}
}
static void
rgb_to_ciexyz(const libcolour_rgb_t *restrict from, libcolour_ciexyz_t *restrict to)
{
libcolour_rgb_t tmp;
TYPE R, G, B;
if (from->with_transfer) {
tmp = *from;
tmp.with_transfer = 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;
}
RGB_TO_CIEXYZ(R, G, B, to->X, to->Y, to->Z, from->M);
}
static void
srgb_to_ciexyz(const libcolour_srgb_t *restrict from, libcolour_ciexyz_t *restrict to)
{
libcolour_srgb_t tmp;
TYPE R, G, B;
if (from->with_transfer) {
tmp.model = LIBCOLOUR_SRGB;
tmp.with_transfer = 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;
}
SRGB_TO_CIEXYZ(R, G, B, to->X, to->Y, to->Z);
}
static void
ciexyy_to_ciexyz(const libcolour_ciexyy_t *restrict from, libcolour_ciexyz_t *restrict to)
{
CIEXYY_TO_CIEXYZ(from->x, from->y, from->Y, to->X, to->Y, to->Z);
}
static void
cielab_to_ciexyz(const libcolour_cielab_t *restrict from, libcolour_ciexyz_t *restrict to)
{
CIELAB_TO_CIEXYZ(from->L, from->a, from->b, to->X, to->Y, to->Z);
}
static void
cieluv_to_ciexyz(const libcolour_cieluv_t *restrict from, libcolour_ciexyz_t *restrict to)
{
CIELUV_TO_CIEXYZ(from->L, from->u, from->v, to->X, to->Y, to->Z,
from->white.X, from->white.Y, from->white.Z);
}
static void
cielchuv_to_ciexyz(const libcolour_cielchuv_t *restrict from, libcolour_ciexyz_t *restrict 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
yiq_to_ciexyz(const libcolour_yiq_t *restrict from, libcolour_ciexyz_t *restrict to)
{
YIQ_TO_CIEXYZ(from->Y, from->I, from->Q, to->X, to->Y, to->Z);
}
static void
ydbdr_to_ciexyz(const libcolour_ydbdr_t *restrict from, libcolour_ciexyz_t *restrict to)
{
YDBDR_TO_CIEXYZ(from->Y, from->Db, from->Dr, to->X, to->Y, to->Z);
}
static void
yuv_to_ciexyz(const libcolour_yuv_t *restrict from, libcolour_ciexyz_t *restrict to)
{
YUV_TO_CIEXYZ(from->Y, from->U, from->V, to->X, to->Y, to->Z);
}
static void
ypbpr_to_ciexyz(const libcolour_ypbpr_t *restrict from, libcolour_ciexyz_t *restrict to)
{
YPBPR_TO_CIEXYZ(from->Y, from->Pb, from->Pr, to->X, to->Y, to->Z);
}
static void
ycgco_to_ciexyz(const libcolour_ycgco_t *restrict from, libcolour_ciexyz_t *restrict to)
{
YCGCO_TO_CIEXYZ(from->Y, from->Cg, from->Co, to->X, to->Y, to->Z);
}
static void
cie1960ucs_to_ciexyz(const libcolour_cie1960ucs_t *restrict from, libcolour_ciexyz_t *restrict to)
{
CIE1960UCS_TO_CIEXYZ(from->u, from->v, from->Y, to->X, to->Y, to->Z);
}
static void
cieuvw_to_ciexyz(const libcolour_cieuvw_t *restrict from, libcolour_ciexyz_t *restrict 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_srgb_t tmp;
tmp.model = LIBCOLOUR_SRGB;
tmp.with_transfer = 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)
{
switch (from->model) {
case LIBCOLOUR_RGB:
rgb_to_ciexyz(&from->rgb, to);
break;
case LIBCOLOUR_SRGB:
srgb_to_ciexyz(&from->srgb, to);
break;
case LIBCOLOUR_CIEXYY:
ciexyy_to_ciexyz(&from->ciexyy, to);
break;
case LIBCOLOUR_CIEXYZ:
*to = from->ciexyz;
break;
case LIBCOLOUR_CIELAB:
cielab_to_ciexyz(&from->cielab, to);
break;
case LIBCOLOUR_CIELUV:
cieluv_to_ciexyz(&from->cieluv, to);
break;
case LIBCOLOUR_CIELCHUV:
cielchuv_to_ciexyz(&from->cielchuv, to);
break;
case LIBCOLOUR_YIQ:
yiq_to_ciexyz(&from->yiq, to);
break;
case LIBCOLOUR_YDBDR:
ydbdr_to_ciexyz(&from->ydbdr, to);
break;
case LIBCOLOUR_YUV:
yuv_to_ciexyz(&from->yuv, to);
break;
case LIBCOLOUR_YPBPR:
ypbpr_to_ciexyz(&from->ypbpr, to);
break;
case LIBCOLOUR_YCGCO:
ycgco_to_ciexyz(&from->ycgco, to);
break;
case LIBCOLOUR_CIE1960UCS:
cie1960ucs_to_ciexyz(&from->cie1960ucs, to);
break;
case LIBCOLOUR_CIEUVW:
cieuvw_to_ciexyz(&from->cieuvw, to);
break;
default:
other_to_ciexyz(from, to);
break;
}
}
static void
ciexyz_to_cielab(const libcolour_ciexyz_t *restrict from, libcolour_cielab_t *restrict to)
{
CIEXYZ_TO_CIELAB(from->X, from->Y, from->Z, to->L, to->a, to->b);
}
static void
other_to_cielab(const libcolour_colour_t *restrict from, libcolour_cielab_t *restrict to)
{
libcolour_ciexyz_t tmp;
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp);
ciexyz_to_cielab(&tmp, to);
}
static void
to_cielab(const libcolour_colour_t *restrict from, libcolour_cielab_t *restrict to)
{
switch (from->model) {
case LIBCOLOUR_CIEXYZ:
ciexyz_to_cielab(&from->ciexyz, to);
return;
case LIBCOLOUR_CIELAB:
*to = from->cielab;
return;
default:
other_to_cielab(from, to);
return;
}
}
static void
ciexyz_to_cieluv(const libcolour_ciexyz_t *restrict from, libcolour_cieluv_t *restrict to)
{
CIEXYZ_TO_CIELUV(from->X, from->Y, from->Z, to->L, to->u, to->v,
to->white.X, to->white.Y, to->white.Z);
}
static void
cielchuv_to_cieluv(const libcolour_cielchuv_t *restrict from, libcolour_cieluv_t *restrict to)
{
libcolour_ciexyz_t tmp;
libcolour_cielchuv_t tmp2;
TYPE L, C, h;
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_CIELCHUV;
tmp2.white = to->white;
tmp2.one_revolution = PI2;
to_ciexyz((const libcolour_colour_t*)from, &tmp);
to_cielchuv((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 * PI2 / from->one_revolution;
}
CIELCHUV_TO_CIELUV(L, C, h, to->L, to->u, to->v);
}
static void
other_to_cieluv(const libcolour_colour_t *restrict from, libcolour_cieluv_t *restrict to)
{
libcolour_ciexyz_t tmp;
tmp.model = LIBCOLOUR_CIEXYZ;
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_CIEXYZ:
ciexyz_to_cieluv(&from->ciexyz, to);
break;
case LIBCOLOUR_CIELCHUV:
cielchuv_to_cieluv(&from->cielchuv, to);
break;
case LIBCOLOUR_CIELUV:
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;
break;
}
/* fall through */
default:
other_to_cieluv(from, to);
break;
}
}
static void
cieluv_to_cielchuv(const libcolour_cieluv_t *restrict from, libcolour_cielchuv_t *restrict to)
{
libcolour_cieluv_t tmp;
TYPE L, u, v;
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 = 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->v;
}
CIELUV_TO_CIELCHUV(L, u, v, to->L, to->C, to->h, to->one_revolution);
}
static void
other_to_cielchuv(const libcolour_colour_t *restrict from, libcolour_cielchuv_t *restrict to)
{
libcolour_cieluv_t tmp;
tmp.model = LIBCOLOUR_CIELUV;
tmp.white = to->white;
to_cieluv(from, &tmp);
cieluv_to_cielchuv(&tmp, to);
}
static void
to_cielchuv(const libcolour_colour_t *restrict from, libcolour_cielchuv_t *restrict to)
{
TYPE one_revolution;
switch (from->model) {
case LIBCOLOUR_CIELUV:
cieluv_to_cielchuv(&from->cieluv, to);
break;
case LIBCOLOUR_CIELCHUV:
if (to->white.X == from->cielchuv.white.X &&
to->white.Y == from->cielchuv.white.Y &&
to->white.Z == from->cielchuv.white.Z) {
if (to->one_revolution == from->cielchuv.one_revolution) {
*to = from->cielchuv;
} else {
one_revolution = to->one_revolution;
*to = from->cielchuv;
to->one_revolution = one_revolution;
to->h = to->h / from->cielchuv.one_revolution * one_revolution;
}
break;
}
/* fall through */
default:
other_to_cielchuv(from, to);
break;
}
}
static void
to_yiq(const libcolour_colour_t *restrict from, libcolour_yiq_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_YIQ:
*to = from->yiq;
break;
case LIBCOLOUR_SRGB:
if (tmp.srgb.with_transfer) {
tmp.srgb.with_transfer = 0;
to_srgb(from, &tmp.srgb);
}
SRGB_TO_YIQ(tmp.srgb.R, tmp.srgb.G, tmp.srgb.B, to->Y, to->I, to->Q);
break;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_YIQ(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->Y, to->I, to->Q);
break;
}
}
static void
to_ydbdr(const libcolour_colour_t *restrict from, libcolour_ydbdr_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_YDBDR:
*to = from->ydbdr;
break;
case LIBCOLOUR_SRGB:
if (tmp.srgb.with_transfer) {
tmp.srgb.with_transfer = 0;
to_srgb(from, &tmp.srgb);
}
SRGB_TO_YDBDR(tmp.srgb.R, tmp.srgb.G, tmp.srgb.B, to->Y, to->Db, to->Dr);
break;
case LIBCOLOUR_YUV:
YUV_TO_YDBDR(tmp.yuv.Y, tmp.yuv.U, tmp.yuv.V, to->Y, to->Db, to->Dr);
break;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_YDBDR(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->Y, to->Db, to->Dr);
break;
}
}
static void
to_yuv(const libcolour_colour_t *restrict from, libcolour_yuv_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_YUV:
*to = from->yuv;
break;
case LIBCOLOUR_YDBDR:
YDBDR_TO_YUV(from->ydbdr.Y, from->ydbdr.Db, from->ydbdr.Dr, to->Y, to->U, to->V);
break;
case LIBCOLOUR_SRGB:
if (tmp.srgb.with_transfer) {
tmp.srgb.with_transfer = 0;
to_srgb(from, &tmp.srgb);
}
SRGB_TO_YUV(tmp.srgb.R, tmp.srgb.G, tmp.srgb.B, to->Y, to->U, to->V);
break;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_YUV(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->Y, to->U, to->V);
break;
}
}
static void
to_ypbpr(const libcolour_colour_t *restrict from, libcolour_ypbpr_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_YPBPR:
*to = from->ypbpr;
break;
case LIBCOLOUR_SRGB:
if (tmp.srgb.with_transfer) {
tmp.srgb.with_transfer = 0;
to_srgb(from, &tmp.srgb);
}
SRGB_TO_YPBPR(tmp.srgb.R, tmp.srgb.G, tmp.srgb.B, to->Y, to->Pb, to->Pr);
break;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_YPBPR(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->Y, to->Pb, to->Pr);
break;
}
}
static void
to_ycgco(const libcolour_colour_t *restrict from, libcolour_ycgco_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_YCGCO:
*to = from->ycgco;
break;
case LIBCOLOUR_SRGB:
if (tmp.srgb.with_transfer) {
tmp.srgb.with_transfer = 0;
to_srgb(from, &tmp.srgb);
}
SRGB_TO_YCGCO(tmp.srgb.R, tmp.srgb.G, tmp.srgb.B, to->Y, to->Cg, to->Co);
break;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_YCGCO(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->Y, to->Cg, to->Co);
break;
}
}
static void
to_cie1960ucs(const libcolour_colour_t *restrict from, libcolour_cie1960ucs_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_CIE1960UCS:
*to = from->cie1960ucs;
return;
case LIBCOLOUR_CIEUVW:
CIEUVW_TO_CIE1960UCS(from->cieuvw.U, from->cieuvw.V, from->cieuvw.W,
to->u, to->v, to->Y, from->cieuvw.u0, from->cieuvw.v0);
return;
default:
tmp.model = LIBCOLOUR_CIEXYZ;
to_ciexyz(from, &tmp.ciexyz);
/* fall through */
case LIBCOLOUR_CIEXYZ:
CIEXYZ_TO_CIE1960UCS(tmp.ciexyz.X, tmp.ciexyz.Y, tmp.ciexyz.Z, to->u, to->v, to->Y);
return;
}
}
static void
to_cieuvw(const libcolour_colour_t *restrict from, libcolour_cieuvw_t *restrict to)
{
libcolour_colour_t tmp = *from;
switch (from->model) {
case LIBCOLOUR_CIEUVW:
CIEUVW_TO_CIEUVW(from->cieuvw.U, from->cieuvw.V, from->cieuvw.W, to->U, to->V, to->W,
from->cieuvw.u0, from->cieuvw.v0, to->u0, to->v0);
break;
default:
tmp.model = LIBCOLOUR_CIE1960UCS;
to_cie1960ucs(from, &tmp.cie1960ucs);
/* fall through */
case LIBCOLOUR_CIE1960UCS:
CIE1960UCS_TO_CIEUVW(tmp.cie1960ucs.u, tmp.cie1960ucs.v, tmp.cie1960ucs.Y,
to->U, to->V, to->W, to->u0, to->v0);
break;
}
}
int
libcolour_convert(const libcolour_colour_t *restrict from, libcolour_colour_t *restrict to)
{
#define X(C, T, N) 1 +
if (from->model < 0 || from->model > LIST_MODELS(X) 0) {
#undef X
errno = EINVAL;
return -1;
}
switch (to->model) {
case LIBCOLOUR_RGB:
to_rgb(from, &to->rgb);
break;
case LIBCOLOUR_SRGB:
to_srgb(from, &to->srgb);
break;
case LIBCOLOUR_CIEXYY:
to_ciexyy(from, &to->ciexyy);
break;
case LIBCOLOUR_CIEXYZ:
to_ciexyz(from, &to->ciexyz);
break;
case LIBCOLOUR_CIELAB:
to_cielab(from, &to->cielab);
break;
case LIBCOLOUR_CIELUV:
to_cieluv(from, &to->cieluv);
break;
case LIBCOLOUR_CIELCHUV:
to_cielchuv(from, &to->cielchuv);
break;
case LIBCOLOUR_YIQ:
to_yiq(from, &to->yiq);
break;
case LIBCOLOUR_YDBDR:
to_ydbdr(from, &to->ydbdr);
break;
case LIBCOLOUR_YUV:
to_yuv(from, &to->yuv);
break;
case LIBCOLOUR_YPBPR:
to_ypbpr(from, &to->ypbpr);
break;
case LIBCOLOUR_YCGCO:
to_ycgco(from, &to->ycgco);
break;
case LIBCOLOUR_CIE1960UCS:
to_cie1960ucs(from, &to->cie1960ucs);
break;
case LIBCOLOUR_CIEUVW:
to_cieuvw(from, &to->cieuvw);
break;
default:
errno = EINVAL;
return -1;
}
return 0;
}