diff options
Diffstat (limited to 'xicc/specplot.c')
-rw-r--r-- | xicc/specplot.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/xicc/specplot.c b/xicc/specplot.c new file mode 100644 index 0000000..b2baf05 --- /dev/null +++ b/xicc/specplot.c @@ -0,0 +1,370 @@ + +/* + * International Color Consortium color transform expanded support + * + * Author: Graeme W. Gill + * Date: 2006/5/9 + * Version: 1.00 + * + * Copyright 2006 Graeme W. Gill + * All rights reserved. + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + * + */ + +/* + * This is some test code to test the Daylight and Plankian spectra, + * Correlated and Visual Color Temperatures, and CRI. + * and plot a spectrum, CMF or CCSS. + */ + +#include <stdio.h> +#include <math.h> +#include "xspect.h" +#include "numlib.h" +#include "plot.h" + +#define PLANKIAN +#define XRES 500 + +#define MAXGRAPHS 10 + +#ifdef PLANKIAN +#define BBTYPE icxIT_Ptemp +#else +#define BBTYPE icxIT_Dtemp +#endif + +/* Display a spectrum etc. */ +/* We are guaranteed that the x range/increments are identical, */ +/* and that there is only one spectrum if douv */ +static int do_spec( + char name[MAXGRAPHS][200], + xspect *sp, + int nsp, /* Number of sp */ + int dozero, /* Include zero in the range */ + int douv, /* Do variation of added UV test */ + double uvmin, + double uvmax +) { + int n, i, j, k, m; + double wl_short, wl_long; /* Common range */ + double xyz[3]; /* Color temperature */ + double Yxy[3]; + double Lab[3]; /* D50 Lab value */ + double xx[XRES]; + double yy[10][XRES]; + double *yp[10]; + double cct, vct; + double cct_xyz[3], vct_xyz[3]; + double cct_lab[3], vct_lab[3]; + icmXYZNumber wp; + double de; + double uv = uvmin; + double step = 0.1; + xspect tsp; /* Spectrum with possible UV added */ + char *color[] = { + "Black", "Red", "Green", "Blue", "Yellow", "Purple", "Brown", "Orange", "Grey", "Magenta" + }; + + printf("\n"); + + for (j = 0; j < 10; j++) + yp[j] = NULL; + + if (nsp > 10) + nsp = 10; + + m = 0; /* offset in output array */ + n = 1; + + wl_short = 1e6; + wl_long = -1e6; + for (k = 0; k < nsp; k++) { + if (sp[k].spec_wl_long > wl_long) + wl_long = sp[k].spec_wl_long; + if (sp[k].spec_wl_short < wl_short) + wl_short = sp[k].spec_wl_short; + } + + if (douv) { + n = 1 + (int)(0.5 + (uvmax-uvmin)/0.1); + if (n > 9) + n = 9; /* Don't use white */ + if (n > 1) + step = (uvmax-uvmin)/(n-1.0); + } + + for (k = 0; k < nsp; k++) { + tsp = sp[k]; + for (uv = uvmax, j = 0; j < n; j++, uv -= step) { + + if (douv) { + printf("UV level = %f\n",uv); + xsp_setUV(&tsp, &sp[k], uv); + } + + /* Compute XYZ of illuminant */ + if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, &tsp) != 0) + error ("icx_sp_temp2XYZ returned error"); + + icmXYZ2Yxy(Yxy, xyz); + icmXYZ2Lab(&icmD50, Lab, xyz); + + printf("Type = %s [%s]\n",name[k], color[k]); + printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]); + printf("D50 L*a*b* = %f %f %f\n", Lab[0], Lab[1], Lab[2]); + +#ifndef NEVER + /* Test density */ + { + double dens[4]; + + xsp_Tdensity(dens, &tsp); + + printf("CMYV density = %f %f %f %f\n", dens[0], dens[1], dens[2], dens[3]); + } +#endif + + /* Compute CCT */ + if ((cct = icx_XYZ2ill_ct(cct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0) + error ("Got bad cct\n"); + + /* Compute VCT */ + if ((vct = icx_XYZ2ill_ct(vct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0) + error ("Got bad vct\n"); + +#ifdef PLANKIAN + printf("CCT = %f, VCT = %f\n",cct, vct); +#else + printf("CDT = %f, VDT = %f\n",cct, vct); +#endif + + { + int invalid = 0; + double cri; + cri = icx_CIE1995_CRI(&invalid, &tsp); + printf("CRI = %.1f%s\n",cri,invalid ? " (Invalid)" : ""); + } + + /* Use modern color difference - gives a better visual match */ + icmAry2XYZ(wp, vct_xyz); + icmXYZ2Lab(&wp, cct_lab, cct_xyz); + icmXYZ2Lab(&wp, vct_lab, vct_xyz); + de = icmCIE2K(cct_lab, vct_lab); + printf("CIEDE2000 Delta E = %f\n",de); + + /* Plot spectrum out */ + for (i = 0; i < XRES; i++) { + double ww; + + ww = (wl_long - wl_short) + * ((double)i/(XRES-1.0)) + wl_short; + + xx[i] = ww; + yy[(m + k + j) % 10][i] = value_xspect(&tsp, ww); + } + yp[(m + k + j) % 10] = &yy[(m + k + j) % 10][0]; + } + } + do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], XRES, dozero); + + + return 0; +} + + +void usage(void) { + fprintf(stderr,"Plot spectrum and calculate CCT and VCT\n"); + fprintf(stderr,"Author: Graeme W. Gill\n"); + fprintf(stderr,"usage: specplot [infile.sp]\n"); + fprintf(stderr," -v verbose\n"); + fprintf(stderr," -c combine multiple files into one plot\n"); + fprintf(stderr," -z don't make range cover zero\n"); + fprintf(stderr," -u level plot effect of adding estimated UV level\n"); + fprintf(stderr," -U plot effect of adding range of estimated UV level\n"); + fprintf(stderr," [infile.sp ...] spectrum files to plot\n"); + fprintf(stderr," default is all built in illuminants\n"); + exit(1); +} + +int +main( + int argc, + char *argv[] +) { + int fa, nfa; /* argument we're looking at */ + int k; + int verb = 0; + int comb = 0; + int zero = 1; + double temp; + xspect sp[MAXGRAPHS]; + icxIllumeType ilType; + int douv = 0; + double uvmin = -1.0, uvmax = 1.0; + char buf[MAXGRAPHS][200]; + + error_program = argv[0]; + + /* Process the 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) < argc) { + if (argv[fa+1][0] != '-') { + nfa = fa + 1; + na = argv[nfa]; /* next is seperate non-flag argument */ + } + } + } + + /* Show added UV */ + if (argv[fa][1] == 'u') { + douv = 1; + + fa = nfa; + if (na == NULL) + usage(); + + uvmin = uvmax = atof(na); + if (uvmin < -10.0 || uvmax > 10.0) + usage(); + } + + else if (argv[fa][1] == 'U') { + douv = 1; + } + + /* Verbosity */ + else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') { + verb = 1; + + } else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') { + comb = 1; + + } else if (argv[fa][1] == 'z' || argv[fa][1] == 'Z') { + zero = 0; + + } else { + usage(); + } + } + else + break; + } + + if (fa < argc && argv[fa][0] != '-') { /* Got file arguments */ + int nsp = 0; /* Current number in sp[] */ + int soff = 0; /* Offset within file */ + int maxgraphs = MAXGRAPHS; + int eof; + + if (douv) + maxgraphs = 1; + + nsp = 0; + + /* Until we run out */ + for (;;) { + int i, nret, nreq; + + /* If we've got to the limit of each plot, */ + /* or at least one and there are no more files, */ + /* or at least one and we're not combining files and at start of a new file */ + if (nsp >= MAXGRAPHS || (nsp > 0 && ((!comb && soff == 0) || fa >= argc))) { + /* Plot what we've got */ + do_spec(buf, sp, nsp, zero, douv, uvmin, uvmax); + nsp = 0; + } + + if (fa >= argc) /* No more files */ + break; + + /* Read as many spectra from the file as possible */ + nreq = MAXGRAPHS - nsp; + if (read_nxspect(&sp[nsp], argv[fa], &nret, soff, nreq, 0) != 0) { + error ("Unable to read custom spectrum, CMF or CCSS '%s'",argv[fa]); + } + for (i = 0; i < nret; i++) { + xspect_denorm(&sp[nsp + i]); + sprintf(buf[nsp + i],"File '%s' spect %d",argv[fa], soff + i); + } + nsp += nret; + soff += nret; + if (nret < nreq) { /* We're done with this file */ + fa++; + soff = 0; + } + } + + } else { + + /* For each standard illuminant */ + for (ilType = icxIT_A; ilType <= icxIT_F10; ilType++) { + char *inm = NULL; + + switch (ilType) { + case icxIT_A: + inm = "A"; break; + case icxIT_C: + inm = "C"; break; + case icxIT_D50: + inm = "D50"; break; + case icxIT_D50M2: + inm = "D50M2"; break; + case icxIT_D65: + inm = "D65"; break; + case icxIT_E: + inm = "E"; break; + case icxIT_F5: + inm = "F5"; break; + case icxIT_F8: + inm = "F8"; break; + case icxIT_F10: + inm = "F10"; break; + default: + inm = "Unknown"; break; + break; + } + + if (standardIlluminant(&sp[0], ilType, 0) != 0) + error ("standardIlluminant returned error"); + + strcpy(buf[0],inm); + do_spec(buf, sp, 1, zero, douv, uvmin, uvmax); + } + + /* For each material and illuminant */ + for (temp = 2500; temp <= 9000; temp += 500) { + + for (k = 0; k < 2; k++) { + + ilType = k == 0 ? icxIT_Dtemp : icxIT_Ptemp; + + if (standardIlluminant(&sp[0], ilType, temp) != 0) + error ("standardIlluminant returned error"); + + sprintf(buf[0], "%s at %f", k == 0 ? "Daylight" : "Black body", temp); + + do_spec(buf, sp, 1, zero, douv, uvmin, uvmax); + } + } + + } + return 0; +} + + + + + + + + |