diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-09-01 13:56:46 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-09-01 13:56:46 +0200 |
commit | 22f703cab05b7cd368f4de9e03991b7664dc5022 (patch) | |
tree | 6f4d50beaa42328e24b1c6b56b6ec059e4ef21a5 /spectro/spotread.c |
Initial import of argyll version 1.5.1-8debian/1.5.1-8
Diffstat (limited to 'spectro/spotread.c')
-rw-r--r-- | spectro/spotread.c | 2271 |
1 files changed, 2271 insertions, 0 deletions
diff --git a/spectro/spotread.c b/spectro/spotread.c new file mode 100644 index 0000000..3218243 --- /dev/null +++ b/spectro/spotread.c @@ -0,0 +1,2271 @@ + + /* Spectrometer/Colorimeter color spot reader utility */ + +/* + * Argyll Color Correction System + * Author: Graeme W. Gill + * Date: 3/10/2001 + * + * Derived from printread.c/chartread.c + * Was called printspot. + * + * Copyright 2001 - 2013 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :- + * see the License2.txt file for licencing details. + */ + +/* This program reads a spot reflection/transmission/emission value using */ +/* a spectrometer or colorimeter. */ + +/* TTBD + * + * Should fix plot so that it is a separate object running its own thread, + * so that it can be sent a graph without needing to be clicked in all the time. + * + * Should add option to show reflective/tranmsission density values. + * + * Should add option for Y u' v' values. + */ + +#undef DEBUG +#undef TEST_EVENT_CALLBACK /* Report async event callbacks */ + +#define COMPORT 1 /* Default com port 1..4 */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <sys/types.h> +#include <fcntl.h> +#include <time.h> +#include <string.h> +#ifndef SALONEINSTLIB +#include "copyright.h" +#include "aconfig.h" +#include "numlib.h" +#include "cgats.h" +#include "xicc.h" +#include "conv.h" +#include "plot.h" +#else /* SALONEINSTLIB */ +#include "sa_config.h" +#include "numsup.h" +#include "xspect.h" +#include "conv.h" +#endif /* SALONEINSTLIB */ +#include "ccss.h" +#include "ccmx.h" +#include "inst.h" +#include "icoms.h" +#include "instappsup.h" +#include "spyd2setup.h" +#ifdef EN_SPYD2 +#include "spyd2setup.h" +#endif + +#if defined (NT) +#include <conio.h> +#endif + +#ifdef NEVER /* Not currently used */ +/* Convert control chars to ^[A-Z] notation in a string */ +static char * +fix_asciiz(char *s) { + static char buf [200]; + char *d; + for(d = buf; ;) { + if (*s < ' ' && *s > '\000') { + *d++ = '^'; + *d++ = *s++ + '@'; + } else + *d++ = *s++; + if (s[-1] == '\000') + break; + } + return buf; +} +#endif + +#ifdef SALONEINSTLIB + +#define D50_X_100 96.42 +#define D50_Y_100 100.00 +#define D50_Z_100 82.49 + +/* CIE XYZ 0..100 to perceptual D50 CIE 1976 L*a*b* */ +static void +XYZ2Lab(double *out, double *in) { + double X = in[0], Y = in[1], Z = in[2]; + double x,y,z,fx,fy,fz; + + x = X/D50_X_100; + y = Y/D50_Y_100; + z = Z/D50_Z_100; + + if (x > 0.008856451586) + fx = pow(x,1.0/3.0); + else + fx = 7.787036979 * x + 16.0/116.0; + + if (y > 0.008856451586) + fy = pow(y,1.0/3.0); + else + fy = 7.787036979 * y + 16.0/116.0; + + if (z > 0.008856451586) + fz = pow(z,1.0/3.0); + else + fz = 7.787036979 * z + 16.0/116.0; + + out[0] = 116.0 * fy - 16.0; + out[1] = 500.0 * (fx - fy); + out[2] = 200.0 * (fy - fz); +} + +/* Return the normal Delta E given two Lab values */ +static double LabDE(double *Lab0, double *Lab1) { + double rv = 0.0, tt; + + tt = Lab0[0] - Lab1[0]; + rv += tt * tt; + tt = Lab0[1] - Lab1[1]; + rv += tt * tt; + tt = Lab0[2] - Lab1[2]; + rv += tt * tt; + + return sqrt(rv); +} + +/* Lab to LCh */ +void Lab2LCh(double *out, double *in) { + double C, h; + + C = sqrt(in[1] * in[1] + in[2] * in[2]); + + h = (180.0/3.14159265359) * atan2(in[2], in[1]); + h = (h < 0.0) ? h + 360.0 : h; + + out[0] = in[0]; + out[1] = C; + out[2] = h; +} + +/* XYZ to Yxy */ +static void XYZ2Yxy(double *out, double *in) { + double sum = in[0] + in[1] + in[2]; + double Y, x, y; + + if (sum < 1e-9) { + Y = 0.0; + y = 0.0; + x = 0.0; + } else { + Y = in[1]; + x = in[0]/sum; + y = in[1]/sum; + } + out[0] = Y; + out[1] = x; + out[2] = y; +} + +#endif /* SALONEINSTLIB */ + +/* Replacement for gets */ +char *getns(char *buf, int len) { + int i; + if (fgets(buf, len, stdin) == NULL) + return NULL; + + for (i = 0; i < len; i++) { + if (buf[i] == '\n') { + buf[i] = '\000'; + return buf; + } + } + buf[len-1] = '\000'; + return buf; +} + +/* Deal with an instrument error. */ +/* Return 0 to retry, 1 to abort */ +static int ierror(inst *it, inst_code ic) { + int ch; + empty_con_chars(); + printf("Got '%s' (%s) error.\nHit Esc or Q to give up, any other key to retry:", + it->inst_interp_error(it, ic), it->interp_error(it, ic)); + fflush(stdout); + ch = next_con_char(); + printf("\n"); + if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q') /* Escape, ^C or Q */ + return 1; + return 0; +} + +/* A color structure */ +/* This can hold all representations simultaniously */ +typedef struct { + double gy; + double r,g,b; + double cmyk[4]; + double XYZ[4]; /* Colorimeter readings */ + double eXYZ[4]; /* Expected XYZ values */ + xspect sp; /* Spectral reading */ + + char *id; /* Id string */ + char *loc; /* Location string */ + int loci; /* Location integer = pass * 256 + step */ +} col; + +#ifdef TEST_EVENT_CALLBACK + void test_event_callback(void *cntx, inst_event_type event) { + a1logd(g_log,0,"Got event_callback with 0x%x\n",event); + } +#endif + +#if defined(__APPLE__) && defined(__POWERPC__) + +/* Workaround for a ppc gcc 3.3 optimiser bug... */ +static int gcc_bug_fix(int i) { + static int nn; + nn += i; + return nn; +} +#endif /* APPLE */ + +/* + + Flags used: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ + upper ... . . . . .. ... + lower . .... .. . .. . .. + +*/ + +void +usage(char *diag, ...) { + int i; + icompaths *icmps; + inst2_capability cap2 = 0; + fprintf(stderr,"Measure spot values, Version %s\n",ARGYLL_VERSION_STR); + fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL Version 2 or later\n"); + if (setup_spyd2() == 2) + fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n"); + if (diag != NULL) { + va_list args; + fprintf(stderr,"Diagnostic: "); + va_start(args, diag); + vfprintf(stderr, diag, args); + va_end(args); + fprintf(stderr,"\n"); + } + fprintf(stderr,"usage: spotread [-options] [logfile]\n"); + fprintf(stderr," -v Verbose mode\n"); + fprintf(stderr," -s Print spectrum for each reading\n"); +#ifndef SALONEINSTLIB + fprintf(stderr," -S Plot spectrum for each reading\n"); +#endif /* !SALONEINSTLIB */ + fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT); + if ((icmps = new_icompaths(g_log)) != NULL) { + icompath **paths; + if ((paths = icmps->paths) != NULL) { + int i; + for (i = 0; ; i++) { + if (paths[i] == NULL) + break; + if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0) + fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name); + else + fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name); + } + } else + fprintf(stderr," ** No ports found **\n"); + } + fprintf(stderr," -t Use transmission measurement mode\n"); + fprintf(stderr," -e Use emissive measurement mode (absolute results)\n"); + fprintf(stderr," -eb Use display white brightness relative measurement mode\n"); + fprintf(stderr," -ew Use display white relative measurement mode\n"); + fprintf(stderr," -p Use telephoto measurement mode (absolute results)\n"); + fprintf(stderr," -pb Use projector white brightness relative measurement mode\n"); + fprintf(stderr," -pw Use projector white relative measurement mode\n"); + fprintf(stderr," -a Use ambient measurement mode (absolute results)\n"); + fprintf(stderr," -f Use ambient flash measurement mode (absolute results)\n"); + cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0); +#ifndef SALONEINSTLIB + fprintf(stderr," -I illum Set simulated instrument illumination using FWA (def -i illum):\n"); + fprintf(stderr," M0, M1, M2, A, C, D50, D50M2, D65, F5, F8, F10 or file.sp]\n"); +#endif + fprintf(stderr," -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n"); +#ifndef SALONEINSTLIB + fprintf(stderr," A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n"); +#else + fprintf(stderr," A, C, D50 (def.), D65\n"); +#endif + fprintf(stderr," -Q observ Choose CIE Observer for spectral data or CCSS instrument:\n"); +#ifndef SALONEINSTLIB + fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n"); +#else + fprintf(stderr," 1931_2 (def), 1964_10\n"); +#endif +#ifndef SALONEINSTLIB + fprintf(stderr," (Choose FWA during operation)\n"); +#endif + fprintf(stderr," -F filter Set filter configuration (if aplicable):\n"); + fprintf(stderr," n None\n"); + fprintf(stderr," p Polarising filter\n"); + fprintf(stderr," 6 D65\n"); + fprintf(stderr," u U.V. Cut\n"); + fprintf(stderr," -E extrafilterfile Apply extra filter compensation file\n"); + fprintf(stderr," -x Display Yxy instead of Lab\n"); + fprintf(stderr," -h Display LCh instead of Lab\n"); + fprintf(stderr," -V Show running average and std. devation from ref.\n"); +#ifndef SALONEINSTLIB + fprintf(stderr," -T Display correlated color temperatures and CRI\n"); +#endif /* !SALONEINSTLIB */ +// fprintf(stderr," -K type Run instrument calibration first\n"); + fprintf(stderr," -N Disable auto calibration of instrument\n"); + fprintf(stderr," -H Start in high resolution spectrum mode (if available)\n"); + if (cap2 & inst2_ccmx) + fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix\n"); + if (cap2 & inst2_ccss) { + fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n"); + } + fprintf(stderr," -Y r|n Override refresh, non-refresh display mode\n"); + fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n"); +// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n"); + fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n"); + fprintf(stderr," -D [level] Print debug diagnostics to stderr\n"); + fprintf(stderr," logfile Optional file to save reading results as text\n"); + + if (icmps != NULL) + icmps->del(icmps); + exit(1); +} + +int main(int argc, char *argv[]) { + int i, j; + int fa, nfa, mfa; /* current argument we're looking at */ + int verb = 0; + int debug = 0; + int docalib = 0; /* Do a manual instrument calibration */ + int nocal = 0; /* Disable auto calibration */ + int pspec = 0; /* 1 = Print out the spectrum for each reading */ + /* 2 = Plot out the spectrum for each reading */ + int trans = 0; /* Use transmissioin mode */ + int emiss = 0; /* 1 = Use emissive mode, 2 = display bright rel. */ + /* 3 = display white rel. */ + int tele = 0; /* 1 = Use telephoto emissive sub-mode. */ + int ambient = 0; /* 1 = Use ambient emissive mode, 2 = ambient flash mode */ + int highres = 0; /* Use high res mode if available */ + int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */ + int refrmode = -1; /* -1 = default, 0 = non-refresh mode, 1 = non-refresh mode */ + int nadaptive = 0; /* Use non-apative mode if available */ + int doYxy= 0; /* Display Yxy instead of Lab */ + int doLCh= 0; /* Display LCh instead of Lab */ + int doCCT= 0; /* Display correlated color temperatures */ + inst_mode mode = 0, smode = 0; /* Normal mode and saved readings mode */ + inst_opt_type trigmode = inst_opt_unknown; /* Chosen trigger mode */ + inst_opt_filter fe = inst_opt_filter_unknown; + /* Filter configuration */ + char outname[MAXNAMEL+1] = "\000"; /* Output logfile name */ + char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */ + char filtername[MAXNAMEL+1] = "\000"; /* Filter compensation */ + FILE *fp = NULL; /* Logfile */ + icompaths *icmps = NULL; + int comport = COMPORT; /* COM port used */ + icompath *ipath = NULL; + int dtype = 0; /* Display type selection charater */ + inst_mode cap = inst_mode_none; /* Instrument mode capabilities */ + inst2_capability cap2 = inst2_none; /* Instrument capabilities 2 */ + inst3_capability cap3 = inst3_none; /* Instrument capabilities 3 */ + double lx, ly; /* Read location on xy table */ + baud_rate br = baud_38400; /* Target baud rate */ + flow_control fc = fc_nc; /* Default flow control */ + inst *it; /* Instrument object */ + inst_code rv; + int uswitch = 0; /* Instrument switch is enabled */ + int spec = 0; /* Need spectral data for observer/illuminant flag */ + icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */ + xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */ + icxIllumeType illum = icxIT_D50; /* Spectral defaults */ + xspect cust_illum; /* Custom illumination spectrum */ + icxObserverType obType = icxOT_default; + xspect sp; /* Last spectrum read */ + xspect rsp; /* Reference spectrum */ + xsp2cie *sp2cie = NULL; /* default conversion */ + xsp2cie *sp2cief[26]; /* FWA corrected conversions */ + double wXYZ[3] = { -10.0, 0, 0 };/* White XYZ for display white relative */ + double Lab[3] = { -10.0, 0, 0}; /* Last Lab */ + double rXYZ[3] = { 0.0, -10.0, 0}; /* Reference XYZ */ + double rLab[3] = { -10.0, 0, 0}; /* Reference Lab */ + double Yxy[3] = { 0.0, 0, 0}; /* Yxy value */ + double LCh[3] = { 0.0, 0, 0}; /* LCh value */ + double refstats = 0; /* Print running avg & stddev against ref */ + double rstat_n; /* Stats N */ + double rstat_XYZ[3]; /* Stats sum of XYZ's */ + double rstat_XYZsq[3]; /* Stats sum of XYZ's squared */ + double rstat_Lab[3]; /* Stats sum of Lab's */ + double rstat_Labsq[3]; /* Stats sum of Lab's squared */ + int savdrd = 0; /* At least one saved reading is available */ + int ix; /* Reading index number */ + int loghead = 0; /* NZ if log file heading has been printed */ + + set_exe_path(argv[0]); /* Set global exe_path and error_program */ + check_if_not_interactive(); + setup_spyd2(); /* Load firware if available */ + + for (i = 0; i < 26; i++) + sp2cief[i] = NULL; + + sp.spec_n = 0; + rsp.spec_n = 0; + + /* Process the arguments */ + mfa = 0; /* Minimum final arguments */ + for(fa = 1;fa < argc;fa++) { + nfa = fa; /* skip to nfa if next argument is used */ + if (argv[fa][0] == '-') { /* Look for any flags */ + char *na = NULL; /* next argument after flag, null if none */ + + if (argv[fa][2] != '\000') + na = &argv[fa][2]; /* next is directly after flag */ + else { + if ((fa+1+mfa) < argc) { + if (argv[fa+1][0] != '-') { + nfa = fa + 1; + na = argv[nfa]; /* next is seperate non-flag argument */ + } + } + } + + if (argv[fa][1] == 'D') { + debug = 1; + if (na != NULL && na[0] >= '0' && na[0] <= '9') { + debug = atoi(na); + fa = nfa; + } + g_log->debug = debug; + } else if (argv[fa][1] == '?') { + usage("Usage requested"); + + } else if (argv[fa][1] == 'v') { + verb = 1; + g_log->verb = verb; + + } else if (argv[fa][1] == 's') { + pspec = 1; + +#ifndef SALONEINSTLIB + } else if (argv[fa][1] == 'S') { + pspec = 2; +#endif /* !SALONEINSTLIB */ + + /* COM port */ + } else if (argv[fa][1] == 'c') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -c"); + comport = atoi(na); + if (comport < 1 || comport > 40) usage("-c parameter %d out of range",comport); + + /* Display type */ + } else if (argv[fa][1] == 'y') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -y"); + dtype = na[0]; + +#ifndef SALONEINSTLIB + /* Simulated instrument illumination (FWA) */ + } else if (argv[fa][1] == 'I') { + + fa = nfa; + if (na == NULL) usage("Paramater expected following -I"); + if (strcmp(na, "A") == 0 + || strcmp(na, "M0") == 0) { + spec = 1; + tillum = icxIT_A; + } else if (strcmp(na, "C") == 0) { + spec = 1; + tillum = icxIT_C; + } else if (strcmp(na, "D50") == 0 + || strcmp(na, "M1") == 0) { + spec = 1; + tillum = icxIT_D50; + } else if (strcmp(na, "D50M2") == 0 + || strcmp(na, "M2") == 0) { + spec = 1; + tillum = icxIT_D50M2; + } else if (strcmp(na, "D65") == 0) { + spec = 1; + tillum = icxIT_D65; + } else if (strcmp(na, "F5") == 0) { + spec = 1; + tillum = icxIT_F5; + } else if (strcmp(na, "F8") == 0) { + spec = 1; + tillum = icxIT_F8; + } else if (strcmp(na, "F10") == 0) { + spec = 1; + tillum = icxIT_F10; + } else { /* Assume it's a filename */ + spec = 1; + tillum = icxIT_custom; + if (read_xspect(&cust_tillum, na) != 0) + usage("Failed to read custom target illuminant spectrum in file '%s'",na); + } +#endif /* SALONEINSTLIB */ + + /* Spectral Illuminant type for XYZ computation */ + } else if (argv[fa][1] == 'i') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -i"); + if (strcmp(na, "A") == 0) { + spec = 1; + illum = icxIT_A; + } else if (strcmp(na, "C") == 0) { + spec = 1; + illum = icxIT_C; + } else if (strcmp(na, "D50") == 0) { + spec = 1; + illum = icxIT_D50; + } else if (strcmp(na, "D50M2") == 0) { + spec = 1; + illum = icxIT_D50M2; + } else if (strcmp(na, "D65") == 0) { + spec = 1; + illum = icxIT_D65; +#ifndef SALONEINSTLIB + } else if (strcmp(na, "F5") == 0) { + spec = 1; + illum = icxIT_F5; + } else if (strcmp(na, "F8") == 0) { + spec = 1; + illum = icxIT_F8; + } else if (strcmp(na, "F10") == 0) { + spec = 1; + illum = icxIT_F10; + } else { /* Assume it's a filename */ + spec = 1; + illum = icxIT_custom; + if (read_xspect(&cust_illum, na) != 0) + usage("Unable to read custom illuminant file '%s'",na); + } +#else /* SALONEINSTLIB */ + } else + usage("Unrecognised illuminant '%s'",na); +#endif /* SALONEINSTLIB */ + + /* Spectral Observer type */ + } else if (argv[fa][1] == 'Q') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -Q"); + if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */ + obType = icxOT_CIE_1931_2; + } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */ + obType = icxOT_CIE_1964_10; +#ifndef SALONEINSTLIB + } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */ + obType = icxOT_Stiles_Burch_2; + } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */ + obType = icxOT_Judd_Voss_2; + } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */ + obType = icxOT_Shaw_Fairchild_2; +#endif /* !SALONEINSTLIB */ + } else + usage("Spectral observer type '%s' not recognised",na); + + /* Request transmission measurement */ + } else if (argv[fa][1] == 't') { + emiss = 0; + trans = 1; + tele = 0; + ambient = 0; + + /* Request emissive measurement */ + } else if (argv[fa][1] == 'e' || argv[fa][1] == 'd') { + + if (argv[fa][1] == 'd') + warning("spotread -d flag is deprecated"); + + emiss = 1; + trans = 0; + tele = 0; + ambient = 0; + + if (argv[fa][2] != '\000') { + if (argv[fa][2] == 'b' || argv[fa][2] == 'B') + emiss = 2; + else if (argv[fa][2] == 'w' || argv[fa][2] == 'W') + emiss = 3; + else + usage("-d modifier '%c' not recognised",argv[fa][2]); + } + + /* Request telephoto measurement */ + } else if (argv[fa][1] == 'p') { + + emiss = 1; + trans = 0; + tele = 1; + ambient = 0; + + if (argv[fa][2] != '\000') { + fa = nfa; + if (argv[fa][2] == 'b' || argv[fa][2] == 'B') + emiss = 2; + else if (argv[fa][2] == 'w' || argv[fa][2] == 'W') + emiss = 3; + else + usage("-p modifier '%c' not recognised",argv[fa][2]); + } + + /* Request ambient measurement */ + } else if (argv[fa][1] == 'a') { + emiss = 1; + trans = 0; + tele = 0; + ambient = 1; + + /* Request ambient flash measurement */ + } else if (argv[fa][1] == 'f') { + emiss = 1; + trans = 0; + tele = 0; + ambient = 2; + + /* Filter configuration */ + } else if (argv[fa][1] == 'F') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -F"); + if (na[0] == 'n' || na[0] == 'N') + fe = inst_opt_filter_none; + else if (na[0] == 'p' || na[0] == 'P') + fe = inst_opt_filter_pol; + else if (na[0] == '6') + fe = inst_opt_filter_D65; + else if (na[0] == 'u' || na[0] == 'U') + fe = inst_opt_filter_UVCut; + else + usage("-F type '%c' not recognised",na[0]); + + /* Extra filter compensation file */ + } else if (argv[fa][1] == 'E') { + fa = nfa; + if (na == NULL) usage("Paramater expected following -E"); + strncpy(filtername,na,MAXNAMEL-1); filtername[MAXNAMEL-1] = '\000'; + + /* Show Yxy */ + } else if (argv[fa][1] == 'x') { + doYxy = 1; + doLCh = 0; + + /* Show LCh */ + } else if (argv[fa][1] == 'h') { + doYxy = 0; + doLCh = 1; + + /* Compute running average and standard deviation from ref. */ + /* Also turns off clamping */ + } else if (argv[fa][1] == 'V') { + refstats = 1; +#ifndef SALONEINSTLIB + + /* Show CCT etc. */ + } else if (argv[fa][1] == 'T') { + doCCT = 1; +#endif /* !SALONEINSTLIB */ + + /* Manual calibration */ + } else if (argv[fa][1] == 'K') { + + if (na != NULL && na[0] >= '0' && na[0] <= '9') { + docalib = atoi(na); + fa = nfa; + } else + usage("-K parameter '%c' not recognised",na[0]); + + /* No auto calibration */ + } else if (argv[fa][1] == 'N') { + nocal = 1; + + /* High res mode */ + } else if (argv[fa][1] == 'H') { + highres = 1; + + /* Colorimeter Correction Matrix or */ + /* Colorimeter Calibration Spectral Samples */ + } else if (argv[fa][1] == 'X') { + int ix; + fa = nfa; + if (na == NULL) usage("Parameter expected after -K"); + strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000'; + + /* Serial port flow control */ + } else if (argv[fa][1] == 'W') { + fa = nfa; + if (na == NULL) usage("Parameter expected after -W"); + if (na[0] == 'n' || na[0] == 'N') + fc = fc_none; + else if (na[0] == 'h' || na[0] == 'H') + fc = fc_Hardware; + else if (na[0] == 'x' || na[0] == 'X') + fc = fc_XonXOff; + else + usage("-W parameter '%c' not recognised",na[0]); + + /* Extra flags */ + } else if (argv[fa][1] == 'Y') { + if (na == NULL) + usage("Parameter expected after -Y"); + + if (na[0] == 'A') { + nadaptive = 1; + } else if (na[0] == 'r') { + refrmode = 1; + } else if (na[0] == 'n') { + refrmode = 0; + /* ~~~ i1pro2 test code ~~~ */ + } else if (na[0] == 'U') { + uvmode = 1; + } else { + usage("-Y parameter '%c' not recognised",na[0]); + } + + } else + usage("Flag -%c not recognised",argv[fa][1]); + } + else + break; + } + + /* Get the optional file name argument */ + if (fa < argc) { + strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000'; + if ((fp = fopen(outname, "w")) == NULL) + error("Unable to open logfile '%s' for writing\n",outname); + } + + + /* See if there is an environment variable ccxx */ + if (ccxxname[0] == '\000') { + char *na; + if ((na = getenv("ARGYLL_COLMTER_CAL_SPEC_SET")) != NULL) { + strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000'; + + } else if ((na = getenv("ARGYLL_COLMTER_COR_MATRIX")) != NULL) { + strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000'; + } + } + + /* - - - - - - - - - - - - - - - - - - - */ + if ((icmps = new_icompaths(g_log)) == NULL) + error("Finding instrument paths failed"); + if ((ipath = icmps->get_path(icmps, comport)) == NULL) + error("No instrument at port %d",comport); + + + /* Setup the instrument ready to do reads */ + if ((it = new_inst(ipath, 0, g_log, DUIH_FUNC_AND_CONTEXT)) == NULL) { + usage("Unknown, inappropriate or no instrument detected"); + } + +#ifdef TEST_EVENT_CALLBACK + it->set_event_callback(it, test_event_callback, (void *)it); +#endif + + if (verb) + printf("Connecting to the instrument ..\n"); + +#ifdef DEBUG + printf("About to init the comms\n"); +#endif + + /* Establish communications */ + if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) { + printf("Failed to initialise communications with instrument\n" + "or wrong instrument or bad configuration!\n" + "('%s' + '%s')\n", it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + +#ifdef DEBUG + printf("Established comms\n"); +#endif + +#ifdef DEBUG + printf("About to init the instrument\n"); +#endif + + /* set filter configuration before initialising/calibrating */ + if (fe != inst_opt_filter_unknown) { + if ((rv = it->get_set_opt(it, inst_opt_set_filter, fe)) != inst_ok) { + printf("Setting filter configuration not supported by instrument\n"); + it->del(it); + return -1; + } + } + + /* Initialise the instrument */ + if ((rv = it->init_inst(it)) != inst_ok) { + printf("Instrument initialisation failed with '%s' (%s)!\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + + /* Configure the instrument mode */ + { + int ccssset = 0; + it->capabilities(it, &cap, &cap2, &cap3); + + /* Don't fail if the instrument has only one mode, and */ + /* it's not been selected */ + + if (trans == 0 && emiss == 0 && !IMODETST(cap, inst_mode_reflection)) { + /* This will fail. Switch to a mode the instrument has */ + if (IMODETST(cap, inst_mode_emission)) { + if (verb) + printf("Defaulting to emission measurement\n"); + emiss = 1; + + } else if (IMODETST(cap, inst_mode_transmission)) { + if (verb) + printf("Defaulting to transmission measurement\n"); + trans = 1; + } + } + + if (trans) { + if (!IMODETST(cap, inst_mode_trans_spot) + || it->check_mode(it, inst_mode_trans_spot) != inst_ok) { + printf("Need transmission spot capability,\n"); + printf("and instrument doesn't support it\n"); + it->del(it); + return -1; + } + + } else if (ambient == 1) { + if (!IMODETST(cap, inst_mode_emis_ambient) + || it->check_mode(it, inst_mode_emis_ambient) != inst_ok) { + printf("Requested ambient light capability,\n"); + printf("and instrument doesn't support it.\n"); + if (!IMODETST(cap, inst_mode_emis_spot)) { + it->del(it); + return -1; + } else { + printf("Will use emissive mode instead,\n"); + printf("but note that light level readings may be wrong!\n"); + + } + } else { + if (verb) { + printf("Please make sure the instrument is fitted with\n"); + printf("the appropriate ambient light measuring head\n"); + } + } + + } else if (ambient == 2) { + if (!IMODETST(cap, inst_mode_emis_ambient_flash) + || it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) { + printf("Requested ambient flash capability,\n"); + printf("and instrument doesn't support it.\n"); + it->del(it); + return -1; + } else { + if (verb) { + printf("Please make sure the instrument is fitted with\n"); + printf("the appropriate ambient light measuring head, and that\n"); + printf("you are ready to trigger the flash.\n"); + } + } + + } else if (emiss || tele) { + + if (tele) { + if (!IMODETST(cap, inst_mode_emis_tele) + || it->check_mode(it, inst_mode_emis_tele) != inst_ok) { + printf("Need telephoto spot capability\n"); + printf("and instrument doesn't support it\n"); + it->del(it); + return -1; + } + } else { + if (!IMODETST(cap, inst_mode_emis_spot) + || it->check_mode(it, inst_mode_emis_spot) != inst_ok) { + printf("Need emissive spot capability\n"); + printf("and instrument doesn't support it\n"); + it->del(it); + return -1; + } + } + + if (nadaptive && !IMODETST(cap, inst_mode_emis_nonadaptive)) { + if (verb) { + printf("Requested non-adaptive mode and instrument doesn't support it (ignored)\n"); + nadaptive = 0; + } + } + if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd) + && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) { + if (verb) { + printf("Requested refresh mode override and instrument doesn't support it (ignored)\n"); + refrmode = -1; + } + } + + /* Set display type */ + if (dtype != 0) { + + if (cap2 & inst2_disptype) { + int ix; + if ((ix = inst_get_disptype_index(it, dtype, 0)) < 0) { + it->del(it); + usage("Failed to locate display type matching '%c'",dtype); + } + + if ((rv = it->set_disptype(it, ix)) != inst_ok) { + printf("Setting display type ix %d not supported by instrument\n",ix); + it->del(it); + return -1; + } + } else + printf("Display type ignored - instrument doesn't support display type\n"); + } + + } else { + if (!IMODETST(cap, inst_mode_ref_spot) + || it->check_mode(it, inst_mode_ref_spot) != inst_ok) { + printf("Need reflection spot reading capability,\n"); + printf("and instrument doesn't support it\n"); + it->del(it); + return -1; + } + } + + /* If we have non-standard observer we need spectral or CCSS */ + if (obType != icxOT_default && !IMODETST(cap, inst_mode_spectral) && !(cap2 & inst2_ccss)) { + printf("Non standard observer needs spectral information or CCSS capability\n"); + printf("and instrument doesn't support either.\n"); + it->del(it); + return -1; + } + + /* If we don't have CCSS then we need spectral for non-standard observer */ + if (obType != icxOT_default && (cap2 & inst2_ccss) == 0) { + spec = 1; + } + + if ((spec || pspec) && !IMODETST(cap, inst_mode_spectral)) { + printf("Need spectral information for custom illuminant or observer\n"); + printf("and instrument doesn't support it\n"); + it->del(it); + return -1; + } + + /* Disable initial calibration of machine if selected */ + if (nocal != 0) { + if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) { + printf("Setting no-initial calibrate failed with '%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + printf("Disable initial-calibrate not supported\n"); + } + } + if (highres) { + if (IMODETST(cap, inst_mode_highres)) { + inst_code ev; + if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) { + printf("\nSetting high res mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + highres = 1; + } else if (verb) { + printf("high resolution ignored - instrument doesn't support high res. mode\n"); + } + } + + /* Set it to the appropriate mode */ + + /* Should look at instrument type & user spec ??? */ + if (trans) + smode = mode = inst_mode_trans_spot; + else if (ambient == 1 && IMODETST(cap, inst_mode_emis_ambient) + && it->check_mode(it, inst_mode_emis_ambient) == inst_ok) + smode = mode = inst_mode_emis_ambient; + else if (ambient == 2 && IMODETST(cap, inst_mode_emis_ambient_flash) + && it->check_mode(it, inst_mode_emis_ambient_flash) == inst_ok) + smode = mode = inst_mode_emis_ambient_flash; + else if (tele) // Hmm. What about tele flash ? + smode = mode = inst_mode_emis_tele; + else if (emiss || ambient) + smode = mode = inst_mode_emis_spot; + else { + smode = mode = inst_mode_ref_spot; + if (IMODETST(cap, inst_mode_s_ref_spot) + && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) + smode = inst_mode_s_ref_spot; + } + + /* Mode dependent extra modes */ + if (emiss || tele) { + if (nadaptive) { + mode |= inst_mode_emis_nonadaptive; + smode |= inst_mode_emis_nonadaptive; + } + if (refrmode == 0) { + mode |= inst_mode_emis_norefresh_ovd; + smode |= inst_mode_emis_norefresh_ovd; + } + else if (refrmode == 1) { + mode |= inst_mode_emis_refresh_ovd; + smode |= inst_mode_emis_refresh_ovd; + } + } + + /* Use spec if requested or if available in case of CRI or FWA */ + if (spec || pspec || IMODETST(cap, inst_mode_spectral)) { + mode |= inst_mode_spectral; + smode |= inst_mode_spectral; + } + + // ~~~ i1pro2 test code ~~~ */ + if (uvmode) { + if (!IMODETST(cap, inst_mode_ref_uv)) { + printf("UV measurement mode requested, but instrument doesn't support this mode\n"); + it->del(it); + return -1; + } + mode |= inst_mode_ref_uv; + smode |= inst_mode_ref_uv; + } + + if ((rv = it->set_mode(it, mode)) != inst_ok) { + printf("\nSetting instrument mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + it->capabilities(it, &cap, &cap2, &cap3); + + /* Apply Extra filter compensation */ + if (filtername[0] != '\000') { + if ((rv = it->comp_filter(it, filtername)) != inst_ok) { + printf("\nSetting filter compensation failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + } + + /* Colorimeter Correction Matrix */ + if (ccxxname[0] != '\000') { + ccss *cs = NULL; + ccmx *cx = NULL; + + if ((cx = new_ccmx()) == NULL) { + printf("\nnew_ccmx failed\n"); + it->del(it); + return -1; + } + if (cx->read_ccmx(cx,ccxxname) == 0) { + if ((cap2 & inst2_ccmx) == 0) { + printf("\nInstrument doesn't have Colorimeter Correction Matrix capability\n"); + it->del(it); + return -1; + } + if ((rv = it->col_cor_mat(it, cx->matrix)) != inst_ok) { + printf("\nSetting Colorimeter Correction Matrix failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + cx->del(cx); + it->del(it); + return -1; + } + cx->del(cx); + + } else { + cx->del(cx); + cx = NULL; + + /* CCMX failed, try CCSS */ + if ((cs = new_ccss()) == NULL) { + printf("\nnew_ccss failed\n"); + it->del(it); + return -1; + } + if (cs->read_ccss(cs,ccxxname)) { + printf("\nReading CCMX/CCSS File '%s' failed with error %d:'%s'\n", + ccxxname, cs->errc, cs->err); + cs->del(cs); + it->del(it); + return -1; + } + if ((cap2 & inst2_ccss) == 0) { + printf("\nInstrument doesn't have Colorimeter Calibration Spectral Sample capability\n"); + cs->del(cs); + it->del(it); + return -1; + } + if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, NULL)) != inst_ok) { + printf("\nSetting CCS Observer failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + cs->del(cs); + it->del(it); + return -1; + } + if ((rv = it->col_cal_spec_set(it, cs->samples, cs->no_samp)) != inst_ok) { + printf("\nSetting Colorimeter Calibration Spectral Samples failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + cs->del(cs); + it->del(it); + return -1; + } + ccssset = 1; + cs->del(cs); + } + } + + /* If non-standard observer wasn't set by a CCSS file above */ + if (obType != icxOT_default && (cap2 & inst2_ccss) && ccssset == 0) { + if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, 0)) != inst_ok) { + printf("\nSetting CCSS Observer failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + } + + /* If it batter powered, show the status of the battery */ + if ((cap2 & inst2_has_battery)) { + double batstat = 0.0; + if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) != inst_ok) { + printf("\nGetting instrument battery status failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + printf("The battery charged level is %.0f%%\n",batstat * 100.0); + } + + /* If it's an instrument that need positioning let user trigger via uicallback */ + /* in spotread, else enable switch or user via uicallback trigger if possible. */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + trigmode = inst_opt_trig_prog; + + } else if (cap2 & inst2_user_switch_trig) { + trigmode = inst_opt_trig_user_switch; + uswitch = 1; + + /* Or go for keyboard trigger */ + } else if (cap2 & inst2_user_trig) { + trigmode = inst_opt_trig_user; + + /* Or something is wrong with instrument capabilities */ + } else { + printf("\nNo reasonable trigger mode avilable for this instrument\n"); + it->del(it); + return -1; + } + if ((rv = it->get_set_opt(it, trigmode)) != inst_ok) { + printf("\nSetting trigger mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + + /* Setup the keyboard trigger to return our commands */ + inst_set_uih(0x0, 0xff, DUIH_TRIG); + inst_set_uih('r', 'r', DUIH_CMND); + inst_set_uih('R', 'R', DUIH_CMND); + inst_set_uih('h', 'h', DUIH_CMND); + inst_set_uih('H', 'H', DUIH_CMND); + inst_set_uih('k', 'k', DUIH_CMND); + inst_set_uih('K', 'K', DUIH_CMND); + inst_set_uih('s', 's', DUIH_CMND); + inst_set_uih('S', 'S', DUIH_CMND); + inst_set_uih('f', 'f', DUIH_CMND); + inst_set_uih('F', 'F', DUIH_CMND); + inst_set_uih('q', 'q', DUIH_ABORT); + inst_set_uih('Q', 'Q', DUIH_ABORT); + inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */ + inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */ + } + +#ifdef DEBUG + printf("About to enter read loop\n"); +#endif + + if (verb) + printf("Init instrument success !\n"); + + if (spec) { + /* Any non-illuminated mode has no illuminant */ + if (emiss || tele || ambient) + illum = icxIT_none; + + /* Create a spectral conversion object */ + if ((sp2cie = new_xsp2cie(illum, &cust_illum, obType, NULL, icSigXYZData, + refstats ? icxNoClamp : icxClamp)) == NULL) + error("Creation of spectral conversion object failed"); + + /* If we are setting a specific simulated instrument illuminant */ + if (tillum != icxIT_none) { + tillump = &cust_tillum; + if (tillum != icxIT_custom) { + if (standardIlluminant(tillump, tillum, 0.0)) { + error("simulated inst. illum. not recognised"); + } + } + } + } + + /* Hold table */ + if (cap2 & inst2_xy_holdrel) { + for (;;) { /* retry loop */ + if ((rv = it->xy_sheet_hold(it)) == inst_ok) + break; + + if (ierror(it, rv)) { + it->xy_clear(it); + it->del(it); + return -1; + } + } + } + + /* Read spots until the user quits */ + for (ix = 1;; ix++) { + ipatch val; + double XYZ[3]; /* XYZ scaled 0..100 or absolute */ + double tXYZ[3]; +#ifndef SALONEINSTLIB + double cct, vct, vdt; + double cct_de, vct_de, vdt_de; +#endif /* !SALONEINSTLIB */ + int ch = '0'; /* Character */ + int sufwa = 0; /* Setup for FWA compensation */ + int dofwa = 0; /* Do FWA compensation */ + int fidx = -1; /* FWA compensated index, default = none */ + + if (savdrd != -1 && IMODETST(cap, inst_mode_s_ref_spot) + && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) { + inst_stat_savdrd sv; + + savdrd = 0; + if ((rv = it->get_set_opt(it, inst_stat_saved_readings, &sv)) != inst_ok) { + printf("\nGetting saved reading status failed with error :'%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + it->del(it); + return -1; + } + if (sv & inst_stat_savdrd_spot) + savdrd = 1; + } + + /* Read a stored value */ + if (savdrd == 1) { + inst_code ev; + + /* Set to saved spot mode */ + if ((ev = it->set_mode(it, smode)) != inst_ok) { + printf("\nSetting instrument mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + it->capabilities(it, &cap, &cap2, &cap3); + + /* Set N and n to be a command */ + inst_set_uih('N', 'N', DUIH_CMND); + inst_set_uih('n', 'n', DUIH_CMND); + + /* Set to keyboard only trigger */ + if ((ev = it->get_set_opt(it, inst_opt_trig_user)) != inst_ok) { + printf("\nSetting trigger mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + + printf("\nThere are saved spot readings in the instrument.\n"); +#ifndef SALONEINSTLIB + printf("Hit [A-Z] to use reading for white and setup FWA compensation (keyed to letter)\n"); + printf("[a-z] to use reading for FWA compensated value from keyed reference\n"); + printf("'r' to set reference, 's' to save spectrum,\n"); +#else /* SALONEINSTLIB */ + printf("Hit 'r' to set reference\n"); +#endif /* SALONEINSTLIB */ + printf("Hit ESC or Q to exit, N to not read saved reading,\n"); + printf("any other key to use reading: "); + fflush(stdout); + + /* Read the sample or get a command */ + rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp); + + ch = inst_get_uih_char(); + + /* Restore the trigger mode */ + if ((ev = it->get_set_opt(it, trigmode)) != inst_ok) { + printf("\nSetting trigger mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + + /* Set N and n to be a trigger */ + inst_set_uih('N', 'N', DUIH_TRIG); + inst_set_uih('n', 'n', DUIH_TRIG); + + /* Set back to read spot mode */ + if ((ev = it->set_mode(it, mode)) != inst_ok) { + printf("\nSetting instrument mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + it->capabilities(it, &cap, &cap2, &cap3); + + /* If user said no to reading stored values */ + if ((rv & inst_mask) == inst_user_abort + && (ch & DUIH_CMND) && ((ch & 0xff) == 'N' || (ch & 0xff) == 'n')) { + printf("\n"); + savdrd = -1; + continue; + } + + /* Do a normal read */ + } else { + + /* Do any needed calibration before the user places the instrument on a desired spot */ + if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) { + inst_code ev; + + printf("\nSpot read needs a calibration before continuing\n"); + + /* save current location */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + for (;;) { /* retry loop */ + if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok) + break; + if (ierror(it, ev) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (ev != inst_ok) { + printf("\nSpot read got abort or error from xy_get_location\n"); + break; /* Abort */ + } + } + + ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL); + if (ev != inst_ok) { /* Abort or fatal error */ + printf("\nSpot read got abort or error from calibration\n"); + break; + } + + /* restore location */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + for (;;) { /* retry loop */ + if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok) + break; + if (ierror(it, ev) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (ev != inst_ok) { + printf("\nSpot read got abort or error from xy_get_location\n"); + break; /* Abort */ + } + } + } + + if (ambient == 2) { /* Flash ambient */ + printf("\nConfigure for ambient, press and hold button, trigger flash then release button,\n"); +#ifndef SALONEINSTLIB + printf("or hit 'r' to set reference, 's' to save spectrum,\n"); +#else /* SALONEINSTLIB */ + printf("or hit 'r' to set reference\n"); +#endif /* SALONEINSTLIB */ + printf("'h' to toggle high res., 'k' to do a calibration\n"); + + } else { + /* If this is an xy instrument: */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + + /* Allow the user to position the instrument */ + for (;;) { /* retry loop */ + if ((rv = it->xy_locate_start(it)) == inst_ok) + break; + if (ierror(it, rv) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (rv != inst_ok) { + printf("\nSpot read got abort or error from xy_locate_start\n"); + break; /* Abort */ + } + + printf("\nUsing the XY table controls, locate the point to measure with the sight,\n"); + + /* Purely manual instrument */ + } else { + + /* If this is display white brightness relative, read the white */ + if ((emiss > 1 || tele > 1) && wXYZ[0] < 0.0) + printf("\nPlace instrument on white reference spot,\n"); + else { + printf("\nPlace instrument on spot to be measured,\n"); + } + } +#ifndef SALONEINSTLIB + printf("and hit [A-Z] to read white and setup FWA compensation (keyed to letter)\n"); + printf("[a-z] to read and make FWA compensated reading from keyed reference\n"); + printf("'r' to set reference, 's' to save spectrum,\n"); + printf("'f' to report cal. refresh rate, 'F' to measure refresh rate\n"); +#else /* SALONEINSTLIB */ + printf("Hit 'r' to set reference\n"); +#endif /* SALONEINSTLIB */ + printf("'h' to toggle high res., 'k' to do a calibration\n"); + } + if (uswitch) + printf("Hit ESC or Q to exit, instrument switch or any other key to take a reading: "); + else + printf("Hit ESC or Q to exit, any other key to take a reading: "); + fflush(stdout); + + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + /* Wait for the user to hit a key */ + for (;;) { + if ((rv = inst_get_uicallback()(inst_get_uicontext(), inst_armed)) != inst_ok) + break; + } + + if (rv == inst_user_abort) { + break; /* Abort */ + + } else if (rv == inst_user_trig) { + inst_code ev; + + /* Take the location set on the sight, and move the instrument */ + /* to take the measurement there. */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + for (;;) { /* retry loop */ + if ((rv = it->xy_get_location(it, &lx, &ly)) == inst_ok) + break; + if (ierror(it, rv) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (rv != inst_ok) { + printf("\nSpot read got abort or error from xy_get_location\n"); + break; /* Abort */ + } + + for (;;) { /* retry loop */ + if ((rv = it->xy_locate_end(it)) == inst_ok) + break; + if (ierror(it, rv) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (rv != inst_ok) { + printf("\nSpot read got abort or error from xy_locate_end\n"); + break; /* Abort */ + } + + for (;;) { /* retry loop */ + if ((rv = it->xy_position(it, 1, lx, ly)) == inst_ok) + break; + if (ierror(it, rv) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (rv != inst_ok) { + printf("\nSpot read got abort or error from xy_position\n"); + break; /* Abort */ + } + } + rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp); + + /* Restore the location the instrument to have the location */ + /* sight over the selected patch. */ + for (;;) { /* retry loop */ + if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok) + break; + if (ierror(it, ev) == 0) /* Ignore */ + continue; + break; /* Abort */ + } + if (ev != inst_ok) { + printf("\nSpot read got abort or error from xy_position\n"); + break; /* Abort */ + } + } + /* else what ? */ + } else { + rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp); + } + } + +#ifdef DEBUG + printf("read_sample returned '%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); +#endif /* DEBUG */ + + /* Get any command or trigger character */ + if ((rv & inst_mask) == inst_user_trig + || (rv & inst_mask) == inst_user_abort) + ch = inst_get_uih_char(); + else + ch = '0'; + + /* Do return after command */ + if ((rv & inst_mask) == inst_user_abort && (ch & DUIH_CMND)) + printf("\n"); + + /* Deal with a user abort */ + if ((rv & inst_mask) == inst_user_abort && (ch & DUIH_ABORT)) { + printf("\n\nSpot read stopped at user request!\n"); + printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout); + ch = next_con_char(); + if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') { + printf("\n"); + break; + } + printf("\n"); + continue; + + /* Deal with a needs calibration */ + } else if ((rv & inst_mask) == inst_needs_cal) { + inst_code ev; + printf("\n\nSpot read failed because instruments needs calibration.\n"); + ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL); + if (ev != inst_ok) { /* Abort or fatal error */ + printf("\nSpot read got abort or error from calibrate\n"); + break; + } + continue; + + /* Deal with a bad sensor position */ + } else if ((rv & inst_mask) == inst_wrong_config) { + printf("\n\nSpot read failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv)); + continue; + + /* Deal with a misread */ + } else if ((rv & inst_mask) == inst_misread) { + empty_con_chars(); + printf("\n\nSpot read failed due to misread (%s)\n",it->interp_error(it, rv)); + printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout); + ch = next_con_char(); + printf("\n"); + if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') { + break; + } + continue; + + /* Deal with a communications error */ + } else if ((rv & inst_mask) == inst_coms_fail) { + empty_con_chars(); + printf("\n\nSpot read failed due to communication problem.\n"); + printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout); + ch = next_con_char(); + if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') { + printf("\n"); + break; + } + printf("\n"); + if (it->icom->port_type(it->icom) == icomt_serial) { + /* Allow retrying at a lower baud rate */ + int tt = it->last_scomerr(it); + if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) { + if (br == baud_57600) br = baud_38400; + else if (br == baud_38400) br = baud_9600; + else if (br == baud_9600) br = baud_4800; + else if (br == baud_9600) br = baud_4800; + else if (br == baud_2400) br = baud_1200; + else br = baud_1200; + } + if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) { + printf("init_coms returned '%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + break; + } + } + continue; + + /* Some fatal error */ + } else if ((rv & inst_mask) != inst_ok + && (rv & inst_mask) != inst_user_trig + && (rv & inst_mask) != inst_user_abort) { + printf("\n\nGot fatal error '%s' (%s)\n", + it->inst_interp_error(it, rv), it->interp_error(it, rv)); + break; + } + + /* Process command or reading */ + ch &= 0xff; + if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') { /* Or ^C */ + break; + } + if (ch == 'H' || ch == 'h') { /* Toggle high res mode */ + if (IMODETST(cap, inst_mode_highres)) { + inst_code ev; + if (highres) { + if ((ev = it->get_set_opt(it, inst_opt_stdres)) != inst_ok) { + printf("\nSetting std res mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + highres = 0; + if (pspec) + loghead = 0; + printf("\n Instrument set to standard resolution spectrum mode\n"); + } else { + if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) { + printf("\nSetting high res mode failed with error :'%s' (%s)\n", + it->inst_interp_error(it, ev), it->interp_error(it, ev)); + it->del(it); + return -1; + } + highres = 1; + if (pspec) + loghead = 0; + printf("\n Instrument set to high resolution spectrum mode\n"); + } + } else { + printf("\n 'H' Command ignored - instrument doesn't support high res. mode\n"); + } + --ix; + continue; + } + if (ch == 'R' || ch == 'r') { /* Make last reading the reference */ + if (Lab[0] >= -9.0) { + rXYZ[0] = XYZ[0]; + rXYZ[1] = XYZ[1]; + rXYZ[2] = XYZ[2]; + rLab[0] = Lab[0]; + rLab[1] = Lab[1]; + rLab[2] = Lab[2]; + if (pspec) { + rsp = sp; /* Save spectral reference too */ + } + if (refstats) { + rstat_n = 1; + for (j = 0; j < 3; j++) { + rstat_XYZ[j] = XYZ[j]; + rstat_XYZsq[j] = XYZ[j] * XYZ[j]; + rstat_Lab[j] = Lab[j]; + rstat_Labsq[j] = Lab[j] * Lab[j]; + } + } + printf("\n Reference is now XYZ: %f %f %f Lab: %f %f %f\n", rXYZ[0], rXYZ[1], rXYZ[2],rLab[0], rLab[1], rLab[2]); + } else { + printf("\n No previous reading to use as reference\n"); + } + --ix; + continue; + } +#ifndef SALONEINSTLIB + if (ch == 'S' || ch == 's') { /* Save last spectral into file */ + if (sp.spec_n > 0) { + char buf[500]; + printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout); + if (getns(buf, 500) != NULL && strlen(buf) > 0) { + if(write_xspect(buf, &sp)) + printf("\nWriting file '%s' failed\n",buf); + else + printf("\nWriting file '%s' succeeded\n",buf); + } else { + printf("\nNo filename, nothing saved\n"); + } + } else { + printf("\nNo previous spectral reading to save to file (Use -s flag ?)\n"); + } + --ix; + continue; + } +#endif /* !SALONEINSTLIB */ + if (ch == 'K' || ch == 'k') { /* Do a calibration */ + inst_code ev; + + printf("\nDoing a calibration\n"); + + /* save current location */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + for (;;) { /* retry loop */ + if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok) + break; + if (ierror(it, ev) == 0) { /* Ignore */ + --ix; + continue; + } + break; /* Abort */ + } + if (ev != inst_ok) { + printf("\nSpot read got abort or error from xy_get_location\n"); + break; /* Abort */ + } + } + + ev = inst_handle_calibrate(it, inst_calt_available, inst_calc_none, NULL, NULL); + if (ev != inst_ok) { /* Abort or fatal error */ + printf("\nSpot read got abort or error from calibrate\n"); + break; + } + + /* restore location */ + if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) { + for (;;) { /* retry loop */ + if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok) + break; + if (ierror(it, ev) == 0) { /* Ignore */ + --ix; + continue; + } + break; /* Abort */ + } + if (ev != inst_ok) { + printf("\nSpot read got abort or error from xy_position"); + break; /* Abort */ + } + } + --ix; + continue; + } + + /* Measure refresh rate */ + if (ch == 'F') { + double refr; + inst_code ev; + + if (!(cap2 & inst2_emis_refr_meas)) { + printf("\nInstrument isn't capable of refresh rate measurement in current mode\n"); + --ix; + continue; + } + + ev = it->read_refrate(it, &refr); + if (ev == inst_unsupported) { + printf("\nInstrument isn't capable of refresh rate measurement in current mode\n"); + --ix; + continue; + } + + if (ev == inst_misread) { + printf("\nNo refresh detectable, or measurement failed\n"); + --ix; + continue; + + } else if (ev != inst_ok) { + if (ierror(it, ev) == 0) { /* Ignore */ + --ix; + continue; + } + break; /* Abort */ + } else { + printf("\nRefresh rate = %f Hz\n",refr); + } + --ix; + continue; + } + + /* Report calibrated refresh rate */ + if (ch == 'f') { + double refr; + inst_code ev; + + if (!(cap2 & inst2_refresh_rate)) { + printf("\nInstrument isn't capable of refresh rate calibration\n"); + --ix; + continue; + } + + ev = it->get_refr_rate(it, &refr); + if (ev == inst_unsupported) { + printf("\nInstrument isn't capable of refresh rate calibration\n"); + --ix; + continue; + + } else if (ev == inst_needs_cal) { + int refrmode; + + printf("\nRefresh rate hasn't been calibrated\n"); + + if ((ev = it->get_set_opt(it, inst_opt_get_dtinfo, &refrmode, NULL)) != inst_ok) { + printf("Can't get curretn refresh mode from instrument\n"); + --ix; + continue; + } + if (!refrmode) { + printf("Instrument isn't set to a refresh display type\n"); + --ix; + continue; + } + + ev = inst_handle_calibrate(it, inst_calt_ref_freq, inst_calc_none, NULL, NULL); + + if (ev != inst_ok) { /* Abort or fatal error */ + printf("\nSpot read got abort or error from calibrate\n"); + if (ierror(it, ev) == 0) { /* Ignore */ + --ix; + continue; + } + break; + } + ev = it->get_refr_rate(it, &refr); + } + + if (ev == inst_misread) { + printf("\nNo refresh, or wasn't able to measure one\n"); + --ix; + continue; + + } else if (ev != inst_ok) { + if (ierror(it, ev) == 0) { /* Ignore */ + --ix; + continue; + } + break; /* Abort */ + } else { + printf("\nRefresh rate = %f Hz\n",refr); + } + --ix; + continue; + } + +#ifndef SALONEINSTLIB + if (ch >= 'A' && ch <= 'Z') { + printf("\nMeasured media to setup FWA compensation slot '%c'\n",ch); + sufwa = 1; + fidx = ch - 'A'; + } + if (ch >= 'a' && ch <= 'z') { + fidx = ch - 'a'; + if (fidx < 0 || sp2cief[fidx] == NULL) { + printf("\nUnable to apply FWA compensation because it wasn't set up\n"); + fidx = -1; + } else { + dofwa = 1; + } + + } + + /* Setup FWA compensation */ + if (sufwa) { + double FWAc; + xspect insp; /* Instrument illuminant */ + + if (val.sp.spec_n <= 0) { + error("Instrument didn't return spectral data"); + } + + if (inst_illuminant(&insp, it->get_itype(it)) != 0) + error ("Instrument doesn't have an FWA illuminent"); + + /* Creat the base conversion object */ + if (sp2cief[fidx] == NULL) { + if ((sp2cief[fidx] = new_xsp2cie(illum, &cust_illum, obType, + NULL, icSigXYZData, refstats ? icxNoClamp : icxClamp)) == NULL) + error("Creation of spectral conversion object failed"); + } + + if (sp2cief[fidx]->set_fwa(sp2cief[fidx], &insp, tillump, &val.sp)) + error ("Set FWA on sp2cie failed"); + + sp2cief[fidx]->get_fwa_info(sp2cief[fidx], &FWAc); + printf("FWA content = %f\n",FWAc); + } +#else /* !SALONEINSTLIB */ + if (sufwa) { + error ("FWA compensation not supported in this version"); + } +#endif /* !SALONEINSTLIB */ + + /* Print and/or plot out spectrum, */ + /* even if it's an FWA setup */ + if (pspec) { + xspect tsp; + + if (val.sp.spec_n <= 0) + error("Instrument didn't return spectral data"); + + tsp = val.sp; /* Temp. save spectral reading */ + + /* Compute FWA corrected spectrum */ + if (dofwa != 0) { + sp2cief[fidx]->sconvert(sp2cief[fidx], &tsp, NULL, &tsp); + } + + printf("Spectrum from %f to %f nm in %d steps\n", + tsp.spec_wl_short, tsp.spec_wl_long, tsp.spec_n); + + for (j = 0; j < tsp.spec_n; j++) + printf("%s%8.3f",j > 0 ? ", " : "", tsp.spec[j]); + printf("\n"); + +#ifndef SALONEINSTLIB + /* Plot the spectrum */ + if (pspec == 2) { + double xx[XSPECT_MAX_BANDS]; + double yy[XSPECT_MAX_BANDS]; + double yr[XSPECT_MAX_BANDS]; + double xmin, xmax, ymin, ymax; + xspect *ss; /* Spectrum range to use */ + int nn; + + if (rsp.spec_n > 0) { + if ((tsp.spec_wl_long - tsp.spec_wl_short) > + (rsp.spec_wl_long - rsp.spec_wl_short)) + ss = &tsp; + else + ss = &rsp; + } else + ss = &tsp; + + if (tsp.spec_n > rsp.spec_n) + nn = tsp.spec_n; + else + nn = rsp.spec_n; + + if (nn > XSPECT_MAX_BANDS) + error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,nn); + + for (j = 0; j < nn; j++) { +#if defined(__APPLE__) && defined(__POWERPC__) + gcc_bug_fix(j); +#endif + xx[j] = ss->spec_wl_short + + j * (ss->spec_wl_long - ss->spec_wl_short)/(nn-1); + + yy[j] = value_xspect(&tsp, xx[j]); + + if (rLab[0] >= -1.0) { /* If there is a reference */ + yr[j] = value_xspect(&rsp, xx[j]); + } + } + + xmax = ss->spec_wl_long; + xmin = ss->spec_wl_short; + if (emiss || uvmode) { + ymin = ymax = 0.0; /* let it scale */ + } else { + ymin = 0.0; + ymax = 120.0; + } + do_plot_x(xx, yy, rLab[0] >= -1.0 ? yr : NULL, NULL, nn, 1, + xmin, xmax, ymin, ymax, 2.0); + } +#endif /* !SALONEINSTLIB */ + } + + if (sufwa == 0) { /* Not setting up fwa, so show reading */ + + sp = val.sp; /* Save as last spectral reading */ + + /* Compute the XYZ & Lab */ + if (dofwa == 0 && spec == 0) { + if (val.XYZ_v == 0) + error("Instrument didn't return XYZ value"); + + for (j = 0; j < 3; j++) + XYZ[j] = val.XYZ[j]; + + } else { + /* Compute XYZ given spectral */ + + if (sp.spec_n <= 0) { + error("Instrument didn't return spectral data"); + } + + if (dofwa == 0) { + /* Convert it to XYZ space using uncompensated */ + sp2cie->convert(sp2cie, XYZ, &sp); + } else { + /* Convert using compensated conversion */ + sp2cief[fidx]->sconvert(sp2cief[fidx], &sp, XYZ, &sp); + } + if (!(emiss || tele || ambient)) { + for (j = 0; j < 3; j++) + XYZ[j] *= 100.0; /* 0..100 scale */ + } + } + + /* XYZ is 0 .. 100 for reflective/transmissive, and absolute for emissibe here */ + /* XYZ is 0 .. 1 for reflective/transmissive, and absolute for emissibe here */ + +#ifndef SALONEINSTLIB + /* Compute color temperatures */ + if (ambient || doCCT) { + icmXYZNumber wp; + double nxyz[3], axyz[3]; + double lab[3], alab[3]; + + nxyz[0] = XYZ[0] / XYZ[1]; + nxyz[2] = XYZ[2] / XYZ[1]; + nxyz[1] = XYZ[1] / XYZ[1]; + + /* Compute CCT */ + if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, obType, NULL, XYZ, NULL, 0)) < 0) + error ("Got bad cct\n"); + axyz[0] /= axyz[1]; + axyz[2] /= axyz[1]; + axyz[1] /= axyz[1]; + icmAry2XYZ(wp, axyz); + icmXYZ2Lab(&wp, lab, nxyz); + icmXYZ2Lab(&wp, alab, axyz); + cct_de = icmLabDE(lab, alab); + + /* Compute VCT */ + if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, obType, NULL, XYZ, NULL, 1)) < 0) + error ("Got bad vct\n"); + axyz[0] /= axyz[1]; + axyz[2] /= axyz[1]; + axyz[1] /= axyz[1]; + icmAry2XYZ(wp, axyz); + icmXYZ2Lab(&wp, lab, nxyz); + icmXYZ2Lab(&wp, alab, axyz); + vct_de = icmLabDE(lab, alab); + + /* Compute VDT */ + if ((vdt = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, obType, NULL, XYZ, NULL, 1)) < 0) + error ("Got bad vct\n"); + axyz[0] /= axyz[1]; + axyz[2] /= axyz[1]; + axyz[1] /= axyz[1]; + icmAry2XYZ(wp, axyz); + icmXYZ2Lab(&wp, lab, nxyz); + icmXYZ2Lab(&wp, alab, axyz); + vdt_de = icmLabDE(lab, alab); + } + + /* Compute D50 Lab from XYZ */ + icmXYZ2Lab(&icmD50_100, Lab, XYZ); + + /* Compute Yxy from XYZ */ + icmXYZ2Yxy(Yxy, XYZ); + + /* Compute LCh from Lab */ + icmLab2LCh(LCh, Lab); + +#else /* SALONEINSTLIB */ + /* Compute D50 Lab from XYZ */ + XYZ2Lab(Lab, XYZ); + + /* Compute Yxy from XYZ */ + XYZ2Yxy(Yxy, XYZ); + + /* Compute LCh from Lab */ + Lab2LCh(LCh, Lab); +#endif /* SALONEINSTLIB */ + + if (emiss > 1 || tele > 1) { + if (wXYZ[0] < 0.0) { + if (XYZ[1] < 10.0) + error ("White of XYZ %f %f %f doesn't seem reasonable",XYZ[0], XYZ[1], XYZ[2]); + printf("\n Making result XYZ: %f %f %f, D50 Lab: %f %f %f white reference.\n", + XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]); + wXYZ[0] = XYZ[0]; + wXYZ[1] = XYZ[1]; + wXYZ[2] = XYZ[2]; + continue; + } + if (emiss == 2 || tele == 2) { + /* Normalize to white Y value and scale to 0..100 */ + XYZ[0] = 100.0 * XYZ[0] / wXYZ[1]; + XYZ[1] = 100.0 * XYZ[1] / wXYZ[1]; + XYZ[2] = 100.0 * XYZ[2] / wXYZ[1]; + } +#ifndef SALONEINSTLIB + else { + + /* Normalize to white and scale to 0..100 */ + XYZ[0] = XYZ[0] * icmD50_100.X / wXYZ[0]; + XYZ[1] = XYZ[1] * icmD50_100.Y / wXYZ[1]; + XYZ[2] = XYZ[2] * icmD50_100.Z / wXYZ[2]; + } + + /* recompute Lab */ + icmXYZ2Lab(&icmD50_100, Lab, XYZ); + + /* recompute Yxy from XYZ */ + icmXYZ2Yxy(Yxy, XYZ); + + /* recompute LCh from Lab */ + icmLab2LCh(LCh, Lab); +#else /* SALONEINSTLIB */ + else { + + /* Normalize to white */ + XYZ[0] = XYZ[0] * D50_X_100 / wXYZ[0]; + XYZ[1] = XYZ[1] * D50_Y_100 / wXYZ[1]; + XYZ[2] = XYZ[2] * D50_Z_100 / wXYZ[2]; + } + + /* recompute Lab */ + XYZ2Lab(Lab, XYZ); + + /* recompute Yxy from XYZ */ + XYZ2Yxy(Yxy, XYZ); + + /* recompute LCh from Lab */ + Lab2LCh(LCh, Lab); +#endif /* SALONEINSTLIB */ + } + + if (ambient && (cap2 & inst2_ambient_mono)) { + printf("\n Result is Y: %f, L*: %f\n",XYZ[1], Lab[0]); + } else { + if (doYxy) { + /* Print out the XYZ and Yxy */ + printf("\n Result is XYZ: %f %f %f, Yxy: %f %f %f\n", + XYZ[0], XYZ[1], XYZ[2], Yxy[0], Yxy[1], Yxy[2]); + } else if (doLCh) { + /* Print out the XYZ and LCh */ + printf("\n Result is XYZ: %f %f %f, LCh: %f %f %f\n", + XYZ[0], XYZ[1], XYZ[2], LCh[0], LCh[1], LCh[2]); + } else { + /* Print out the XYZ and Lab */ + printf("\n Result is XYZ: %f %f %f, D50 Lab: %f %f %f\n", + XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]); + } + } + + if (rLab[0] >= -9.0) { + if (refstats) { + double avg[3], sdev[3]; + rstat_n++; + + for (j = 0; j < 3; j++) { + rstat_XYZ[j] += XYZ[j]; + rstat_XYZsq[j] += XYZ[j] * XYZ[j]; + + avg[j] = rstat_XYZ[j]/rstat_n; + sdev[j] = sqrt(rstat_n * rstat_XYZsq[j] - rstat_XYZ[j] * rstat_XYZ[j])/rstat_n; + } + printf(" XYZ stats %.0f: Avg %f %f %f, S.Dev %f %f %f\n", + rstat_n, avg[0], avg[1], avg[2], sdev[0], sdev[1], sdev[2]); + + for (j = 0; j < 3; j++) { + rstat_Lab[j] += Lab[j]; + rstat_Labsq[j] += Lab[j] * Lab[j]; + + avg[j] = rstat_Lab[j]/rstat_n; + sdev[j] = sqrt(rstat_n * rstat_Labsq[j] - rstat_Lab[j] * rstat_Lab[j])/rstat_n; + } + printf(" Lab stats %.0f: Avg %f %f %f, S.Dev %f %f %f\n", + rstat_n, avg[0], avg[1], avg[2], sdev[0], sdev[1], sdev[2]); + } +#ifndef SALONEINSTLIB + printf(" Delta E to reference is %f %f %f (%f, CIE94 %f)\n", + Lab[0] - rLab[0], Lab[1] - rLab[1], Lab[2] - rLab[2], + icmLabDE(Lab, rLab), icmCIE94(Lab, rLab)); +#else + printf(" Delta E to reference is %f %f %f (%f)\n", + Lab[0] - rLab[0], Lab[1] - rLab[1], Lab[2] - rLab[2], + LabDE(Lab, rLab)); +#endif + } + if (ambient) { + if (ambient == 2) + printf(" Apparent flash duration = %f seconds\n",val.duration); + if (cap2 & inst2_ambient_mono) { + printf(" Ambient = %.1f Lux%s\n", + 3.141592658 * XYZ[1], ambient == 2 ? "-Seconds" : ""); + if (ambient != 2) + printf(" Suggested EV @ ISO100 for %.1f Lux incident light = %.1f\n", + 3.141592658 * XYZ[1], + log(3.141592658 * XYZ[1]/2.5)/log(2.0)); + } else { +#ifndef SALONEINSTLIB + printf(" Ambient = %.1f Lux%s, CCT = %.0fK (Delta E %f)\n", + 3.1415926 * XYZ[1], ambient == 2 ? "-Seconds" : "", + cct, cct_de); + if (ambient != 2) + printf(" Suggested EV @ ISO100 for %.1f Lux incident light = %.1f\n", + 3.141592658 * XYZ[1], + log(3.141592658 * XYZ[1]/2.5)/log(2.0)); + printf(" Closest Planckian temperature = %.0fK (Delta E %f)\n",vct, vct_de); + printf(" Closest Daylight temperature = %.0fK (Delta E %f)\n",vdt, vdt_de); +#else /* SALONEINSTLIB */ + printf(" Ambient = %.1f Lux%s\n", + 3.1415926 * XYZ[1], ambient == 2 ? "-Seconds" : ""); +#endif /* SALONEINSTLIB */ + } +#ifndef SALONEINSTLIB + } else if (doCCT) { + printf(" CCT = %.0fK (Delta E %f)\n",cct, cct_de); + printf(" Closest Planckian temperature = %.0fK (Delta E %f)\n",vct, vct_de); + printf(" Closest Daylight temperature = %.0fK (Delta E %f)\n",vdt, vdt_de); +#endif + } +#ifndef SALONEINSTLIB + if (val.sp.spec_n > 0 && (ambient || doCCT)) { + int invalid = 0; + double cri; + cri = icx_CIE1995_CRI(&invalid, &sp); + printf(" Color Rendering Index (Ra) = %.1f%s\n",cri,invalid ? " (Invalid)" : ""); + } +#endif + + /* Save reading to the log file */ + if (fp != NULL) { + /* Print some column titles */ + if (loghead == 0) { + fprintf(fp,"Reading\tX\tY\tZ\tL*\ta*\tb*"); + if (pspec) { /* Print or plot out spectrum */ + for (j = 0; j < sp.spec_n; j++) { + double wvl = sp.spec_wl_short + + j * (sp.spec_wl_long - sp.spec_wl_short)/(sp.spec_n-1); + fprintf(fp,"\t%3f",wvl); + } + } + fprintf(fp,"\n"); + loghead = 1; + } + + /* Print results */ + fprintf(fp,"%d\t%f\t%f\t%f\t%f\t%f\t%f", + ix, XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]); + + if (pspec != 0) { + for (j = 0; j < sp.spec_n; j++) + fprintf(fp,"\t%8.3f",sp.spec[j]); + } + fprintf(fp,"\n"); + } + } + } /* Next reading */ + + /* Release paper */ + if (cap2 & inst2_xy_holdrel) { + it->xy_clear(it); + } + +#ifdef DEBUG + printf("About to exit\n"); +#endif + + if (sp2cie != NULL) + sp2cie->del(sp2cie); + for (i = 0; i < 26; i++) + if (sp2cief[i] != NULL) + sp2cief[i]->del(sp2cief[i]); + + /* Free instrument */ + it->del(it); + + icmps->del(icmps); + + if (fp != NULL) + fclose(fp); + + return 0; +} + + + + |