From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- xicc/xcolorants.c | 768 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 768 insertions(+) create mode 100644 xicc/xcolorants.c (limited to 'xicc/xcolorants.c') diff --git a/xicc/xcolorants.c b/xicc/xcolorants.c new file mode 100644 index 0000000..84a7720 --- /dev/null +++ b/xicc/xcolorants.c @@ -0,0 +1,768 @@ + +/* + * International Color Consortium color transform expanded support + * Known colorants support. + * + * Author: Graeme W. Gill + * Date: 24/2/2002 + * Version: 1.00 + * + * Copyright 2002 Graeme W. Gill + * All rights reserved. + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + * + */ + +/* TTBD: + Would like to have some short string way of defining whether + the ink combination is additive or subtractive, instead + of just guessing. + */ + +#include +#include +#include +#include +#include "icc.h" +#include "xcolorants.h" +#include "sort.h" + +/* Colorant table for N color device characterisation. */ +/* This is ordered to match the ICC colorspace convention. */ +/* NOTE:- need to keep these in same order as ink mask */ +/* enumeration (lsb to msb), or strange things result! */ +static struct { + inkmask m; /* Mask value */ + char *c; /* 1/2 Character name */ + char *s; /* Everyday name */ + char *ps; /* Postscript colorant name */ + double aXYZ[3]; /* Rough XYZ values (0..1) for that additive colorant */ + double sXYZ[3]; /* Rough XYZ values (0..1) for that subtractive colorant */ +} icx_ink_table[] = { + { ICX_CYAN, ICX_C_CYAN, ICX_S_CYAN, ICX_PS_CYAN, + { 0.12, 0.18, 0.48 }, + { 0.12, 0.18, 0.48 } }, + { ICX_MAGENTA, ICX_C_MAGENTA, ICX_S_MAGENTA, ICX_PS_MAGENTA, + { 0.38, 0.19, 0.20 }, + { 0.38, 0.19, 0.20 } }, + { ICX_YELLOW, ICX_C_YELLOW, ICX_S_YELLOW, ICX_PS_YELLOW, + { 0.76, 0.81, 0.11 }, + { 0.76, 0.81, 0.11 } }, + { ICX_BLACK, ICX_C_BLACK, ICX_S_BLACK, ICX_PS_BLACK, + { 0.01, 0.01, 0.01 }, + { 0.04, 0.04, 0.04 } }, + { ICX_ORANGE, ICX_C_ORANGE, ICX_S_ORANGE, ICX_PS_ORANGE, + { 0.59, 0.41, 0.03 }, + { 0.59, 0.41, 0.05 } }, + { ICX_RED, ICX_C_RED, ICX_S_RED, ICX_PS_RED, + { 0.412414, 0.212642, 0.019325 }, + { 0.40, 0.21, 0.05 } }, + { ICX_GREEN, ICX_C_GREEN, ICX_S_GREEN, ICX_PS_GREEN, + { 0.357618, 0.715136, 0.119207 }, + { 0.11, 0.27, 0.21 } }, + { ICX_BLUE, ICX_C_BLUE, ICX_S_BLUE, ICX_PS_BLUE, + { 0.180511, 0.072193, 0.950770 }, + { 0.11, 0.27, 0.47 } }, + { ICX_WHITE, ICX_C_WHITE, ICX_S_WHITE, ICX_PS_WHITE, + { 0.950543, 1.0, 1.089303 }, /* D65 ? */ + { 0.9642, 1.00, 0.8249 } }, /* D50 */ + { ICX_LIGHT_CYAN, ICX_C_LIGHT_CYAN, ICX_S_LIGHT_CYAN, ICX_PS_LIGHT_CYAN, + { 0.76, 0.89, 1.08 }, + { 0.76, 0.89, 1.08 } }, + { ICX_LIGHT_MAGENTA, ICX_C_LIGHT_MAGENTA, ICX_S_LIGHT_MAGENTA, ICX_PS_LIGHT_MAGENTA, + { 0.83, 0.74, 1.02 }, + { 0.83, 0.74, 1.02 } }, + { ICX_LIGHT_YELLOW, ICX_C_LIGHT_YELLOW, ICX_S_LIGHT_YELLOW, ICX_PS_LIGHT_YELLOW, + { 0.88, 0.97, 0.72 }, + { 0.88, 0.97, 0.72 } }, + { ICX_LIGHT_BLACK, ICX_C_LIGHT_BLACK, ICX_S_LIGHT_BLACK, ICX_PS_LIGHT_BLACK, + { 0.56, 0.60, 0.65 }, + { 0.56, 0.60, 0.65 } }, + { ICX_MEDIUM_CYAN, ICX_C_MEDIUM_CYAN, ICX_S_MEDIUM_CYAN, ICX_PS_MEDIUM_CYAN, + { 0.61, 0.81, 1.07 }, + { 0.61, 0.81, 1.07 } }, + { ICX_MEDIUM_MAGENTA, ICX_C_MEDIUM_MAGENTA, ICX_S_MEDIUM_MAGENTA, ICX_PS_MEDIUM_MAGENTA, + { 0.74, 0.53, 0.97 }, + { 0.74, 0.53, 0.97 } }, + { ICX_MEDIUM_YELLOW, ICX_C_MEDIUM_YELLOW, ICX_S_MEDIUM_YELLOW, ICX_PS_MEDIUM_YELLOW, + { 0.82, 0.93, 0.40 }, + { 0.82, 0.93, 0.40 } }, + { ICX_MEDIUM_BLACK, ICX_C_MEDIUM_BLACK, ICX_S_MEDIUM_BLACK, ICX_PS_MEDIUM_BLACK, + { 0.27, 0.29, 0.31 }, + { 0.27, 0.29, 0.31 } }, + { ICX_LIGHT_LIGHT_BLACK, ICX_C_LIGHT_LIGHT_BLACK, ICX_S_LIGHT_LIGHT_BLACK, ICX_PS_LIGHT_LIGHT_BLACK, + { 0.76, 0.72, 0.65 }, /* Very rough - should substiture real numbers */ + { 0.76, 0.72, 0.65 } }, + { 0, "", "", "", { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } } +}; + + +/* Colorant table for N color device characterisation */ +static struct { + inkmask m; /* Mask combination */ + inkmask rm; /* Light ink reduced mask combination */ + icColorSpaceSignature psig; /* Appropriate primary ICC signature */ + icColorSpaceSignature ssig; /* Appropriate secondary ICC signature */ + char *desc; /* Description */ +} icx_colcomb_table[] = { + { ICX_K, ICX_K, icSigGrayData, icSigGrayData, + "Print grey" }, + { ICX_W, ICX_W, icSigGrayData, icSigGrayData, + "Video grey" }, + { ICX_IRGB, ICX_IRGB, icSigRgbData, icSigRgbData, + "Print RGB" }, + { ICX_RGB, ICX_RGB, icSigRgbData, icSigRgbData, + "Video RGB" }, + { ICX_CMYK, ICX_CMYK, icSigCmykData, icSigCmykData, + "CMYK" }, + { ICX_CMY, ICX_CMY, icSigCmyData, icSigCmyData, + "CMY" }, + { ICX_CMYKcm, ICX_CMYK, icSig6colorData, icSigMch6Data, + "CMYK + Light CM" }, + { ICX_CMYKcmk, ICX_CMYK, icSig7colorData, icSig7colorData, + "CMYK + Light CMK" }, + { ICX_CMYKRB, ICX_W, icSig6colorData, icSigMch6Data, + "CMYK + Red + Blue" }, + { ICX_CMYKOG, ICX_W, icSig6colorData, icSigMch6Data, + "CMYK + Orange + Green" }, + { ICX_CMYKcmk1k, ICX_CMYK, icSig8colorData, icSigMch8Data, + "CMYK + Light CMK + Light Light K" }, + { ICX_CMYKOGcm, ICX_CMYKOG, icSig8colorData, icSigMch8Data, + "CMYK + Orange + Green + Light CM" }, + { ICX_CMYKcm2c2m, ICX_CMYK, icSig8colorData, icSigMch8Data, + "CMYK + Light CM + Medium CM" }, + { 0, 0, 0, 0, "" } +}; + + +/* Given an ink combination mask, return the number of recognised inks in it */ +int icx_noofinks(inkmask mask) { + int i, count = 0; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask & icx_ink_table[i].m) { + count++; + } + } + return count; +} + +/* Given an ink combination mask, return the 1-2 character based string */ +/* If winv is nz, include ICX_INVERTED indicator if set */ +/* Return NULL on error. free() after use */ +char *icx_inkmask2char(inkmask mask, int winv) { + int i; + char *rv; + + if ((rv = malloc(2 * ICX_MXINKS + 1)) == NULL) + return NULL; + + *rv = '\000'; + + if (winv && (mask & ICX_INVERTED)) + strcat(rv, "i"); + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask & icx_ink_table[i].m) { + strcat(rv, icx_ink_table[i].c); + } + } + + return rv; +} + +/* Given the 1-2 character string, return the ink combination mask */ +/* Note that ICX_ADDITIVE will be guessed */ +/* Return 0 if unrecognised character in string */ +inkmask icx_char2inkmask(char *chstring) { + inkmask mask = 0; + int k, i; + char *cp; + + cp = chstring; + + for (k = 0; ; k++) { + + if (*cp == '\000') { + break; + } + + /* "Inverted" prefix ? */ + if (k == 0 && *cp == 'i') { + mask |= ICX_INVERTED; + cp++; + continue; + } + /* Colorant ? */ + for (i = 0; icx_ink_table[i].m != 0; i++) { + + if (strncmp(cp, icx_ink_table[i].c, strlen(icx_ink_table[i].c)) == 0) { + mask |= icx_ink_table[i].m; + cp += strlen(icx_ink_table[i].c); + break; + } + } + if (icx_ink_table[i].m == 0) { /* oops - unrecognised character */ + return 0; + } + } + + /* Check it out againts known combinations to guess additive */ + for (i = 0; icx_colcomb_table[i].m != 0; i++) { + if ((icx_colcomb_table[i].m & ~ICX_ADDITIVE) == mask) { + mask = icx_colcomb_table[i].m; + break; + } + } + + return mask; +} + +/* Given an ink combination mask that may contain light inks, */ +/* return the corresponding ink mask without light inks. */ +/* Return 0 if ink combination not recognised. */ +inkmask icx_ink2primary_ink(inkmask mask) { + int i; + for (i = 0; icx_colcomb_table[i].m != 0; i++) { + if (mask == icx_colcomb_table[i].m) { + return icx_colcomb_table[i].rm; + } + } + return 0; +} + + +/* Given an ink combination mask and a single ink mask, */ +/* return the index number for that ink. */ +/* Return -1 if mask1 not in mask */ +int icx_ink2index(inkmask mask, inkmask mask1) { + int i, count = 0; + + if ((mask1 & mask) == 0) + return -1; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask1 == icx_ink_table[i].m) { + return count; + } + if (mask & icx_ink_table[i].m) { + count++; + } + } + + return -1; +} + +/* Given an ink combination mask and a index number, */ +/* return the single ink mask. */ +/* Return 0 if there are no inks at that index */ +inkmask icx_index2ink(inkmask mask, int ixno) { + int i, count = 0; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask & icx_ink_table[i].m) { + if (ixno == count) + return icx_ink_table[i].m; + count++; + } + } + return 0; +} + + +/* Given a single ink mask, */ +/* return its string representation */ +char *icx_ink2string(inkmask mask) { + int i; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask == icx_ink_table[i].m) + return icx_ink_table[i].s; + } + return NULL; +} + +/* Given a single ink mask, */ +/* return its 1-2 character representation */ +char *icx_ink2char(inkmask mask) { + int i; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask == icx_ink_table[i].m) + return icx_ink_table[i].c; + } + return NULL; +} + +/* Given a single ink mask, */ +/* return its Postscript string representation */ +char *icx_ink2psstring(inkmask mask) { + int i; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (mask == icx_ink_table[i].m) + return icx_ink_table[i].ps; + } + return NULL; +} + + +/* Return an enumerated single colorant description */ +/* Return 0 if no such enumeration, single colorant mask if there is */ +inkmask icx_enum_colorant( +int no, /* Enumeration mask index */ +char **desc /* Return enumeration description */ +) { + int i; + + for (i = 0; icx_ink_table[i].m != 0; i++) { + if (i == no) { + if (desc != NULL) + *desc = icx_ink_table[i].s; + return icx_ink_table[i].m; + } + } + return 0; +} + +/* Return an enumerated colorant combination */ +/* Return 0 if no such enumeration, colorant combination mask if there is */ +inkmask icx_enum_colorant_comb( +int no, /* Enumeration mask index */ +char **desc /* Return enumeration description */ +) { + int i; + + for (i = 0; icx_colcomb_table[i].m != 0; i++) { + if (i == no) { + if (desc != NULL) + *desc = icx_colcomb_table[i].desc; + return icx_colcomb_table[i].m; + } + } + return 0; +} + + +/* Given an colorant combination mask, */ +/* check if it matches the given ICC colorspace signature. */ +/* return NZ if it does. */ +/* (We don't check colorant colors for multi-colorant devices though) */ +int icx_colorant_comb_match_icc( +inkmask mask, /* Colorant combination mask */ +icColorSpaceSignature sig /* ICC signature */ +) { + int i; + for (i = 0; icx_colcomb_table[i].m != 0; i++) { + if (mask == icx_colcomb_table[i].m) { + if (sig == icx_colcomb_table[i].psig + || sig == icx_colcomb_table[i].ssig) { + return 1; + } else { + return 0; + } + } + } + return 0; +} + +/* Given an ICC colorspace signature, return the appropriate */ +/* colorant combination mask. Return 0 if ambiguous signature. */ +inkmask icx_icc_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSignature deviceClass) { + switch (sig) { + case icSigGrayData: + if (deviceClass == icSigOutputClass) + return ICX_K; + return ICX_W; + + case icSigCmyData: + return ICX_CMY; + + case icSigRgbData: + if (deviceClass == icSigOutputClass) + return ICX_IRGB; + return ICX_RGB; + + case icSigCmykData: + return ICX_CMYK; + + default: + break; + } + return 0; +} + +/* Given an ICC colorspace signature, and a matching list */ +/* of the D50 L*a*b* colors of the colorants, return the best matching */ +/* colorant combination mask. Return 0 if not an applicable colorspace. */ +/* (Note we're not dealing with colorant order here.) */ +inkmask icx_icc_cv_to_colorant_comb( +icColorSpaceSignature sig, /* Input ICC colorspace signature */ +icProfileClassSignature deviceClass, /* Device class */ +double cvals[][3] /* Input L*a*b* colorant values */ +) { + int i, j; + int imask; + int ninks, ncol; + double slab[ICX_MXINKS][3]; + double alab[ICX_MXINKS][3]; + typedef struct { int x; double v; } mchstr; + mchstr mch[MAX_CHAN][ICX_MXINKS]; /* match index */ + int used[ICX_MXINKS]; + int co[ICX_MXINKS]; /* Combination counter */ + double cmv; /* Combination match value */ + int bco[ICX_MXINKS]; /* Best Combinat */ + double bcmv; /* Best Match value */ + int order[MAX_CHAN]; /* Place holder, not currently used - return ink order */ + + switch (sig) { + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigHsvData: + case icSigHlsData: + case icSigNamedData: + return 0; + + case icSigGrayData: + if (deviceClass == icSigOutputClass) + return ICX_K; + return ICX_W; + + case icSigCmyData: + return ICX_CMY; + + case icSigRgbData: + if (deviceClass == icSigOutputClass) + return ICX_IRGB; + return ICX_RGB; + + case icSigCmykData: + return ICX_CMYK; + + default: + break; + + } +#ifdef NEVER /* Rely on device class (above) */ + if (sig == icSigGrayData) { + /* This only works reliably if we got the Lab data from a non-ICC */ + /* conformant monochrome profile (one that doesn't force device 0 */ + /* input of the grayTRTC to black), or uses a LUT based monochrome */ + /* profile. */ + /* It also won't work if someone uses a monochrome profile for a */ + /* device with a non grey colorant. */ + /* Really ICC should have icSigWhiteData, icSigBlackData, icSig1colorData ? */ + if (cvals[0][0] > 50.0) { + return ICX_W; + } else { + return ICX_K; + } + } +#endif /* NEVER */ + + /* Compute Lab values of stock inks, and count them */ + for (ninks = 0; ninks < ICX_MXINKS; ninks++) { + if (icx_ink_table[ninks].m == 0) + break; + icmXYZ2Lab(&icmD50, slab[ninks], icx_ink_table[ninks].sXYZ); + icmXYZ2Lab(&icmD50, alab[ninks], icx_ink_table[ninks].aXYZ); + } + + ncol = icmCSSig2nchan(sig); /* Number of colorants */ + + /* Compute ideal matching of device colorants to stock inks */ + for (i = 0; i < ncol; i++) { + for (j = 0; j < ninks; j++) { + double tt; + mch[i][j].x = j; + mch[i][j].v = icmCIE94sq(cvals[i], slab[j]); + tt = icmCIE94sq(cvals[i], alab[j]); + if (tt < mch[i][j].v) + mch[i][j].v = tt; + } + /* Sort the matches for this colorant */ +#define HEAP_COMPARE(A,B) (A.v < B.v) + HEAPSORT(mchstr, mch[i], ninks) +#undef HEAP_COMPARE + +//printf("\n~1 Colorant %d has best matches\n",i); +//for (j = 0; j < ninks; j++) +//printf("~1 ix %d color = '%s' dE %f\n",j, icx_ink_table[mch[i][j].x].s, mch[i][j].v); + } + + /* Do exaustive combination search, using early */ + /* out to keep combination count down.*/ + + /* Reset the combination counter */ + for (j = 0; j < ninks; j++) /* Reset ink used flag */ + used[j] = 0; + cmv = 0.0; + for (i = ncol-1; i >= 0; i--) { + for (j = 0; j < ninks; j++) { /* Set to lowest usable number */ + if (used[mch[i][j].x] == 0) { /* Can use this one */ + used[mch[i][j].x] = 1; /* Now it's matched */ + cmv += mch[i][j].v; + co[i] = j; + break; /* we assume ncol < ninks */ + } + } + } + +//printf("\n~1 Initial combination has cmv = %f\n",cmv); +//for (i = 0; i < ncol; i++) +//printf("~1 Chan %d color = '%s'\n",i, icx_ink_table[mch[i][co[i]].x].s); + + /* Set this as the best initial match */ + for (i = 0; i < ncol; i++) + bco[i] = co[i]; + bcmv = cmv; + + /* Now go through all other combinations */ + for (;;) { + + /* Increment counter */ + for (i = 0;;) { + + /* Work up the digits, incrementing each one */ + for (; i < ncol; i++) { + j = co[i]; + used[mch[i][j].x] = 0; + cmv -= mch[i][j].v; + while (++j < ninks && (used[mch[i][j].x] != 0 || (cmv + mch[i][j].v) >= bcmv)) { + }; + if (j < ninks) { /* No carry */ + used[mch[i][j].x] = 1; + cmv += mch[i][j].v; + co[i] = j; + break; + } + /* Carry to next colorant */ + } + if (i >= ncol) + break; /* Run out of digits to increment */ + + /* Now work down again, resetting digit */ + for (--i; i >= 0; i--) { + for (j = 0; j < ninks; j++) { /* Set to lowest usable number */ + if (used[mch[i][j].x] == 0 && (cmv + mch[i][j].v) < bcmv) { + /* Can use this one */ + used[mch[i][j].x] = 1; /* Now it's matched */ + cmv += mch[i][j].v; + co[i] = j; + break; + } + } + if (j >= ninks) { /* No combination is feasible */ + i++; /* Go back to incrementing next highest digit */ + break; + } + } + if (i < 0) /* We reset all the lower digits */ + break; /* We're at a good combination, so done. */ + } + if (i >= ncol) + break; /* We're done all combinations */ + +//printf("\n~1 New combination has cmv = %f\n",cmv); +//for (i = 0; i < ncol; i++) +//printf("~1 Chan %d color = '%s'\n",i, icx_ink_table[mch[i][co[i]].x].s); + + /* See if this is better (it always should be !) */ + if (cmv < bcmv) { + for (i = 0; i < ncol; i++) + bco[i] = co[i]; + bcmv = cmv; + } + } + + /* Compile the result */ + for (imask = 0, i = 0; i < ncol; i++) { + imask |= icx_ink_table[mch[i][bco[i]].x].m; + order[i] = bco[i]; /* icx ink_table index corresponding to channel */ + } + + /* Slight hack to recognise some additive combinations */ + if (imask == ICX_WHITE) + imask = ICX_W; + else if (imask == (ICX_RED | ICX_GREEN | ICX_BLUE)) + imask = ICX_RGB; + + return imask; +} + +/* Given a colorant combination mask */ +/* return the primary matching ICC colorspace signature. */ +/* return 0 if there is no match */ +icColorSpaceSignature icx_colorant_comb_to_icc( +inkmask mask /* Colorant combination mask */ +) { + int i; + + for (i = 0; icx_colcomb_table[i].m != 0; i++) { + if (mask == icx_colcomb_table[i].m) + return icx_colcomb_table[i].psig; + } + return 0; +} + + + +/* - - - - - - - - - - - - - - - - - */ +/* Approximate device colorant model */ + +/* Given device values, return an estimate of the XYZ value for that color. */ +static void icxColorantLu_to_XYZ( +icxColorantLu *s, +double XYZ[3], /* Output */ +double d[ICX_MXINKS] /* Input */ +) { + int e, j; + + if (s->mask & ICX_ADDITIVE ) { + /* We assume a simple additive model with gamma */ + + XYZ[0] = XYZ[1] = XYZ[2] = 0.0; + + for (e = 0; e < s->di; e++) { + double v = d[e]; + + if (v < 0.0) + v = 0.0; + else if (v > 1.0) + v = 1.0; + if (v <= 0.03928) + v /= 12.92; + else + v = pow((0.055 + v)/1.055, 2.4); /* Gamma */ + + for (j = 0; j < 3; j++) + XYZ[j] += v * icx_ink_table[s->iix[e]].aXYZ[j]; + } + + /* Normalise Y to 1.0, & add black glare */ + for (j = 0; j < 3; j++) { + XYZ[j] *= s->Ynorm; + XYZ[j] = XYZ[j] * (1.0 - icx_ink_table[s->bkix].aXYZ[j]) + icx_ink_table[s->bkix].aXYZ[j]; + } + + } else { + /* We assume a simple screened subtractive filter model, with dot gain */ + + /* start with white */ + XYZ[0] = icx_ink_table[s->whix].sXYZ[0]; + XYZ[1] = icx_ink_table[s->whix].sXYZ[1]; + XYZ[2] = icx_ink_table[s->whix].sXYZ[2]; + + /* And filter it out for each component */ + for (e = 0; e < s->di; e++) { + double v = d[e]; + + if (v < 0.0) + v = 0.0; + else if (v > 1.0) + v = 1.0; + v = 1.0 - pow(1.0 - v, 2.2); /* Compute dot gain */ + + for (j = 0; j < 3; j++) { + double fv; + + /* Normalise filtering effect of this colorant */ + fv = icx_ink_table[s->iix[e]].aXYZ[j]/icx_ink_table[s->whix].sXYZ[j]; + + /* Compute screened filtering effect */ + fv = (1.0 - v) + v * fv; + + /* Apply filter to our current value */ + XYZ[j] *= fv; + } + } + } +} + +/* Given device values, return an estimate of the */ +/* relative Lab value for that color. */ +static void icxColorantLu_to_rLab( +icxColorantLu *s, +double Lab[3], /* Output */ +double d[ICX_MXINKS] /* Input */ +) { + + icxColorantLu_to_XYZ(s, Lab, d); /* Compute XYZ */ + icmXYZ2Lab(&s->wp, Lab, Lab); /* Convert from XYZ to Lab */ +} + +/* We're done with aproximate device model */ +static void icxColorantLu_del(icxColorantLu *s) { + + if (s != NULL) { + free(s); + } +} + +/* Given an ink definition, return an aproximate */ +/* device to CIE color converted object. */ +icxColorantLu *new_icxColorantLu(inkmask mask) { + int i, e; + icxColorantLu *s; + + if ((s = (icxColorantLu *)malloc(sizeof(icxColorantLu))) == NULL) { + fprintf(stderr,"icxColorantLu: malloc failed allocating object\n"); + exit(-1); + } + + /* Initialise methods */ + s->del = icxColorantLu_del; + s->dev_to_XYZ = icxColorantLu_to_XYZ; + s->dev_to_rLab = icxColorantLu_to_rLab; + + /* Init */ + s->mask = mask; + + for (e = i = 0; icx_ink_table[i].m != 0; i++) { + if (ICX_WHITE == icx_ink_table[i].m) + s->whix = i; + if (ICX_BLACK == icx_ink_table[i].m) + s->bkix = i; + if (mask & icx_ink_table[i].m) + s->iix[e++] = i; + } + s->di = e; + + + s->Ynorm = 0.0; + if (mask & ICX_ADDITIVE ) { + for (e = 0; e < s->di; e++) + s->Ynorm += icx_ink_table[s->iix[e]].aXYZ[1]; + s->Ynorm = 1.0/s->Ynorm; + icmAry2XYZ(s->wp, icx_ink_table[s->whix].aXYZ); + } else { + icmAry2XYZ(s->wp, icx_ink_table[s->whix].sXYZ); + } + + return s; +} + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3