summaryrefslogtreecommitdiff
path: root/profile
diff options
context:
space:
mode:
Diffstat (limited to 'profile')
-rw-r--r--profile/applycal.c1
-rw-r--r--profile/colprof.c90
-rw-r--r--profile/colverify.c141
-rw-r--r--profile/invprofcheck.c1
-rw-r--r--profile/prof.h14
-rw-r--r--profile/profcheck.c24
-rw-r--r--profile/profin.c1
-rw-r--r--profile/profout.c298
-rw-r--r--profile/txt2ti3.c129
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;
+}