summaryrefslogtreecommitdiff
path: root/spectro/spec2cie.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/spec2cie.c')
-rw-r--r--spectro/spec2cie.c220
1 files changed, 158 insertions, 62 deletions
diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c
index 322ab05..d77c334 100644
--- a/spectro/spec2cie.c
+++ b/spectro/spec2cie.c
@@ -1,7 +1,7 @@
/*
* Argyll Color Correction System
- * Spectral .ti3 file converter
+ * Spectral .ti3 or .sp file converter
*
* Copyright 2005 Gerhard Fuernkranz
* All rights reserved.
@@ -26,17 +26,17 @@
* under the GNU GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*
- * This program takes the spectral data in a .ti3 file, converts them
+ * This program takes the spectral data in a .ti3 or .sp file, converts them
* to XYZ and Lab and fills the XYZ_[XYZ] and LAB_[LAB] columns in the
- * output .ti3 file with the computed XYZ and Lab values. If the columns
+ * output .ti3 or .sp file with the computed XYZ and Lab values. If the columns
* XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
* added to the output file.
*
- * All other colums are copied from the input to the output .ti3 file.
+ * All other colums are copied from the input to the output .ti3 or .sp file.
*
* If the -f option is used, the FWA corrected spectral reflectances
- * are written to the output .ti3 file, instead of simply copying the
- * spectral reflectances from the input .ti3 file. In this case, the
+ * are written to the output .ti3 or .sp file, instead of simply copying the
+ * spectral reflectances from the input .ti3 or .sp file. In this case, the
* XYZ_[XYZ] and D50 LAB_[LAB] values are computed from the FWA corrected
* reflectances as well.
*/
@@ -50,10 +50,11 @@
Calibration tables aren't being passed through either ??
- L*a*b* is always D50.
-
This is intended for conversion of reflective measurements to XYZ -
there is no illuminant for emissive values.
+
+ L*a*b* is always D50.
+
*/
#define ALLOW_PLOT
@@ -74,33 +75,33 @@
#include "inst.h"
#ifdef ALLOW_PLOT
#include "plot.h"
-#endif
#include "ui.h"
+#endif
void
usage (void)
{
- fprintf (stderr, "Convert spectral .ti3 file, Version %s\n", ARGYLL_VERSION_STR);
+ fprintf (stderr, "Convert spectral .ti3 or .sp file, Version %s\n", ARGYLL_VERSION_STR);
fprintf (stderr, "Author: Gerhard Fuernkranz, licensed under the AGPL Version 3\n");
fprintf (stderr, "\n");
- fprintf (stderr, "Usage: spec2cie [options] input.ti3 output.ti3\n");
- fprintf (stderr, " -v Verbose mode\n");
- fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 file:\n");
- fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " (only used in conjunction with -f)\n");
- fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
- fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
- fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
- fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
- fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
- fprintf (stderr, " -n Don't output spectral values\n");
+ fprintf (stderr, "Usage: spec2cie [options] input.[ti3|sp] output.[ti3|sp]\n");
+ fprintf (stderr, " -v Verbose mode\n");
+ fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 or .sp file:\n");
+ fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " (only used in conjunction with -f)\n");
+ fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
+ fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
+ fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
+ fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
+ fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
+ fprintf (stderr, " -n Don't output spectral values\n");
#ifdef ALLOW_PLOT
- fprintf (stderr, " -p Plot each values spectrum\n");
+ fprintf (stderr, " -p Plot each values spectrum\n");
#endif
- fprintf (stderr, " input.ti3 Measurement file\n");
- fprintf (stderr, " output.ti3 Converted measurement file\n");
+ fprintf (stderr, " input.[ti3|sp] Measurement file\n");
+ fprintf (stderr, " output.[ti3|sp] Converted measurement file\n");
exit (1);
}
@@ -116,6 +117,7 @@ main(int argc, char *argv[])
cgats *ocg; /* output cgats structure */
cgats_set_elem *elems;
+ int isspect = 0; /* nz if SPECT file rathe than TI3 */
int isemis = 0; /* nz if this is an emissive reference */
int isdisp = 0; /* nz if this is a display device */
int isdnormed = 0; /* Has display data been normalised to 100 ? */
@@ -126,12 +128,18 @@ main(int argc, char *argv[])
int fwacomp = 0; /* FWA compensation */
int doplot = 0; /* Plot each patches spectrum */
char* illum_str = "D50";
- icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant, if set. */
xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
- icxIllumeType illum = icxIT_none; /* Spectral defaults */
- xspect cust_illum; /* Custom CIE illumination spectrum */
- icxIllumeType inst_illum = icxIT_none; /* Spectral defaults */
+ /* if tillum == icxIT_custom */
+ icxIllumeType illum = icxIT_none; /* CIE calc. illuminant spectrum, and FWA inst. */
+ /* illuminant if tillum not set. */
+ xspect cust_illum; /* Custom CIE illumination spectrum if illum == icxIT_custom */
+ 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) */
+ icxIllumeType inst_illum = icxIT_none; /* Actual instrument illumination */
xspect inst_cust_illum; /* Custom actual instrument illumination spectrum */
+ /* if inst_illum == icxIT_custom */
+
icxObserverType observ = icxOT_none;
xspect cust_observ[3]; /* Custom observer CMF's */
@@ -211,9 +219,18 @@ main(int argc, char *argv[])
inst_illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
inst_illum = icxIT_custom;
- if (read_xspect (&inst_cust_illum, na) != 0)
+ if (read_xspect (&inst_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("Instrument illuminant '%s' is wrong measurement type",na);
}
}
@@ -243,14 +260,24 @@ 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();
+
+ 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);
}
}
}
/* CIE tristimulous spectral Illuminant type */
+ /* (and FWA simulated instrument illuminant if tillum == icxIT_none) */
else if (argv[fa][1] == 'i') {
fa = nfa;
if (na == NULL)
@@ -281,9 +308,18 @@ main(int argc, char *argv[])
illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
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);
}
}
@@ -334,23 +370,32 @@ main(int argc, char *argv[])
/* Open and look at the .ti3 profile patches file */
- icg = new_cgats (); /* Create a CGATS structure */
+ icg = new_cgats (); /* Create a CGATS structure */
icg->add_other (icg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (icg, "SPECT"); /* Spectral file */
- ocg = new_cgats (); /* Create a CGATS structure */
+ ocg = new_cgats (); /* Create a CGATS structure */
ocg->add_other (ocg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (ocg, "SPECT"); /* Spectral file */
if (icg->read_name (icg, in_ti3_name))
error ("CGATS file read error: %s", icg->err);
- if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
- error ("Input file isn't a CTI3 format file");
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other
+ || (icg->t[0].oi != 0 && icg->t[0].oi != 1))
+ error ("Input file isn't a CTI3 or SPECT format file");
+
+ if (icg->t[0].oi == 1)
+ isspect = 1;
+
if (icg->ntables < 1)
error ("Input file doesn't contain at least one table");
/* add table to output file */
-
- ocg->add_table(ocg, tt_other, 0);
+ if (isspect)
+ ocg->add_table(ocg, tt_other, 1);
+ else
+ ocg->add_table(ocg, tt_other, 0);
/* copy keywords */
@@ -370,19 +415,39 @@ main(int argc, char *argv[])
}
}
- if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
- error ("Input file doesn't contain keyword DEVICE_CLASS");
-
- /* Reflective options when not a reflective profile type */
- if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
- || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
- isemis = 1;
- if (illum != icxIT_none)
- error("-i illuminant can't be used for emissive reference type");
- if (fwacomp)
- error("-f FWA compensation can't be used for emissive reference type");
- fwacomp = 0;
- tillum = icxIT_none;
+ if (isspect) {
+ if ((dti = icg->find_kword (icg, 0, "MEAS_TYPE")) < 0)
+ error ("Input file doesn't contain keyword MEAS_TYPE");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"EMISSION") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISSION_FLASH") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT_FLASH") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
+
+ } else {
+ if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
}
/* Set defaults */
@@ -392,26 +457,30 @@ main(int argc, char *argv[])
if (observ == icxOT_none)
observ = icxOT_CIE_1931_2;
- /* Figure out what sort of device it is */
+ /* See if the display CIE data has been normalised to Y = 100 */
{
int ti;
- char *tos;
-
- if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
- isdisp = 1;
- }
- /* See if the display CIE data has been normalised to Y = 100 */
if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
|| strcmp(icg->t[0].kdata[ti],"NO") == 0) {
isdnormed = 0;
} else {
isdnormed = 1;
}
+ }
+
+ /* Figure out what sort of device it is */
+ if (icg->find_kword(icg, 0, "COLOR_REP") >= 0) {
+ int ti;
+ char *tos;
if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
error("Input file doesn't contain keyword COLOR_REP");
+ if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
+ isdisp = 1;
+ }
+
if ((tos = strchr(icg->t[0].kdata[ti], '_')) == NULL)
tos = icg->t[0].kdata[ti];
@@ -513,7 +582,7 @@ main(int argc, char *argv[])
/* Read in the CGATs fields */
{
- int sidx; /* Sample ID index */
+// int sidx; /* Sample ID index */
int ti, ii;
int Xi, Yi, Zi, Li, ai, bi; /* CGATS indexes for each field */
int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
@@ -528,10 +597,12 @@ main(int argc, char *argv[])
xspect mwsp; /* FWA compensated medium white spectrum */
double mwXYZ[3]; /* Media white XYZ */
+#ifdef NEVER
if ((sidx = icg->find_field (icg, 0, "SAMPLE_ID")) < 0)
error ("Input file doesn't contain field SAMPLE_ID");
if (icg->t[0].ftype[sidx] != nqcs_t)
error ("Field SAMPLE_ID is wrong type");
+#endif
/* Using spectral data */
@@ -628,14 +699,28 @@ main(int argc, char *argv[])
error("Out of memory");
}
+ /* If CIE calculation illuminant is not standard, compute it's white point */
+ if (illum != icxIT_D50) {
+ ill_wp = _ill_wp;
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(ill_wp, observ, cust_observ, illum, 0.0, &cust_illum) != 0)
+ error("icx_ill_sp2XYZ returned error");
+ }
+
/* Create a spectral conversion object */
- if ((sp2cie = new_xsp2cie (illum,
- illum == icxIT_none ? NULL : &cust_illum,
- observ, cust_observ, icSigXYZData, icxClamp)) == NULL)
+ if ((sp2cie = new_xsp2cie(illum, &cust_illum, observ, cust_observ,
+ icSigXYZData, icxClamp)) == NULL)
{
error ("Creation of spectral conversion object failed");
}
+ if (fwacomp && devspace == icmSigDefaultData) {
+ // In theory could fake white spectra by accumulating max of
+ // all values as an alternative.
+ error ("No device values, so can't locate white patch for FWA compensation");
+ }
+
if (fwacomp) {
double nw = 0.0; /* Number of media white patches */
@@ -741,6 +826,8 @@ main(int argc, char *argv[])
}
}
+ /* Enable FWA, and use tillump as instrument illuminant if */
+ /* it is set, else use observer illuminant set by new_xsp2cie(). */
/* (Note that sp and mwsp.norm is set to 100.0) */
if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
error ("Set FWA on sp2cie failed");
@@ -755,6 +842,15 @@ main(int argc, char *argv[])
sp2cie->sconvert (sp2cie, &rmwsp, mwXYZ, &mwsp);
}
+ /* If CIE conversion illuminant is non-standard, add it to the output */
+ if (ill_wp != NULL) {
+ char buf[100];
+
+ sprintf(buf,"%f %f %f", ill_wp[0], ill_wp[1], ill_wp[2]);
+ ocg->add_kword(ocg, 0, "ILLUMINANT_WHITE_POINT_XYZ",buf, NULL);
+ }
+
+ /* Transform patches from spectral to CIE */
for (i = 0; i < npat; i++) {
xspect corr_sp;