Files
argyllcms/xicc/xcam.c
2026-08-20 20:28:40 +01:00

246 lines
5.6 KiB
C

/*
* Abstract interface to color appearance model transforms.
*
* This is to allow the rest of Argyll to use a default CAM.
*
* Author: Graeme W. Gill
* Date: 25/7/2004
* Version: 1.00
*
* Copyright 2004 Graeme W. Gill
* Please refer to COPYRIGHT file for details.
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "xcam.h"
#include "cam97s3.h"
#include "cam02.h"
static void icx_cam_free(icxcam *s);
static int icx_set_view_vc(icxcam *s, icxViewCond *vc);
static int icx_set_view(icxcam *s, ViewingCondition Ev, double Wxyz[3],
double La, double Yb, double Lv, double Yf, double Yg, double Gxyz[3],
int hk, double hkscale, double mtaf, double Wxyz2[3]);
static int icx_XYZ_to_cam(struct _icxcam *s, double Jab[3], double XYZ[3]);
static int icx_cam_to_XYZ(struct _icxcam *s, double XYZ[3], double Jab[3]);
static void settrace(struct _icxcam *s, int tracev);
static void icx_cam_dump(struct _icxcam *s);
/* Return the default CAM */
icxCAM icxcam_default(void) {
// return cam_CIECAM97s3;
return cam_CIECAM02;
}
/* Return a string describing the given CAM */
char *icxcam_description(icxCAM which) {
if (which == cam_default)
which = icxcam_default();
switch(which) {
case cam_CIECAM97s3:
return "CIECAM97s3";
case cam_CIECAM02:
return "CIECAM02";
default:
break;
}
return "Unknown CAM";
}
/* Create a cam conversion object */
icxcam *new_icxcam(icxCAM which) {
icxcam *s;
if ((s = (icxcam *)calloc(1, sizeof(icxcam))) == NULL) {
fprintf(stderr,"icxcam: malloc failed allocating object\n");
return NULL;
}
/* Initialise methods */
s->del = icx_cam_free;
s->set_view_vc = icx_set_view_vc;
s->set_view = icx_set_view;
s->XYZ_to_cam = icx_XYZ_to_cam;
s->cam_to_XYZ = icx_cam_to_XYZ;
s->settrace = settrace;
s->dump = icx_cam_dump;
/* We set the default CAM here */
if (which == cam_default)
which = icxcam_default();
s->tag = which;
switch(which) {
case cam_CIECAM97s3:
if ((s->p = (void *)new_cam97s3()) == NULL) {
fprintf(stderr,"icxcam: malloc failed allocating object\n");
free(s);
return NULL;
}
break;
case cam_CIECAM02:
if ((s->p = (void *)new_cam02()) == NULL) {
fprintf(stderr,"icxcam: malloc failed allocating object\n");
free(s);
return NULL;
}
break;
default:
fprintf(stderr,"icxcam: unknown CAM type\n");
free(s);
return NULL;
}
return s;
}
static void icx_cam_free(icxcam *s) {
if (s != NULL) {
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
pp->del(pp);
break;
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
pp->del(pp);
break;
}
default:
break;
}
free(s);
}
}
static int icx_set_view_vc(
icxcam *s,
icxViewCond *vc
) {
return s->set_view(s,
vc->Ev, vc->Wxyz, vc->La, vc->Yb, vc->Lv,
vc->Yf, vc->Yg, vc->Gxyz,
vc->hk, vc->hkscale,
vc->mtaf, vc->Wxyz2);
}
static int icx_set_view(
icxcam *s,
ViewingCondition Ev, /* Enumerated Viewing Condition */
double Wxyz[3], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
double La, /* Adapting/Surround Luminance cd/m^2 */
double Yb, /* Relative Luminance of Background to reference white */
double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
/* Ignored if Ev is set to other than vc_none */
double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
double Yg, /* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
int hk, /* Flag, NZ to use Helmholtz-Kohlraush effect */
double hkscale, /* HK effect scaling factor */
double mtaf, /* Mid tone partial adapation factor from Wxyz to Wxyz2, <= 0.0 if none */
double Wxyz2[3] /* Mid tone Adapted White XYZ (Y range 0.0 .. 1.0) */
) {
s->Wxyz[0] = Wxyz[0];
s->Wxyz[1] = Wxyz[1];
s->Wxyz[2] = Wxyz[2];
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, 0.2 * Yg, Gxyz, hk);
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, Yf, Yg, Gxyz, hk, hkscale, mtaf, Wxyz2);
}
default:
break;
}
return 0;
}
/* Conversions */
static int icx_XYZ_to_cam(
struct _icxcam *s,
double Jab[3],
double XYZ[3]
) {
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
return pp->XYZ_to_cam(pp, Jab, XYZ);
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
return pp->XYZ_to_cam(pp, Jab, XYZ);
}
default:
break;
}
return 0;
}
static int icx_cam_to_XYZ(
struct _icxcam *s,
double XYZ[3],
double Jab[3]
) {
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
return pp->cam_to_XYZ(pp, XYZ, Jab);
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
return pp->cam_to_XYZ(pp, XYZ, Jab);
}
default:
break;
}
return 0;
}
/* Debug */
static void settrace(
struct _icxcam *s,
int tracev
) {
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
pp->trace = tracev;
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
pp->trace = tracev;
}
default:
break;
}
}
/* Dump the viewing conditions to stdout */
static void icx_cam_dump(struct _icxcam *s) {
switch(s->tag) {
case cam_CIECAM97s3: {
cam97s3 *pp = (cam97s3 *)s->p;
// pp->dump(pp);
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
pp->dump(pp);
}
default:
break;
}
}