diff options
Diffstat (limited to 'profile')
-rw-r--r-- | profile/applycal.c | 1 | ||||
-rw-r--r-- | profile/colprof.c | 90 | ||||
-rw-r--r-- | profile/colverify.c | 141 | ||||
-rw-r--r-- | profile/invprofcheck.c | 1 | ||||
-rw-r--r-- | profile/prof.h | 14 | ||||
-rw-r--r-- | profile/profcheck.c | 24 | ||||
-rw-r--r-- | profile/profin.c | 1 | ||||
-rw-r--r-- | profile/profout.c | 298 | ||||
-rw-r--r-- | profile/txt2ti3.c | 129 |
9 files changed, 565 insertions, 134 deletions
diff --git a/profile/applycal.c b/profile/applycal.c index 17187db..ff9a76d 100644 --- a/profile/applycal.c +++ b/profile/applycal.c @@ -33,7 +33,6 @@ #include "numlib.h" #include "rspl.h" #include "xicc.h" -#include "ui.h" #undef DEBUG diff --git a/profile/colprof.c b/profile/colprof.c index 7309dc4..b359ebb 100644 --- a/profile/colprof.c +++ b/profile/colprof.c @@ -49,6 +49,7 @@ #include <stdio.h> #include <string.h> #include <time.h> +#include <ctype.h> #include "copyright.h" #include "aconfig.h" #include "numlib.h" @@ -135,8 +136,10 @@ void usage(char *diag, ...) { /* Research options: */ /* fprintf(stderr," -r sSMOOTH RSPL or shaper suplimental optimised smoothing factor\n"); */ /* fprintf(stderr," -r rSMOOTH RSPL or shaper raw underlying smoothing factor\n"); */ - fprintf(stderr," -s src%s Apply gamut mapping to output profile perceptual B2A table for given source space\n",ICC_FILE_EXT); - fprintf(stderr," -S src%s Apply gamut mapping to output profile perceptual and saturation B2A table\n",ICC_FILE_EXT); + fprintf(stderr," -s src%s|cperc Apply gamut mapping to output profile perceptual B2A table\n",ICC_FILE_EXT); + fprintf(stderr," for given source space, or compression percentage\n"); + fprintf(stderr," -S src%s|experc Apply gamut mapping to output profile perceptual and\n",ICC_FILE_EXT); + fprintf(stderr," and saturation B2A table, or expansion percentage\n"); fprintf(stderr," -nP Use colormetric source gamut to make output profile perceptual table\n"); fprintf(stderr," -nS Use colormetric source gamut to make output profile saturation table\n"); fprintf(stderr," -g src.gam Use source image gamut as well for output profile gamut mapping\n"); @@ -207,6 +210,7 @@ int main(int argc, char *argv[]) { icxIllumeType illum = icxIT_none; /* Spectral illuminant (defaults to D50) */ xspect cust_illum; /* Custom illumination spectrum */ icxObserverType observ = icxOT_none; /* Observer (defaults to 1931 2 degree) */ + int gcompr = 0, gexpr = 0; /* Gamut compression/expansion % instead of Input icc profile */ char ipname[MAXNAMEL+1] = ""; /* Input icc profile - enables gamut map */ char sgname[MAXNAMEL+1] = ""; /* Image source gamut name */ char absstring[3 * MAXNAMEL +1]; /* Storage for absnames */ @@ -640,14 +644,24 @@ int main(int argc, char *argv[]) { } else if (strcmp(na, "F10") == 0) { tillum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + tillum = icxIT_custom; - if (read_xspect(&cust_tillum, na) != 0) + if (read_xspect(&cust_tillum, &mt, na) != 0) usage("Failed to read custom target illuminant spectrum in file '%s'",na); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("Target illuminant '%s' is wrong measurement type",na); + } } } } - /* Spectral Illuminant type */ + /* CIE Illuminant type */ else if (argv[fa][1] == 'i') { if (na == NULL) usage("Expect argument to illuminant flag -i"); fa = nfa; @@ -676,10 +690,20 @@ int main(int argc, char *argv[]) { spec = 1; illum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + spec = 1; illum = icxIT_custom; - if (read_xspect(&cust_illum, na) != 0) + if (read_xspect(&cust_illum, &mt, na) != 0) usage("Failed to read custom illuminant spectrum in file '%s'",na); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("CIE illuminant '%s' is wrong measurement type",na); + } } } @@ -727,15 +751,51 @@ int main(int argc, char *argv[]) { } } + /* Percetual Source Compression and Perceptual/Saturation Gamut Maping mode enable */ /* Percetual Source Gamut and Perceptual/Saturation Gamut Maping mode enable */ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') { - if (argv[fa][1] == 'S') + int sat = 0; + if (argv[fa][1] == 'S') { sepsat = 1; + sat = 1; + } else { + sepsat = 0; + } if (na == NULL) usage("Unrecognised argument to source gamut flag -%c",argv[fa][1]); fa = nfa; - strncpy(ipname,na,MAXNAMEL); ipname[MAXNAMEL] = '\000'; + { + char *cp; + int comp = 0; + for (cp = na; *cp != '\000'; cp++) { + if (!isdigit(*cp)) + break; + } + /* If general gamut compression/expansion mode */ + if (*cp == '\000') { + int ratio = atoi(na); + if (ratio <= 0 || ratio > 100) { + usage("Gamut -%c %s %d%% must be > 0 and < 100", + argv[fa][1], sat ? "expansion" : "compression", ratio); + } + if (sat) { + gexpr = ratio; + if (gcompr == 0) + gcompr = ratio; + } else { + gcompr = ratio; + if (gexpr == 0) + gexpr = ratio; + } + } + } + /* Not compression %, so assume it's a filename. */ + /* We allow both filename and general compression to allow */ + /* for a non-default L mapping. */ + if (gcompr == 0) { + strncpy(ipname,na,MAXNAMEL); ipname[MAXNAMEL] = '\000'; + } } /* Source image gamut */ @@ -899,10 +959,10 @@ int main(int argc, char *argv[]) { if (fwacomp && spec == 0) error("FWA compensation only works when viewer and/or illuminant selected"); - if (pgmi_set && ipname[0] == '\000') + if (pgmi_set && (ipname[0] == '\000' && gcompr == 0)) warning("-t perceptual intent override only works if -s srcprof or -S srcprof is used"); - if (sgmi_set && ipname[0] == '\000') + if (sgmi_set && (ipname[0] == '\000' && gcompr == 0)) warning("-T saturation intent override only works if -S srcprof is used"); if (sgmi_set && sepsat == 0) { /* Won't do much otherwise */ @@ -911,12 +971,14 @@ int main(int argc, char *argv[]) { sepsat = 1; } - if (gamdiag && ipname[0] == '\000') - warning("no gamut mapping called for, so -P will produce nothing"); + if (gamdiag && (ipname[0] == '\000' && gcompr == 0)) + warning("No gamut mapping called for, so -P will produce nothing"); if (sgname[0] != '\000' && ipname[0] == '\000') warning("-g srcgam will do nothing without -s srcprof or -S srcprof"); + /* Should warning input viewing condition set and ipname[0] == '\000' */ + if (oquality == -1) { /* B2A tables will be used */ oquality = iquality; } @@ -945,7 +1007,7 @@ int main(int argc, char *argv[]) { || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) { if (illum != icxIT_none) warning("-i illuminant ignored for emissive reference type"); - if (fwacomp != icxIT_none) + if (fwacomp != 0) warning("-f FWA compensation ignored for emissive reference type"); fwacomp = 0; @@ -1023,7 +1085,7 @@ int main(int argc, char *argv[]) { int kmax; kmax = atoi(icg->t[0].kdata[ti]); if (kmax > 0 && kmax <= 100.0) { - if (klimit > 0 && klimit <= 100.0) { /* User has specified limit as option */ + if (klimit >= 0 && klimit <= 100.0) { /* User has specified limit as option */ if (kmax < klimit) { warning("Black ink limit greater than original chart! (%d%% > %d%%)",klimit,kmax); } @@ -1114,6 +1176,7 @@ int main(int argc, char *argv[]) { &ink, inname, outname, icg, spec, tillum, &cust_tillum, illum, &cust_illum, observ, fwacomp, smooth, avgdev, 1.0, + gcompr, gexpr, ipname[0] != '\000' ? ipname : NULL, sgname[0] != '\000' ? sgname : NULL, absnames, @@ -1162,6 +1225,7 @@ int main(int argc, char *argv[]) { NULL, inname, outname, icg, spec, icxIT_none, NULL, illum, &cust_illum, observ, 0, smooth, avgdev, demph, + gcompr, gexpr, ipname[0] != '\000' ? ipname : NULL, sgname[0] != '\000' ? sgname : NULL, absnames, diff --git a/profile/colverify.c b/profile/colverify.c index 1ab3f64..86d5575 100644 --- a/profile/colverify.c +++ b/profile/colverify.c @@ -25,7 +25,7 @@ * they are just ignored. */ -#define DEBUG +#undef DEBUG #define verbo stdout @@ -61,6 +61,7 @@ usage(void) { fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n"); fprintf(stderr,"usage: colverify [-options] target.ti3 measured.ti3\n"); fprintf(stderr," -v [n] Verbose mode, n >= 2 print each value\n"); + fprintf(stderr," -l Match patches by sample location rather than id\n"); fprintf(stderr," -n Normalise each files reading to its white Y\n"); fprintf(stderr," -N Normalise each files reading to its white XYZ\n"); fprintf(stderr," -m Normalise each files reading to its white X+Y+Z\n"); @@ -83,6 +84,7 @@ usage(void) { fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n"); fprintf(stderr," -L profile.%s Skip any first file out of profile gamut patches\n",ICC_FILE_EXT_ND); fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix to second file\n"); +// fprintf(stderr," -Z A|X Just print Average|Max +tab\n"); fprintf(stderr," target.ti3 Target (reference) PCS or spectral values.\n"); fprintf(stderr," measured.ti3 Measured (actual) PCS or spectral values\n"); exit(1); @@ -113,6 +115,7 @@ int main(int argc, char *argv[]) { int fa,nfa,mfa; /* current argument we're looking at */ int verb = 0; /* Verbose level */ + int useloc = 0; /* Match patches by sample location */ int norm = 0; /* 1 = norm to White Y, 2 = norm to White XYZ */ /* 3 = norm to White X+Y+Z, 4 = norm to average XYZ */ int usestdd50 = 0; /* Use standard D50 instead of avg white as reference */ @@ -123,6 +126,7 @@ int main(int argc, char *argv[]) int dohisto = 0; /* Plot histogram of delta E's */ char histoname[MAXNAMEL+1] = "\000"; /* Optional file to save histogram points to */ int dosort = 0; + int dozrep = 0; /* 1 = print average, 2 = print max */ char ccmxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */ char gprofname[MAXNAMEL+1] = "\000"; /* Gamut limit profile name */ @@ -196,6 +200,11 @@ int main(int argc, char *argv[]) } } + /* Use location to match patches */ + else if (argv[fa][1] == 'l') { + useloc = 1; + } + /* normalize */ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') { @@ -296,10 +305,20 @@ int main(int argc, char *argv[]) spec = 1; tillum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + spec = 1; tillum = icxIT_custom; - if (read_xspect(&cust_tillum, na) != 0) + if (read_xspect(&cust_tillum, &mt, na) != 0) usage(); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("Target illuminant '%s' is wrong measurement type",na); + } } } } @@ -333,10 +352,20 @@ int main(int argc, char *argv[]) spec = 1; illum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + spec = 1; illum = icxIT_custom; - if (read_xspect(&cust_illum, na) != 0) + if (read_xspect(&cust_illum, &mt, na) != 0) usage(); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("CIE illuminant '%s' is wrong measurement type",na); + } } } @@ -375,6 +404,17 @@ int main(int argc, char *argv[]) if (na == NULL) usage(); fa = nfa; strncpy(ccmxname,na,MAXNAMEL-1); ccmxname[MAXNAMEL-1] = '\000'; + } + + else if (argv[fa][1] == 'Z') { + if (na == NULL) usage(); + fa = nfa; + if (strcmp(na, "A") == 0) { + dozrep = 1; + } else if (strcmp(na, "X") == 0) { + dozrep = 2; + } else + usage(); } else usage(); @@ -555,9 +595,8 @@ int main(int argc, char *argv[]) if ((sidx = cgf->find_field(cgf, 0, "SAMPLE_ID")) < 0 && (sidx = cgf->find_field(cgf, 0, "SampleName")) < 0 && (sidx = cgf->find_field(cgf, 0, "Sample_Name")) < 0 - && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0 - && (sidx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0) - error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_LOC",cg[n].name); + && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0) + error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME",cg[n].name); if (cgf->t[0].ftype[sidx] != nqcs_t && cgf->t[0].ftype[sidx] != cs_t) error("Sample ID/Name field isn't a quoted or non quoted character string"); @@ -608,8 +647,8 @@ int main(int argc, char *argv[]) cg[n].pat[i].xyz[1] = *((double *)cgf->t[0].fdata[i][yix]); cg[n].pat[i].xyz[2] = *((double *)cgf->t[0].fdata[i][zix]); - if (isLab) { /* Convert Lab to XYZ */ - icmLab2XYZ(&icmD50, cg[n].pat[i].xyz, cg[n].pat[i].xyz); + if (isLab) { /* Convert Lab to XYZ 0..100% */ + icmLab2XYZ(&icmD50_100, cg[n].pat[i].xyz, cg[n].pat[i].xyz); } //printf("~1 file %d patch %d = XYZ %f %f %f\n", n,i,cg[n].pat[i].xyz[0],cg[n].pat[i].xyz[1],cg[n].pat[i].xyz[2]); @@ -896,15 +935,37 @@ int main(int argc, char *argv[]) /* Create a list to map the second list of patches to the first */ if ((match = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL) error("Malloc failed - match[]"); - for (i = 0; i < cg[0].npat; i++) { - for (j = 0; j < cg[1].npat; j++) { - if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0) - break; /* Found it */ + + /* Use location to match */ + if (useloc) { + for (i = 0; i < cg[0].npat; i++) { + if (cg[0].pat[0].loc == '\000' + || cg[1].pat[0].loc == '\000') + error("Need both files to have SAMPLE_LOC field to match on location"); + + for (j = 0; j < cg[1].npat; j++) { + if (strcmp(cg[0].pat[i].loc, cg[1].pat[j].loc) == 0) + break; /* Found it */ + } + if (j < cg[1].npat) { + match[i] = j; + } else { + error("Failed to find matching patch to '%s'",cg[0].pat[i].loc); + } } - if (j < cg[1].npat) { - match[i] = j; - } else { - error("Failed to find matching patch to '%s'",cg[0].pat[i].sid); + + /* Use id */ + } else { + for (i = 0; i < cg[0].npat; i++) { + for (j = 0; j < cg[1].npat; j++) { + if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0) + break; /* Found it */ + } + if (j < cg[1].npat) { + match[i] = j; + } else { + error("Failed to find matching patch to '%s'",cg[0].pat[i].sid); + } } } @@ -1329,7 +1390,7 @@ int main(int argc, char *argv[]) double de = cg[0].pat[sort[i]].de; if (cg[0].pat[i].og) /* Skip out of gamut */ continue; - if (j <= n10) { /* If in worst 10% of in gamut patches */ + if (j < n10) { /* If in worst 10% of in gamut patches */ aerr10 += de; if (de > merr10) merr10 = de; @@ -1343,24 +1404,36 @@ int main(int argc, char *argv[]) fprintf(verbo,"No of test patches in worst 10%% are = %d\n",n10); fprintf(verbo,"No of test patches in best 90%% are = %d\n",n90); } - printf("Verify results:\n"); - if (norm == 4) - printf(" L*a*b* ref. = average XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]); - else if (norm == 1) { - printf(" File 1 L* ref. Y %f\n", cg[0].w[1]); - printf(" File 2 L* ref. Y %f\n", cg[1].w[1]); - } else if (norm == 2) { - printf(" File 1 L*a*b* ref. XYZ %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); - printf(" File 2 L*a*b* ref. XYZ %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); - } else if (norm == 3) { - printf(" File 1 L* ref. X+Y+Z %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); - printf(" File 2 L* ref. X+Y+Z %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); + + /* Single number report */ + if (dozrep != 0) { + if (dozrep == 1) { + printf(" %f\t", aerr); + } else if (dozrep == 2) { + printf(" %f\t", merr); + } + fflush(stdout); + + } else { + printf("Verify results:\n"); + if (norm == 4) + printf(" L*a*b* ref. = average XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]); + else if (norm == 1) { + printf(" File 1 L* ref. Y %f\n", cg[0].w[1]); + printf(" File 2 L* ref. Y %f\n", cg[1].w[1]); + } else if (norm == 2) { + printf(" File 1 L*a*b* ref. XYZ %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); + printf(" File 2 L*a*b* ref. XYZ %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); + } else if (norm == 3) { + printf(" File 1 L* ref. X+Y+Z %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); + printf(" File 2 L* ref. X+Y+Z %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); + } + printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr); + printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10); + printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90); + printf(" avg err X %f, Y %f, Z %f\n", aixerr[0], aixerr[1], aixerr[2]); + printf(" avg err L* %f, a* %f, b* %f\n", aierr[0], aierr[1], aierr[2]); } - printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr); - printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10); - printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90); - printf(" avg err X %f, Y %f, Z %f\n", aixerr[0], aixerr[1], aixerr[2]); - printf(" avg err L* %f, a* %f, b* %f\n", aierr[0], aierr[1], aierr[2]); free(sort); free(match); diff --git a/profile/invprofcheck.c b/profile/invprofcheck.c index 5cb1101..0d6176c 100644 --- a/profile/invprofcheck.c +++ b/profile/invprofcheck.c @@ -38,7 +38,6 @@ #include "icc.h" #include "xicc.h" #include "vrml.h" -#include "ui.h" /* Resolution of the sampling modes */ #define TRES 11 diff --git a/profile/prof.h b/profile/prof.h index 013fbd6..486c5b8 100644 --- a/profile/prof.h +++ b/profile/prof.h @@ -56,15 +56,19 @@ void make_output_icc( char *file_name, /* output icc name */ cgats *icg, /* input cgats structure */ int spec, /* Use spectral data flag */ - icxIllumeType tillum, /* Target/simulated instrument illuminant */ - xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */ - icxIllumeType illum, /* Spectral illuminant */ - xspect *cust_illum, /* Possible custom illumination */ - icxObserverType observ, /* Spectral observer */ + icxIllumeType tillum, /* Target/simulated instrument illuminant, if set. */ + xspect *cust_tillum, /* Custom target/simulated illumination spectrum */ + /* if tillum == icxIT_custom */ + icxIllumeType illum, /* CIE calc. illuminant spectrum, and FWA inst. */ + /* illuminant if tillum not set. */ + xspect *cust_illum, /* Custom CIE illumination spectrum if illum == icxIT_custom */ + icxObserverType observ, /* CIE calc. observer */ int fwacomp, /* FWA compensation requested */ double smooth, /* RSPL smoothing factor, -ve if raw */ double avgdev, /* reading Average Deviation as a proportion of the input range */ double demph, /* Emphasise dark region grid resolution in cLUT */ + int gcompr, /* Gamut compression % if > 0 rather than ipname */ + int gexpr, /* Gamut saturation expansion % if gcompr > 0 rather */ char *ipname, /* input icc profile - enables gamut map, NULL if none */ char *sgname, /* source image gamut - NULL if none */ char *absname[3], /* abstract profile name for each table */ diff --git a/profile/profcheck.c b/profile/profcheck.c index e3f1bec..c5703da 100644 --- a/profile/profcheck.c +++ b/profile/profcheck.c @@ -294,10 +294,20 @@ int main(int argc, char *argv[]) spec = 1; tillum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + spec = 1; tillum = icxIT_custom; - if (read_xspect(&cust_tillum, na) != 0) + if (read_xspect(&cust_tillum, &mt, na) != 0) usage(); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("Target illuminant '%s' is wrong measurement type",na); + } } } } @@ -330,10 +340,20 @@ int main(int argc, char *argv[]) spec = 1; illum = icxIT_F10; } else { /* Assume it's a filename */ + inst_meas_type mt; + spec = 1; illum = icxIT_custom; - if (read_xspect(&cust_illum, na) != 0) + if (read_xspect(&cust_illum, &mt, na) != 0) usage(); + + if (mt != inst_mrt_none + && mt != inst_mrt_emission + && mt != inst_mrt_ambient + && mt != inst_mrt_emission_flash + && mt != inst_mrt_ambient_flash) { + error("CIE illuminant '%s' is wrong measurement type",na); + } } } diff --git a/profile/profin.c b/profile/profin.c index 4db596c..9287cf9 100644 --- a/profile/profin.c +++ b/profile/profin.c @@ -1164,6 +1164,7 @@ make_input_icc( flags |= ICX_VERBOSE; flags |= ICX_CLIP_NEAREST; /* Not vector clip */ + #ifdef USE_CAM_CLIP_OPT flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */ #else diff --git a/profile/profout.c b/profile/profout.c index 4ad62aa..f12589b 100644 --- a/profile/profout.c +++ b/profile/profout.c @@ -38,13 +38,21 @@ * Fix error handling * fix verbose output * hand icc object back rather than writing file ? + * + * In theory we could add a ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD option + * for the case of a non-D50 illuminant. spec2cie (and colprof internally) would + * have to put the illuminant white point in the .ti3 file and chromatically + * transform the XYZ/Lab values, and then colprof would create the chad tag + * with the illuminant to D50 matrix. icclib would have to undo the + * transform for absolute intent. */ /* Outline of code flow: profout: - Create ICC profile and all the tags. Table tags are initialy not set. + Create ICC profile and all the tags, and setup any options. + Table tags are initialy not set. Read in the CGTATS data and convert spectral to PCS if needed. @@ -164,8 +172,8 @@ typedef struct { double filter_thr; /* Clip DE threshold */ double filter_ratio; /* Clip DE to radius factor */ double filter_maxrad; /* Clip maximum filter radius */ - icColorSpaceSignature pcsspace; /* The PCS colorspace */ - icColorSpaceSignature devspace; /* The device colorspace */ + icColorSpaceSignature pcsspace; /* The profile PCS colorspace */ + icColorSpaceSignature devspace; /* The profile device colorspace */ icxLuLut *x; /* A2B icxLuLut we are inverting in std PCS */ int ntables; /* Number of tables being set. 1 = colorimetric */ @@ -176,6 +184,8 @@ typedef struct { icxLuBase *ixp; /* Source profile perceptual PCS to CAM conversion */ icxLuBase *ox; /* Destination profile CAM to std PCS conversion */ /* (This is NOT used for the colorimetric B2A table creation!) */ + icxcam *icam; /* Alternate to ixp when using default general compression */ + icColorSpaceSignature mapsp; /* output space needed from icam conversion */ /* Abstract transform for each table. These may be */ /* duplicates. */ @@ -406,8 +416,25 @@ void out_b2a_clut(void *cntx, double *out, double in[3]) { } DBG(("convert PCS' to PCS got %f %f %f\n",in1[0],in1[1],in1[2])) - /* Convert from PCS to CAM/Gamut mapping space */ - p->ixp->fwd_relpcs_outpcs(p->ixp, p->pcsspace, in1, in1); + /* Convert from profile PCS to CAM/Gamut mapping space */ + if (p->ixp != NULL) { + p->ixp->fwd_relpcs_outpcs(p->ixp, p->pcsspace, in1, in1); + + } else { /* General compression fallback conversion to CAM/Gamut mapping space */ + + if (p->mapsp == icxSigJabData) { /* Want icxSigJabData for mapping */ + + if (p->pcsspace == icSigLabData) + icmLab2XYZ(&icmD50, in1, in1); + + p->icam->XYZ_to_cam(p->icam, in1, in1); + + } else { /* Must be icSigLabData for mapping */ + + if (p->pcsspace == icSigXYZData) + icmXYZ2Lab(&icmD50, in1, in1); + } + } DBG(("convert PCS to CAM got %f %f %f\n",in1[0],in1[1],in1[2])) @@ -651,15 +678,19 @@ make_output_icc( char *file_name, /* output icc name */ cgats *icg, /* input cgats structure */ int spec, /* Use spectral data flag */ - icxIllumeType tillum, /* Target/simulated instrument illuminant */ - xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */ - icxIllumeType illum, /* Spectral illuminant */ - xspect *cust_illum, /* Possible custom illumination */ - icxObserverType observ, /* Spectral observer */ + icxIllumeType tillum, /* Target/simulated instrument illuminant, if set. */ + xspect *cust_tillum, /* Custom target/simulated illumination spectrum */ + /* if tillum == icxIT_custom */ + icxIllumeType illum, /* CIE calc. illuminant spectrum, and FWA inst. */ + /* illuminant if tillum not set. */ + xspect *cust_illum, /* Custom CIE illumination spectrum if illum == icxIT_custom */ + icxObserverType observ, /* CIE calc. observer */ int fwacomp, /* FWA compensation requested */ double smooth, /* RSPL smoothing factor, -ve if raw */ double avgdev, /* reading Average Deviation as a proportion of the input range */ double demph, /* Emphasise dark region grid resolution in cLUT */ + int gcompr, /* Gamut compression % if > 0, rather than use ipname */ + int gexpr, /* Gamut saturation expansion % if gcompr > 0 rather */ char *ipname, /* input icc profile - enables gamut map, NULL if none */ char *sgname, /* source image gamut - NULL if none */ char *absname[3], /* abstract profile name for each table */ @@ -676,6 +707,8 @@ make_output_icc( double dispLuminance = 0.0; /* Display luminance. 0.0 if not known */ int isdnormed = 0; /* Has display data been normalised to white Y = 100 ? */ int allintents; /* nz if all intents should possibly be created */ + double *ill_wp = NULL; /* If illum is not D50, illum white point XYZ */ + double _ill_wp[3]; /* (What ill_wp points at if it is not NULL) */ icmFile *wr_fp; icc *wr_icco; int npat; /* Number of patches */ @@ -727,7 +760,7 @@ make_output_icc( if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) { isdisp = 1; - if (isLut && ipname != NULL) + if (isLut && (ipname != NULL || gcompr > 0)) allintents = 1; else allintents = 0; /* Only the default intent */ @@ -757,6 +790,28 @@ make_output_icc( } } + /* See if CIE illuminant white point is given, in case CIE data */ + /* is used, and 'chad' tag is going to be created. */ + if (!isdisp) { + int ti; + + if ((ti = icg->find_kword(icg, 0, "ILLUMINANT_WHITE_POINT_XYZ")) >= 0) { + if (sscanf(icg->t[0].kdata[ti], " %lf %lf %lf ",&_ill_wp[0],&_ill_wp[1],&_ill_wp[2]) == 3) { + + /* Normalize it */ + if (_ill_wp[1] > 1e-6) { + _ill_wp[0] /= _ill_wp[1]; + _ill_wp[2] /= _ill_wp[1]; + _ill_wp[1] = 1.0; + + ill_wp = _ill_wp; + } + } + if (verb) + fprintf(verbo,"Unable to parse 'ILLUMINANT_WHITE_POINT_XYZ' keyword\n"); + } + } + /* Figure out what sort of device colorspace it is */ { int ti; @@ -1309,7 +1364,7 @@ make_output_icc( if (allintents) { /* All the intents may be needed */ - if (ipname == NULL) { /* No gamut mapping */ + if (ipname == NULL && gcompr <= 0) { /* No gamut mapping */ icmLut *wo; /* link intent 0 = perceptual to intent 1 = colorimetric */ @@ -1476,7 +1531,7 @@ make_output_icc( if (fseek(fp, 0, SEEK_END)) error("Unable to seek to end of file '%s'",in_name); wo->size = ftell(fp) + 1; /* Size needed + null */ - wo->allocate((icmBase *)wo);/* Allocate space */ + wo->allocate((icmBase *)wo); /* Allocate space */ if (fseek(fp, 0, SEEK_SET)) error("Unable to seek to end of file '%s'",in_name); @@ -1730,6 +1785,16 @@ make_output_icc( cust_illum = NULL; } + /* If CIE calculation illuminant is not standard, compute it's white point, */ + /* in case we are going to create 'chad' tag. */ + if (!isdisp && illum != icxIT_D50) { + ill_wp = _ill_wp; + + /* Compute XYZ of illuminant */ + if (icx_ill_sp2XYZ(ill_wp, observ, NULL, illum, 0.0, cust_illum) != 0) + error("icx_ill_sp2XYZ returned error"); + } + /* Create a spectral conversion object */ if ((sp2cie = new_xsp2cie(illum, cust_illum, observ, NULL, wantLab ? icSigLabData : icSigXYZData, icxClamp)) == NULL) @@ -1902,6 +1967,12 @@ make_output_icc( } /* End of reading in CGATs file */ + /* If we have been given an illuminant white point, set this in the */ + /* ICC profile so that it can save a 'chad' tag if */ + /* ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD is set. */ + if (ill_wp != NULL) + wr_icco->set_illum(wr_icco, ill_wp); + #ifdef EMPH_DISP_BLACKPOINT /* Add extra weighting to sample points near black for additive display. */ /* Not sure what the justification is, apart from making the black */ @@ -2000,6 +2071,7 @@ make_output_icc( error("Creation of xicc failed"); flags |= ICX_CLIP_NEAREST; /* This will avoid clip caused rev setup */ + /* which we don't need when creating A2B */ if (noisluts) flags |= ICX_NO_IN_SHP_LUTS; @@ -2082,13 +2154,12 @@ make_output_icc( xicc *x; icxViewCond *v, *vc; int es; + double *wp = NULL; if (i == 0) { /* Input */ v = ivc_p; /* Override parameters */ es = ivc_e; vc = &ivc; /* Target parameters */ - if (src_xicc == NULL) - continue; /* Source viewing conditions won't be used */ x = src_xicc; } else { /* Output */ v = ovc_p; /* Override parameters */ @@ -2096,13 +2167,16 @@ make_output_icc( vc = &ovc; /* Target parameters */ x = wr_xicc; } + + if (x == NULL) + wp = icmD50_ary3; /* So xicc_enum_viewcond will work without xicc */ /* Set the default */ - xicc_enum_viewcond(x, vc, -1, NULL, 0, NULL); + xicc_enum_viewcond(x, vc, -1, NULL, 0, wp); /* Override the viewing conditions */ if (es >= 0) - if (xicc_enum_viewcond(x, vc, es, NULL, 0, NULL) == -2) + if (xicc_enum_viewcond(x, vc, es, NULL, 0, wp) == -2) error ("%d, %s",x->errc, x->err); if (v->Ev >= 0) vc->Ev = v->Ev; @@ -2142,6 +2216,8 @@ make_output_icc( vc->Gxyz[0] = x/y * vc->Gxyz[1]; vc->Gxyz[2] = z/y * vc->Gxyz[1]; } + if (v->hkscale >= 0.0) + vc->hkscale = v->hkscale; } /* Get a suitable forward conversion object to invert. */ @@ -2153,7 +2229,16 @@ make_output_icc( if (verb) flags |= ICX_VERBOSE; - flags |= ICX_CLIP_NEAREST; /* Not vector clip */ +#ifdef NEVER /* [Und] */ + /* Vector is somewhat flakey (some CuspMap based vectors don't 100% + intersect the gamut, having to fall back on nearest), and the result + is rather poor in saturation for green and yellow in particular. */ + flags |= ICX_CLIP_VECTOR; + warning("!!!! ICX_CLIP_VECTOR in profout.c is on !!!!"); +#else + flags |= ICX_CLIP_NEAREST; +#endif + #ifdef USE_CAM_CLIP_OPT flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */ #else @@ -2180,6 +2265,8 @@ make_output_icc( cx.ixp = NULL; /* Perceptual PCS to CAM conversion */ cx.ox = NULL; /* CAM to PCS conversion */ + cx.icam = NULL; + cx.mapsp = 0; cx.pmap = NULL; /* perceptual gamut map */ cx.smap = NULL; /* Saturation gamut map */ @@ -2191,7 +2278,7 @@ make_output_icc( /* Determine the number of tables */ cx.ntables = 1; - if (src_xicc) { /* Creating separate perceptual and Saturation tables */ + if (src_xicc || gcompr) { /* Creating separate perceptual and Saturation tables */ cx.ntables = 2; if (sepsat) cx.ntables = 3; @@ -2261,16 +2348,17 @@ make_output_icc( wr_icco, icSigBToA1Tag)) == NULL) error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err); - if (src_xicc) { /* Creating separate perceptual and Saturation tables */ + if (src_xicc || gcompr) { /* Creating separate perceptual and Saturation tables */ icRenderingIntent intentp; /* Gamut mapping space perceptual selection */ icRenderingIntent intents; /* Gamut mapping space saturation selection */ icRenderingIntent intento; /* Gamut mapping space output selection */ - gamut *csgamp; /* Incoming colorspace perceptual gamut */ - gamut *csgams; /* Incoming colorspace saturation gamut */ - gamut *igam = NULL; /* Incoming image gamut */ - gamut *ogam; /* Destination colorspace gamut */ - double gres; /* Gamut surface feature resolution */ - int mapres; /* Mapping rspl resolution */ + gamut *csgamp = NULL; /* Incoming colorspace perceptual gamut */ + gamut *csgams = NULL; /* Incoming colorspace saturation gamut */ + gamut *igam = NULL; /* Incoming image gamut */ + gamut *ogam = NULL; /* Destination colorspace gamut */ + gamut *ihgam = NULL; /* Input space general compression hull gamut */ + double gres; /* Gamut surface feature resolution */ + int mapres; /* Mapping rspl resolution */ if (verb) printf("Creating Gamut Mapping\n"); @@ -2353,50 +2441,56 @@ make_output_icc( /* Unlike icclink, we've not provided a way for the user */ /* to set the source profile ink limit, so estimate it */ /* from the profile */ - icxDefaultLimits(src_xicc, &iink.tlimit, iink.tlimit, - &iink.klimit, iink.klimit); - - /* Get lookup object simply for fwd_relpcs_outpcs() */ - /* and perceptual input gamut shell creation. */ - /* Note that the intent=Appearance will trigger Jab CAM, */ - /* overriding icSigLabData.. */ -#ifdef NEVER - printf("~1 input space flags = 0x%x\n",ICX_CLIP_NEAREST); - printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,intentp)); - printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,icSigLabData)); - printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&ivc); - printf("~1 input space inking =\n"); xicc_dump_inking(&iink); -#endif - if ((cx.ixp = src_xicc->get_luobj(src_xicc,ICX_CLIP_NEAREST - , icmFwd, intentp, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL) - error ("%d, %s",src_xicc->errc, src_xicc->err); + if (src_xicc != NULL) { + icxDefaultLimits(src_xicc, &iink.tlimit, iink.tlimit, + &iink.klimit, iink.klimit); - /* Create the source colorspace gamut surface */ - if (verb) - printf(" Finding Source Colorspace Perceptual Gamut\n"); - - if ((csgamp = cx.ixp->get_gamut(cx.ixp, gres)) == NULL) - error ("%d, %s",src_xicc->errc, src_xicc->err); - - if (sepsat) { - icxLuBase *ixs = NULL; /* Source profile saturation lookup for gamut */ - /* Get lookup object for saturation input gamut shell creation */ + /* Get lookup object simply for fwd_relpcs_outpcs() */ + /* and perceptual input gamut shell creation. */ /* Note that the intent=Appearance will trigger Jab CAM, */ /* overriding icSigLabData.. */ - if ((ixs = src_xicc->get_luobj(src_xicc, ICX_CLIP_NEAREST - , icmFwd, intents, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL) - error ("%d, %s",src_xicc->errc, src_xicc->err); - +#ifdef NEVER + printf("~1 input space flags = 0x%x\n",ICX_CLIP_NEAREST); + printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,intentp)); + printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,icSigLabData)); + printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&ivc); + printf("~1 input space inking =\n"); xicc_dump_inking(&iink); +#endif + if ((cx.ixp = src_xicc->get_luobj(src_xicc,ICX_CLIP_NEAREST + , icmFwd, intentp, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL) + error ("%d, %s",src_xicc->errc, src_xicc->err); + + /* Create the source colorspace gamut surface */ if (verb) - printf(" Finding Source Colorspace Saturation Gamut\n"); - - if ((csgams = ixs->get_gamut(ixs, gres)) == NULL) + printf(" Finding Source Colorspace Perceptual Gamut\n"); + + if ((csgamp = cx.ixp->get_gamut(cx.ixp, gres)) == NULL) + error ("%d, %s",src_xicc->errc, src_xicc->err); + + if (sepsat) { + icxLuBase *ixs = NULL; /* Source profile saturation lookup for gamut */ + /* Get lookup object for saturation input gamut shell creation */ + /* Note that the intent=Appearance will trigger Jab CAM, */ + /* overriding icSigLabData.. */ + if ((ixs = src_xicc->get_luobj(src_xicc, ICX_CLIP_NEAREST + , icmFwd, intents, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL) error ("%d, %s",src_xicc->errc, src_xicc->err); - ixs->del(ixs); + + if (verb) + printf(" Finding Source Colorspace Saturation Gamut\n"); + + if ((csgams = ixs->get_gamut(ixs, gres)) == NULL) + error ("%d, %s",src_xicc->errc, src_xicc->err); + ixs->del(ixs); + } } - + /* Read image source gamut if provided */ - if (sgname != NULL) { /* Optional source gamut - ie. from an images */ + /* Optional source gamut - ie. from an images, */ + /* ignored if gcompr > 0 */ + if (sgname != NULL && gcompr > 0) + warning("Image gamut ignored for general gamut compression"); + if (sgname != NULL && gcompr == 0) { int isJab = 0; if ((pgmi->usecas & 0xff) >= 0x2) @@ -2418,7 +2512,7 @@ make_output_icc( /* At the moment it's up to the user to get this right. */ } } - + /* Get lookup object for bwd_outpcs_relpcs(), */ /* and output gamut shell creation */ /* Note that the intent=Appearance will trigger Jab CAM, */ @@ -2435,6 +2529,45 @@ make_output_icc( if ((ogam = cx.ox->get_gamut(cx.ox, gres)) == NULL) error ("%d, %s",wr_xicc->errc, wr_xicc->err); + /* General compression rather than source gamut */ + if (gcompr > 0) { + /* Create alternative to ixp for conv. to Gamut maping space. */ + if (cx.ixp == NULL) { + double wp[3], bp[3] = { 0.0, 0.0, 0.0 }; + cx.mapsp = xiccIsIntentJab(intentp) ? icxSigJabData : icSigLabData; + + if (cx.mapsp == icxSigJabData) { + cx.icam = new_icxcam(cam_default); + cx.icam->set_view(cx.icam, ivc.Ev, ivc.Wxyz, ivc.La, ivc.Yb, ivc.Lv, + ivc.Yf, ivc.Yg, ivc.Gxyz, + XICC_USE_HK, ivc.hkscale); + } + + /* Create a dumy source gamut, used by new_gammap to create */ + /* the L mapping */ + if ((csgamp = new_gamut(0.0, cx.mapsp == icxSigJabData, 0)) == NULL) + error ("Creating fake input gamut failed"); + + if (cx.mapsp == icxSigJabData) { + cx.icam->XYZ_to_cam(cx.icam, wp, icmD50_ary3); + cx.icam->XYZ_to_cam(cx.icam, bp, bp); + } else { + icmXYZ2Lab(&icmD50, bp, icmD50_ary3); + icmXYZ2Lab(&icmD50, bp, bp); + } + csgamp->setwb(csgamp, wp, bp, bp); + csgams = csgamp; + } + + /* Expand destination gamut cylindrically to make source hull gamut. */ + if (verb) + printf(" Creating fake source gamut with compression %d%%\n",gcompr); + if ((ihgam = new_gamut(1.0, 0, 0)) == NULL + || ihgam->exp_cyl(ihgam, ogam, (100.0 + gcompr)/100.0)) { + error ("Creating expanded input failed"); + } + } + if (verb) printf(" Creating Gamut match\n"); @@ -2447,7 +2580,8 @@ make_output_icc( /* values outside the grid range. */ /* setup perceptual gamut mapping */ - cx.pmap = new_gammap(verb, csgamp, igam, ogam, pgmi, 0, 0, 0, 0, mapres, + cx.pmap = new_gammap(verb, csgamp, igam, ogam, pgmi, + ihgam, 0, 0, 0, 0, mapres, NULL, NULL, gamdiag ? "gammap_p.wrl" : NULL ); if (cx.pmap == NULL) @@ -2459,8 +2593,24 @@ make_output_icc( error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err); if (sepsat) { + /* General expansion rather than source gamut */ + if (gcompr > 0) { + if (gexpr == 0) + gexpr = gcompr; + /* Expand destination gamut cylindrically to make source gamut. */ + if (verb) + printf(" Creating fake source gamut with expansion %d%%\n",gexpr); + if (ihgam != NULL) + ihgam->del(ihgam); + if ((ihgam = new_gamut(1.0, 0, 0)) == NULL + || ihgam->exp_cyl(ihgam, ogam, (100.0 - gexpr)/100.0)) { + error ("Creating compressed input failed"); + } + } + /* setup saturation gamut mapping */ - cx.smap = new_gammap(verb, csgams, igam, ogam, sgmi, 0, 0, 0, 0, mapres, + cx.smap = new_gammap(verb, csgams, igam, ogam, sgmi, + ihgam, 0, 0, 0, 0, mapres, NULL, NULL, gamdiag ? "gammap_s.wrl" : NULL ); if (cx.smap == NULL) @@ -2471,18 +2621,22 @@ make_output_icc( wr_icco, icSigBToA2Tag)) == NULL) error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err); } - csgamp->del(csgamp); - csgamp = NULL; - if (sepsat) { + if (csgams != NULL && csgams != csgamp) { csgams->del(csgams); csgams = NULL; } + if (csgamp != NULL) { + csgamp->del(csgamp); + csgamp = NULL; + } if (igam != NULL) { igam->del(igam); igam = NULL; } - ogam->del(ogam); - ogam = NULL; + if (ogam != NULL) { + ogam->del(ogam); + ogam = NULL; + } } } cx.ochan = wo[0]->outputChan; @@ -2802,6 +2956,8 @@ make_output_icc( cx.ixp->del(cx.ixp), cx.ixp = NULL; if (cx.ox != NULL) cx.ox->del(cx.ox), cx.ox = NULL; + if (cx.icam != NULL) + cx.icam->del(cx.icam), cx.icam = NULL; if (src_xicc != NULL) src_xicc->del(src_xicc), src_xicc = NULL; diff --git a/profile/txt2ti3.c b/profile/txt2ti3.c index 28f5071..662fdc3 100644 --- a/profile/txt2ti3.c +++ b/profile/txt2ti3.c @@ -45,6 +45,8 @@ #include "numlib.h" #include "ui.h" +static int trans(char *dst, char *src); + void usage(char *mes) { fprintf(stderr,"Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version %s\n",ARGYLL_VERSION_STR); @@ -57,6 +59,7 @@ usage(char *mes) { fprintf(stderr," -l limit set ink limit, 0 - 400%% (default max in file)\n"); fprintf(stderr," -d Set type of device as Display, not Output\n"); fprintf(stderr," -i Set type of device as Input, not Output\n"); + fprintf(stderr," -T Transpose sample name Letters and Numbers\n"); fprintf(stderr," [devfile] Input Device CMYK target file (typically file.txt)\n"); fprintf(stderr," infile Input CIE, Spectral or Device & Spectral file (typically file.txt)\n"); fprintf(stderr," [specfile] Input Spectral file (typically file.txt)\n"); @@ -72,11 +75,13 @@ int main(int argc, char *argv[]) int out2 = 0; /* Create dumy .ti2 file output */ int disp = 0; /* nz if this is a display device */ int inp = 0; /* nz if this is an input device */ + int transpose = 0; /* nz to transpose letters and numbers */ static char devname[MAXNAMEL+1] = { 0 }; /* Input CMYK/Device .txt file (may be null) */ static char ciename[MAXNAMEL+1] = { 0 }; /* Input CIE .txt file (may be null) */ static char specname[MAXNAMEL+1] = { 0 }; /* Input Device / Spectral .txt file */ static char outname[MAXNAMEL+9] = { 0 }; /* Output cgats .ti3 file base name */ static char outname2[MAXNAMEL+9] = { 0 }; /* Output cgats .ti2 file base name */ + int ti; /* Temporary field index */ cgats *cmy = NULL; /* Input RGB/CMYK reference file */ int f_id1 = -1, f_c, f_m, f_y, f_k = 0; /* Field indexes */ double dev_scale = 1.0; /* Device value scaling */ @@ -91,6 +96,7 @@ int main(int argc, char *argv[]) time_t clk = time(0); struct tm *tsp = localtime(&clk); char *atm = asctime(tsp); /* Ascii time */ + char *devcalstd = NULL; /* X-Rite calibration standard if any */ int islab = 0; /* CIE is Lab rather than XYZ */ int specmin = 0, specmax = 0, specnum = 0; /* Min and max spectral in nm, inclusive */ int npat = 0; /* Number of patches */ @@ -143,6 +149,9 @@ int main(int argc, char *argv[]) disp = 0; inp = 1; + } else if (argv[fa][1] == 'T') { + transpose = 1; + } else if (argv[fa][1] == 'v') verb = 1; else @@ -309,6 +318,9 @@ int main(int argc, char *argv[]) && cmy->t[0].ftype[f_id2] != i_t) error("Field SampleName (%s) from cie file '%s' is wrong type",ncie->t[0].fsym[f_id2],ciename); + if ((ti = ncie->find_kword(ncie, 0, "DEVCALSTD")) >= 0) + devcalstd = ncie->t[0].kdata[ti]; + if (ncie->find_field(ncie, 0, "XYZ_X") < 0 && ncie->find_field(ncie, 0, "LAB_L") < 0) { @@ -359,7 +371,7 @@ int main(int argc, char *argv[]) /* Open up the input Spectral device data file */ if (specname[0] != '\000') { - char bufs[5][50]; + char bufs[6][50]; spec = new_cgats(); /* Create a CGATS structure */ spec->add_other(spec, "LGOROWLENGTH"); /* Gretag/Logo Target file */ @@ -390,12 +402,14 @@ int main(int argc, char *argv[]) sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin); sprintf(bufs[3],"R_%03d", specmin); sprintf(bufs[4],"SPECTRAL_%03d", specmin); + sprintf(bufs[5],"SPECTRAL_NM%03d", specmin); if (spec->find_field(spec, 0, bufs[0]) < 0 && spec->find_field(spec, 0, bufs[1]) < 0 && spec->find_field(spec, 0, bufs[2]) < 0 && spec->find_field(spec, 0, bufs[3]) < 0 - && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */ + && spec->find_field(spec, 0, bufs[4]) < 0 + && spec->find_field(spec, 0, bufs[5]) < 0) /* Not found */ break; } specmin += 10; @@ -405,12 +419,14 @@ int main(int argc, char *argv[]) sprintf(bufs[2],"SPECTRAL_NM_%03d", specmax); sprintf(bufs[3],"R_%03d", specmax); sprintf(bufs[4],"SPECTRAL_%03d", specmax); + sprintf(bufs[5],"SPECTRAL_NM%03d", specmax); if (spec->find_field(spec, 0, bufs[0]) < 0 && spec->find_field(spec, 0, bufs[1]) < 0 && spec->find_field(spec, 0, bufs[2]) < 0 && spec->find_field(spec, 0, bufs[3]) < 0 - && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */ + && spec->find_field(spec, 0, bufs[4]) < 0 + && spec->find_field(spec, 0, bufs[5]) < 0) /* Not found */ break; } specmax -= 10; @@ -419,6 +435,8 @@ int main(int argc, char *argv[]) spec->del(spec); spec = NULL; specname[0] = '\000'; + if (verb) + printf("Not enough (%d) spectral values - discarding spectral\n",specnum); } else { specnum = (specmax - specmin)/10 + 1; @@ -434,12 +452,14 @@ int main(int argc, char *argv[]) sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin + 10 * j); sprintf(bufs[3],"R_%03d", specmin + 10 * j); sprintf(bufs[4],"SPECTRAL_%03d", specmin + 10 * j); + sprintf(bufs[5],"SPECTRAL_NM%03d", specmin + 10 * j); if ((spi[j] = spec->find_field(spec, 0, bufs[0])) < 0 && (spi[j] = spec->find_field(spec, 0, bufs[1])) < 0 && (spi[j] = spec->find_field(spec, 0, bufs[2])) < 0 && (spi[j] = spec->find_field(spec, 0, bufs[3])) < 0 - && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0) { /* Not found */ + && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0 + && (spi[j] = spec->find_field(spec, 0, bufs[5])) < 0) { /* Not found */ spec->del(spec); spec = NULL; @@ -477,10 +497,13 @@ int main(int argc, char *argv[]) /* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL); + if (devcalstd != NULL) + ocg->add_kword(ocg, 0, "DEVCALSTD", devcalstd, NULL); + /* Fields we want */ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t); if (f_id1 >= 0) - ocg->add_field(ocg, 0, "SAMPLE_NAME", cs_t); + ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t); if (ndchan == 3) { ocg->add_field(ocg, 0, "RGB_R", r_t); @@ -606,6 +629,7 @@ int main(int argc, char *argv[]) /* Write out the patch info to the output CGATS file */ for (i = 0; i < npat; i++) { char id[100]; + char loc[100]; int k = 0; if (ncie != NULL) { @@ -631,8 +655,15 @@ int main(int argc, char *argv[]) setel[k++].c = id; /* SAMPLE NAME */ - if (f_id1 >= 0) - setel[k++].c = (char *)cmy->t[0].rfdata[i][f_id1]; + if (f_id1 >= 0) { + strcpy(loc, (char *)cmy->t[0].rfdata[i][f_id1]); + + /* Transpose Letters and Numbers */ + if (transpose) + trans(loc, (char *)cmy->t[0].rfdata[i][f_id1]); + + setel[k++].c = loc; + } if (ndchan == 3) { setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]); @@ -828,4 +859,88 @@ int main(int argc, char *argv[]) } +/* Transpose Letters and Numbers of location */ +/* return nz on error */ +static int trans(char *dst, char *src) { + int tt = 0, first = 0, second = 0; /* 1..n */ + char *c, *d; /* Dividing point */ + +//printf("\nGot '%s'\n",src); + d = src; + + if (*d == '\000') + return 1; + + if ((*d >= 'A' && *d <= 'Z') + || (*d >= 'a' && *d <= 'z')) + tt = 1; // Initial is letters + else + tt = 0; +//printf("Initial is %s\n",tt ? "letters" : "numbers"); + + for (; ; d++) { + if (*d == '\000') { +//printf("Failed to find division\n"); + return 1; + } + if (tt && *d >= '0' && *d <= '9') { +//printf("Found number at offset %d\n",d - src); + break; + + } else if (!tt && ((*d >= 'A' && *d <= 'Z') + || (*d >= 'a' && *d <= 'z'))) { +//printf("Found letter at offset %d\n",d - src); + break; + } + } + + +//printf("2nd seg = '%s'\n",d); + + for (c = src; c < d; c++) { + if (tt) { + if (*c >= 'A' && *c <= 'Z') + first = first * 26 + (*c - 'A' + 1); + else + first = first * 26 + (*c - 'a' + 1); + } else { + first = first * 10 + (*c - '0'); + } + } + for (; *c != '\000'; c++) { + if (!tt) { + if (*c >= 'A' && *c <= 'Z') + second = second * 26 + (*c - 'A' + 1); + else + second = second * 26 + (*c - 'a' + 1); + } else { + second = second * 10 + (*c - '0'); + } + } +//printf("First = %d, second = %d\n",first,second); + + c = dst; + if (tt) { /* Output letters */ + if (second > 26) { + *c++ = 'A' + ((second-1) / 26) -1; + second = ((second-1) % 26) + 1; + } + *c++ = 'A' + second -1; + } else { /* Output letters */ + c += sprintf(c, "%d",second); + } + if (tt) { /* Output letters */ + c += sprintf(c, "%d",first); + } else { /* Output numbers */ + if (first > 26) { + *c++ = 'A' + ((first-1) / 26) -1; + first = ((first-1) % 26) + 1; + } + *c++ = 'A' + first -1; + } + *c = '\000'; +//printf("Output '%s'\n",dst); + + return 0; +} |