diff options
Diffstat (limited to 'xicc/ccss.c')
-rw-r--r-- | xicc/ccss.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/xicc/ccss.c b/xicc/ccss.c new file mode 100644 index 0000000..cd9b4e4 --- /dev/null +++ b/xicc/ccss.c @@ -0,0 +1,636 @@ + +/* + * Argyll Color Correction System + * Colorimeter Correction Matrix + * + * Author: Graeme W. Gill + * Date: 1r9/8/2010 + * + * Copyright 2010 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. + */ + +/* + * TTBD: + */ + +#undef DEBUG + +#define verbo stdout + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <sys/types.h> +#include <time.h> +#ifndef SALONEINSTLIB +#include "numlib.h" +#include "icc.h" +#else +#include "numsup.h" +#include "conv.h" +#endif +#include "cgats.h" +#include "xspect.h" +#include "ccss.h" + +#ifdef NT /* You'd think there might be some standards.... */ +# ifndef __BORLANDC__ +# define stricmp _stricmp +# endif +#else +# define stricmp strcasecmp +#endif + +/* Forward declarations */ +static void free_ccss(ccss *p); + +/* Utilities */ + +/* Method implimentations */ + +/* Write out the ccss to a CGATS format object */ +/* Return nz on error */ +static int create_ccss_cgats( +ccss *p, /* This */ +cgats **pocg /* return CGATS structure */ +) { + int i, j; + time_t clk = time(0); + struct tm *tsp = localtime(&clk); + char *atm = asctime(tsp); /* Ascii time */ + cgats *ocg; /* CGATS structure */ + int nsetel = 0; + cgats_set_elem *setel; /* Array of set value elements */ + char buf[100]; + + atm[strlen(atm)-1] = '\000'; /* Remove \n from end */ + + /* Setup output cgats file */ + ocg = new_cgats(); /* Create a CGATS structure */ + ocg->add_other(ocg, "CCSS"); /* Type is Colorimeter Calibration Spectral Set */ + ocg->add_table(ocg, tt_other, 0); /* Start the first table */ + + if (p->desc != NULL) + ocg->add_kword(ocg, 0, "DESCRIPTOR", p->desc,NULL); + + if (p->orig != NULL) + ocg->add_kword(ocg, 0, "ORIGINATOR", p->orig, NULL); + else + ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll ccss", NULL); + if (p->crdate != NULL) + ocg->add_kword(ocg, 0, "CREATED",p->crdate, NULL); + else + ocg->add_kword(ocg, 0, "CREATED",atm, NULL); + + if (p->disp) + ocg->add_kword(ocg, 0, "DISPLAY",p->disp, NULL); + if (p->tech) + ocg->add_kword(ocg, 0, "TECHNOLOGY", p->tech,NULL); + if (p->disp == NULL && p->tech == NULL) { + sprintf(p->err, "write_ccss: ccss doesn't contain display or techology strings"); + ocg->del(ocg); + return 1; + } + if (p->refrmode >= 0) + ocg->add_kword(ocg, 0, "DISPLAY_TYPE_REFRESH", p->refrmode ? "YES" : "NO", NULL); + if (p->sel != NULL) + ocg->add_kword(ocg, 0, "UI_SELECTORS", p->sel, NULL); + if (p->ref != NULL) + ocg->add_kword(ocg, 0, "REFERENCE",p->ref, NULL); + + sprintf(buf,"%d", p->samples[0].spec_n); + ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL); + sprintf(buf,"%f", p->samples[0].spec_wl_short); + ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL); + sprintf(buf,"%f", p->samples[0].spec_wl_long); + ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL); + sprintf(buf,"%f", p->samples[0].norm); + ocg->add_kword(ocg, 0, "SPECTRAL_NORM",buf, NULL); + + /* Fields we want */ + ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t); + nsetel += 1; /* For id */ + + /* Generate fields for spectral values */ + for (i = 0; i < p->samples[0].spec_n; i++) { + int nm; + + /* Compute nearest integer wavelength */ + nm = (int)(p->samples[0].spec_wl_short + ((double)i/(p->samples[0].spec_n-1.0)) + * (p->samples[0].spec_wl_long - p->samples[0].spec_wl_short) + 0.5); + + sprintf(buf,"SPEC_%03d",nm); + ocg->add_field(ocg, 0, buf, r_t); + } + nsetel += p->samples[0].spec_n; /* Spectral values */ + + if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL) { + strcpy(p->err, "Malloc failed!"); + ocg->del(ocg); /* Clean up */ + return 2; + } + + /* Write out the patch info to the output CGATS file */ + for (i = 0; i < p->no_samp; i++) { + int k = 0; + + sprintf(buf,"%d",i+1); + setel[k++].c = buf; + + for (j = 0; j < p->samples[i].spec_n; j++) + setel[k++].d = p->samples[i].spec[j]; + + ocg->add_setarr(ocg, 0, setel); + } + free(setel); + + if (pocg != NULL) + *pocg = ocg; + + return 0; +} + +/* Write out the ccss to a CGATS format .ccss file */ +/* Return nz on error */ +static int write_ccss( +ccss *p, /* This */ +char *outname /* Filename to write to */ +) { + int rv; + cgats *ocg; /* CGATS structure */ + + if (p->no_samp < 3) { + strcpy(p->err, "Need at least three spectral samples"); + return 1; + } + + /* Create CGATS elements */ + if ((rv = create_ccss_cgats(p, &ocg)) != 0) { + return rv; + } + + /* Write it to file */ + if (ocg->write_name(ocg, outname)) { + strcpy(p->err, ocg->err); + ocg->del(ocg); /* Clean up */ + return 1; + } + ocg->del(ocg); /* Clean up */ + + return 0; +} + +/* write to a CGATS .ccss file to a memory buffer. */ +/* return nz on error, with message in err[] */ +static int buf_write_ccss( +ccss *p, +unsigned char **buf, /* Return allocated buffer */ +int *len /* Return length */ +) { + int rv; + cgats *ocg; /* CGATS structure */ + cgatsFile *fp; + + if (p->no_samp < 3) { + strcpy(p->err, "Need at least three spectral samples"); + return 1; + } + + /* Create CGATS elements */ + if ((rv = create_ccss_cgats(p, &ocg)) != 0) { + return rv; + } + + if ((fp = new_cgatsFileMem(NULL, 0)) == NULL) { + strcpy(p->err, "new_cgatsFileMem failed"); + return 2; + } + + /* Write it to file */ + if (ocg->write(ocg, fp)) { + strcpy(p->err, ocg->err); + ocg->del(ocg); /* Clean up */ + fp->del(fp); + return 1; + } + + /* Get the buffer the ccss has been written to */ + if (fp->get_buf(fp, buf, (size_t *)len)) { + strcpy(p->err, "cgatsFileMem get_buf failed"); + return 2; + } + + ocg->del(ocg); /* Clean up */ + fp->del(fp); + + return 0; +} + +/* Read in the ccss CGATS .ccss file from cgats */ +/* Return nz on error */ +static int read_ccss_cgats( +ccss *p, /* This */ +cgats *icg /* input cgats structure */ +) { + int i, j; + int ti, ii; /* Temporary CGATs index */ + int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */ + xspect sp; + + if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0) { + sprintf(p->err, "read_ccss: Input file isn't a CCSS format file"); + icg->del(icg); + return 1; + } + if (icg->ntables != 1) { + sprintf(p->err, "Input file doesn't contain exactly one table"); + icg->del(icg); + return 1; + } + + free_ccss(p); + + if ((ti = icg->find_kword(icg, 0, "DESCRIPTOR")) >= 0) { + if ((p->desc = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + if ((ti = icg->find_kword(icg, 0, "ORIGINATOR")) >= 0) { + if ((p->orig = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + if ((ti = icg->find_kword(icg, 0, "CREATED")) >= 0) { + if ((p->crdate = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + + if ((ti = icg->find_kword(icg, 0, "DISPLAY")) >= 0) { + if ((p->disp = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + if ((ti = icg->find_kword(icg, 0, "TECHNOLOGY")) >= 0) { + if ((p->tech = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + if (p->disp == NULL && p->tech == NULL) { + sprintf(p->err, "read_ccss: Input file doesn't contain keyword DISPLAY or TECHNOLOGY"); + icg->del(icg); + return 1; + } + if ((ti = icg->find_kword(icg, 0, "DISPLAY_TYPE_REFRESH")) >= 0) { + if (stricmp(icg->t[0].kdata[ti], "YES") == 0) + p->refrmode = 1; + else if (stricmp(icg->t[0].kdata[ti], "NO") == 0) + p->refrmode = 0; + } + + if ((ti = icg->find_kword(icg, 0, "UI_SELECTORS")) >= 0) { + if ((p->sel = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + + if ((ti = icg->find_kword(icg, 0, "REFERENCE")) >= 0) { + if ((p->ref = strdup(icg->t[0].kdata[ti])) == NULL) { + sprintf(p->err, "read_ccss: malloc failed"); + icg->del(icg); + return 2; + } + } + + if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) { + sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_BANDS"); + icg->del(icg); + return 1; + } + sp.spec_n = atoi(icg->t[0].kdata[ii]); + if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0) { + sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_START_NM"); + icg->del(icg); + return 1; + } + sp.spec_wl_short = atof(icg->t[0].kdata[ii]); + if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0) { + sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_END_NM"); + icg->del(icg); + return 1; + } + sp.spec_wl_long = atof(icg->t[0].kdata[ii]); + + if ((ii = icg->find_kword(icg, 0, "SPECTRAL_NORM")) < 0) { + sp.norm = 1.0; /* Older versions don't have SPECTRAL_NORM */ + } else { + sp.norm = atof(icg->t[0].kdata[ii]); + } + + /* Find the fields for spectral values */ + for (j = 0; j < sp.spec_n; j++) { + char buf[100]; + int nm; + + /* Compute nearest integer wavelength */ + nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0)) + * (sp.spec_wl_long - sp.spec_wl_short) + 0.5); + + sprintf(buf,"SPEC_%03d",nm); + + if ((spi[j] = icg->find_field(icg, 0, buf)) < 0) { + sprintf(p->err,"Input file doesn't contain field %s",buf); + icg->del(icg); + return 1; + } + } + + if ((p->no_samp = icg->t[0].nsets) < 3) { + sprintf(p->err, "Input file doesn't contain at least three spectral samples"); + p->no_samp = 0; + icg->del(icg); /* Clean up */ + return 1; + } + + /* Allocate spectral array */ + if ((p->samples = (xspect *)malloc(sizeof(xspect) * p->no_samp)) == NULL) { + strcpy(p->err, "Malloc failed!"); + p->no_samp = 0; + icg->del(icg); /* Clean up */ + return 2; + } + + /* Fill sample array with the data */ + for (i = 0; i < p->no_samp; i++) { + + XSPECT_COPY_INFO(&p->samples[i], &sp); + + /* Read the spectral values for this patch */ + for (j = 0; j < sp.spec_n; j++) { + p->samples[i].spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]); + } + } + + return 0; +} + +/* Read in the ccss CGATS .ccss file */ +/* Return nz on error */ +static int read_ccss( +ccss *p, /* This */ +char *inname /* Filename to read from */ +) { + int rv; + cgats *icg; /* input cgats structure */ + + /* Open and look at the .ccss file */ + if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */ + sprintf(p->err, "read_ccss: new_cgats() failed"); + return 2; + } + icg->add_other(icg, "CCSS"); /* our special type is Model Printer Profile */ + + if (icg->read_name(icg, inname)) { + strcpy(p->err, icg->err); + icg->del(icg); + return 1; + } + + if ((rv = read_ccss_cgats(p, icg)) != 0) { + icg->del(icg); /* Clean up */ + return rv; + } + + icg->del(icg); /* Clean up */ + + return 0; +} + +/* Read in the ccss CGATS .ccss file from a memory buffer */ +/* Return nz on error */ +static int buf_read_ccss( +ccss *p, /* This */ +unsigned char *buf, +int len +) { + int rv; + cgatsFile *fp; + cgats *icg; /* input cgats structure */ + + if ((fp = new_cgatsFileMem(buf, len)) == NULL) { + strcpy(p->err, "new_cgatsFileMem failed"); + return 2; + } + + /* Open and look at the .ccss file */ + if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */ + sprintf(p->err, "read_ccss: new_cgats() failed"); + fp->del(fp); + return 2; + } + icg->add_other(icg, "CCSS"); /* our special type is Model Printer Profile */ + + if (icg->read(icg, fp)) { + strcpy(p->err, icg->err); + icg->del(icg); + fp->del(fp); + return 1; + } + fp->del(fp); + + if ((rv = read_ccss_cgats(p, icg)) != 0) { + icg->del(icg); /* Clean up */ + return rv; + } + + icg->del(icg); /* Clean up */ + + return 0; +} + +/* Set the contents of the ccss. return nz on error. */ +/* (Copy all the values) */ +static int set_ccss(ccss *p, +char *orig, /* Originator (May be NULL) */ +char *crdate, /* Creation date in ctime() format (May be NULL) */ +char *desc, /* General description (optional) */ +char *disp, /* Display make and model (optional if tech) */ +char *tech, /* Display technology description (optional if disp) */ +int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */ +char *sel, /* UI selector characters - NULL for none */ +char *refd, /* Reference spectrometer description (optional) */ +xspect *samples, /* Arry of spectral samples. All assumed to be same dim as first */ +int no_samp /* Number of spectral samples */ +) { + int i; + + free_ccss(p); + if (orig != NULL) { + if ((p->orig = strdup(orig)) == NULL) { + sprintf(p->err, "set_ccss: malloc orig failed"); + return 2; + } + } + if (desc != NULL) { + if ((p->desc = strdup(desc)) == NULL) { + sprintf(p->err, "set_ccss: malloc desc failed"); + return 2; + } + } + if (crdate != NULL) { + if ((p->crdate = strdup(crdate)) == NULL) { + sprintf(p->err, "set_ccss: malloc crdate failed"); + return 2; + } + } + if (disp != NULL) { + if ((p->disp = strdup(disp)) == NULL) { + sprintf(p->err, "set_ccss: malloc disp failed"); + return 2; + } + } + if (tech != NULL) { + if ((p->tech = strdup(tech)) == NULL) { + sprintf(p->err, "set_ccss: malloc tech failed"); + return 2; + } + } + p->refrmode = refrmode; + if (sel != NULL) { + if ((p->sel = strdup(sel)) == NULL) { + sprintf(p->err, "set_ccss: malloc sel failed"); + return 2; + } + } + if (refd != NULL) { + if ((p->ref = strdup(refd)) == NULL) { + sprintf(p->err, "set_ccss: malloc ref failed"); + return 2; + } + } + + if (p->samples != NULL) { + free(p->samples); + p->samples = NULL; + } + + if ((p->no_samp = no_samp) < 3) { + strcpy(p->err, "Must be at least three spectral samples"); + p->no_samp = 0; + return 1; + } + + /* Allocate spectral array */ + if ((p->samples = (xspect *)malloc(sizeof(xspect) * p->no_samp)) == NULL) { + strcpy(p->err, "Malloc failed!"); + p->no_samp = 0; + return 2; + } + + /* And copy all the values */ + for (i = 0; i < p->no_samp; i++) { + p->samples[i] = samples[i]; + } + + return 0; +} + +/* Free the contents */ +static void free_ccss(ccss *p) { + if (p != NULL) { + if (p->desc != NULL) + free(p->desc); + p->desc = NULL; + if (p->orig != NULL) + free(p->orig); + p->orig = NULL; + if (p->crdate != NULL) + free(p->crdate); + p->crdate = NULL; + if (p->disp != NULL) + free(p->disp); + p->disp = NULL; + if (p->tech != NULL) + free(p->tech); + p->tech = NULL; + if (p->sel != NULL) + free(p->sel); + p->sel = NULL; + if (p->ref != NULL) + free(p->ref); + p->ref = NULL; + if (p->samples != NULL) + free(p->samples); + p->samples = NULL; + p->no_samp = 0; + } +} + +/* Delete it */ +static void del_ccss(ccss *p) { + if (p != NULL) { + free_ccss(p); + free(p); + } +} + +/* Allocate a new, uninitialised ccss */ +/* Note thate black and white points aren't allocated */ +ccss *new_ccss(void) { + ccss *p; + + if ((p = (ccss *)calloc(1, sizeof(ccss))) == NULL) + return NULL; + + /* Init method pointers */ + p->del = del_ccss; + p->set_ccss = set_ccss; + p->write_ccss = write_ccss; + p->buf_write_ccss = buf_write_ccss; + p->read_ccss = read_ccss; + p->buf_read_ccss = buf_read_ccss; + + return p; +} + + + + + + + + + + + + + + + + + + + + + + + + + + |