Exemplo n.º 1
0
/* Return nz on error */
static int read_ccmx(
ccmx *p,			/* This */
char *inname	/* Filename to read from */
) {
	int rv;
	cgats *icg;			/* input cgats structure */

	/* Open and look at the .ccmx */
	if ((icg = new_cgats()) == NULL) {		/* Create a CGATS structure */
		sprintf(p->err, "read_ccmx: new_cgats() failed");
		return 2;
	}
	icg->add_other(icg, "CCMX");		/* 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_ccmx_cgats(p, icg)) != 0) {
		icg->del(icg);
		return rv;
	}

	icg->del(icg);		/* Clean up */

	return 0;
}
Exemplo n.º 2
0
/* Return nz on error */
static int create_ccmx_cgats(
ccmx *p,			/* This */
cgats **pocg        /* return CGATS structure */
) {
	int i, j, n;
	time_t clk = time(0);
	struct tm *tsp = localtime(&clk);
	char *atm = asctime(tsp); /* Ascii time */
	cgats *ocg;				/* CGATS structure */
	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, "CCMX"); 		/* our special type is Colorimeter Correction Matrix */
	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */

	if (p->desc != NULL)
		ocg->add_kword(ocg, 0, "DESCRIPTOR", p->desc,NULL);
	ocg->add_kword(ocg, 0, "INSTRUMENT",p->inst, NULL);
	if (p->disp != NULL)
		ocg->add_kword(ocg, 0, "DISPLAY",p->disp, NULL);

	ocg->add_kword(ocg, 0, "TECHNOLOGY", disptech_get_id(p->dtech)->strid,NULL);

	if (p->cc_cbid != 0) {
		sprintf(buf, "%d", p->cc_cbid);
		ocg->add_kword(ocg, 0, "DISPLAY_TYPE_BASE_ID", buf, NULL);
	}
	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);
	if (p->oem != 0)
		ocg->add_kword(ocg, 0, "OEM","YES", NULL);

	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll ccmx", NULL);
	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);

	ocg->add_kword(ocg, 0, "COLOR_REP", "XYZ", NULL);

	/* Add fields for the matrix */
	ocg->add_field(ocg, 0, "XYZ_X", r_t);
	ocg->add_field(ocg, 0, "XYZ_Y", r_t);
	ocg->add_field(ocg, 0, "XYZ_Z", r_t);

	/* Write out the matrix values */
	for (i = 0; i < 3; i++) {
		ocg->add_set(ocg, 0, p->matrix[i][0], p->matrix[i][1], p->matrix[i][2]);
	}

    if (pocg != NULL)
        *pocg = ocg;

	return 0;
}
Exemplo n.º 3
0
/* Return nz on error */
static int buf_read_ccmx(
ccmx *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 .ccmx file */
	if ((icg = new_cgats()) == NULL) {		/* Create a CGATS structure */
		sprintf(p->err, "read_ccmx: new_cgats() failed");
		fp->del(fp);
		return 2;
	}
	icg->add_other(icg, "CCMX");		/* 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_ccmx_cgats(p, icg)) != 0) {
		icg->del(icg);		/* Clean up */
		return rv;
	}

	icg->del(icg);		/* Clean up */

	return 0;
}
Exemplo n.º 4
0
int main(int argc, char *argv[])
{
	int i, j;
	int fa,nfa;				/* current argument we're looking at */
	int verb = 0;
	int out2 = 0;			/* Create dumy .ti2 file output */
	int disp = 0;			/* nz if this is a display device */
	int inp = 0;			/* nz if this is an input device */
	static char devname[MAXNAMEL+1] = { 0 };		/* Input CMYK/Device .txt file (may be null) */
	static char ciename[MAXNAMEL+1] = { 0 };		/* Input CIE .txt file (may be null) */
	static char specname[MAXNAMEL+1] = { 0 };		/* Input Device / Spectral .txt file */
	static char outname[MAXNAMEL+9] = { 0 };		/* Output cgats .ti3 file base name */
	static char outname2[MAXNAMEL+9] = { 0 };		/* Output cgats .ti2 file base name */
	cgats *cmy = NULL;		/* Input RGB/CMYK reference file */
	int f_id1 = -1, f_c, f_m, f_y, f_k = 0;	/* Field indexes */
	double dev_scale = 1.0;	/* Device value scaling */
	cgats *ncie = NULL;		/* Input CIE readings file (may be Dev & spectral too) */
	int f_id2, f_cie[3];	/* Field indexes */
	cgats *spec = NULL;		/* Input spectral readings (NULL if none) */
	double spec_scale = 1.0;	/* Spectral value scaling */
	int f_id3 = 0;			/* Field indexes */
	int spi[XSPECT_MAX_BANDS];	/* CGATS indexes for each wavelength */
	cgats *ocg;				/* output cgats structure for .ti3 */
	cgats *ocg2;			/* output cgats structure for .ti2 */
	time_t clk = time(0);
	struct tm *tsp = localtime(&clk);
	char *atm = asctime(tsp); /* Ascii time */
	int islab = 0;			/* CIE is Lab rather than XYZ */
	int specmin = 0, specmax = 0, specnum = 0;	/* Min and max spectral in nm, inclusive */
	int npat = 0;			/* Number of patches */
	int ndchan = 0;			/* Number of device channels, 0 = no device, RGB = 3, CMYK = 4 */
	int tlimit = -1;		/* Not set */
	double mxsum = -1.0;	/* Maximim sum of inks found in file */
	int mxsumix = 0;

	error_program = "txt2ti3";

	if (argc <= 1)
		usage("Too few arguments");

	/* 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 */
					}
				}
			}

			if (argv[fa][1] == '?')
				usage(NULL);

			else if (argv[fa][1] == '2')
				out2 = 1;

			else if (argv[fa][1] == 'l') {
				if (na == NULL) usage("No ink limit parameter");
				fa = nfa;
				tlimit = atoi(na);
				if (tlimit < 1)
					tlimit = -1;
			}

			else if (argv[fa][1] == 'd') {
				disp = 1;
				inp = 0;

			} else if (argv[fa][1] == 'i') {
				disp = 0;
				inp = 1;

			} else if (argv[fa][1] == 'v')
				verb = 1;
			else 
				usage("Unknown flag");
		} else
			break;
	}

	/* See how many arguments remain */
	switch (argc - fa) {
		case 2:		/* Must be a new combined device + cie/spectral */
			if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
			strcpy(devname,argv[fa]);
			strcpy(ciename,argv[fa++]);
			if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
			strcpy(outname, argv[fa++]);
			if (verb) printf("Single source file, assumed dev/cie/spectral\n");
			break;
		case 3:		/* Device + cie or spectral */
					/* or combined cie + spectral */
			if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
			strcpy(devname,argv[fa++]);
			if (fa >= argc || argv[fa][0] == '-') usage("Bad cie/spec filename");
			strcpy(ciename,argv[fa++]);	
			if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
			strcpy(outname, argv[fa++]);
			if (verb) printf("Two source files, assumed dev + cie/spectral or dev/cie + spectral\n");
			break;
		case 4:		/* Device, ci and spectral */
			if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
			strcpy(devname,argv[fa++]);
			if (fa >= argc || argv[fa][0] == '-') usage("Bad cie filename");
			strcpy(ciename,argv[fa++]);	
			if (fa >= argc || argv[fa][0] == '-') usage("Bad spec filename");
			strcpy(specname,argv[fa++]);	
			if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
			strcpy(outname, argv[fa++]);
			if (verb) printf("Three source files, assumed dev + cie + spectral\n");
			break;
		default:
			usage("Wrong number of filenames");
	}

	if (out2) {
		strcpy (outname2, outname);
		strcat(outname2,".ti2");
	}

	/* Convert basename into .ti3 */
	strcat(outname,".ti3");

	/* Open up the Input CMYK/RGB reference file (might be same as ncie/spec) */
	cmy = new_cgats();	/* Create a CGATS structure */
	cmy->add_other(cmy, "LGOROWLENGTH"); 	/* Gretag/Logo Target file */
	cmy->add_other(cmy, "Date:");			/* Gretag/Logo Target file */
	cmy->add_other(cmy, "ECI2002");			/* Gretag/Logo Target file */
	cmy->add_other(cmy, ""); 				/* Wildcard */
	if (cmy->read_name(cmy, devname))
		error ("Read: Can't read dev file '%s'. Unknown format, missing or corrupted file ? (%s)",devname,cmy->err);
	if (cmy->ntables != 1)
		warning("Input file '%s' doesn't contain exactly one table",devname);

	if ((npat = cmy->t[0].nsets) <= 0)
		error("No patches");

	if ((f_id1 = cmy->find_field(cmy, 0, "SampleName")) < 0
	 && (f_id1 = cmy->find_field(cmy, 0, "Sample_Name")) < 0
	 && (f_id1 = cmy->find_field(cmy, 0, "SAMPLE_NAME")) < 0
	 && (f_id1 = cmy->find_field(cmy, 0, "SAMPLE_ID")) < 0)
		error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",devname);
	if (cmy->t[0].ftype[f_id1] != nqcs_t
	 && cmy->t[0].ftype[f_id1] != cs_t
	 && cmy->t[0].ftype[f_id1] != i_t)
		error("Field SampleName (%s) from CMYK/RGB file '%s' is wrong type",cmy->t[0].fsym[f_id1],devname);

	if (cmy->find_field(cmy, 0, "RGB_R") >= 0) {
		ndchan = 3;
		if (verb)  {
			if (inp || disp)
				printf("Seems to be an RGB device\n");
			else
				printf("Seems to be a psuedo-RGB device\n");
		}
	} else if (cmy->find_field(cmy, 0, "CMYK_C") >= 0) {
		ndchan = 4;
		if (verb)
			printf("Seems to be a CMYK device\n");
	} else {
		printf("No device values found - hope that's OK!\n");
	}

	if (ndchan == 3) {
		if ((f_c = cmy->find_field(cmy, 0, "RGB_R")) < 0) {
			error("Input file '%s' doesn't contain field RGB_R",devname);
		}
		if (cmy->t[0].ftype[f_c] != r_t)
			error("Field RGB_R from file '%s' is wrong type - expect float",devname);

		if ((f_m = cmy->find_field(cmy, 0, "RGB_G")) < 0)
			error("Input file '%s' doesn't contain field RGB_G",devname);
		if (cmy->t[0].ftype[f_m] != r_t)
			error("Field RGB_G from file '%s' is wrong type - expect float",devname);

		if ((f_y = cmy->find_field(cmy, 0, "RGB_B")) < 0)
			error("Input file '%s' doesn't contain field RGB_B",devname);
		if (cmy->t[0].ftype[f_y] != r_t)
			error("Field RGB_B from file '%s' is wrong type - expect float",devname);

	} else if (ndchan == 4) {
		if ((f_c = cmy->find_field(cmy, 0, "CMYK_C")) < 0) {
			error("Input file '%s' doesn't contain field CMYK_C",devname);
		}
		if (cmy->t[0].ftype[f_c] != r_t)
			error("Field CMYK_C from file '%s' is wrong type - expect float",devname);

		if ((f_m = cmy->find_field(cmy, 0, "CMYK_M")) < 0)
			error("Input file '%s' doesn't contain field CMYK_M",devname);
		if (cmy->t[0].ftype[f_m] != r_t)
			error("Field CMYK_M from file '%s' is wrong type - expect float",devname);

		if ((f_y = cmy->find_field(cmy, 0, "CMYK_Y")) < 0)
			error("Input file '%s' doesn't contain field CMYK_Y",devname);
		if (cmy->t[0].ftype[f_y] != r_t)
			error("Field CMYK_Y from file '%s' is wrong type - expect float",devname);

		if ((f_k = cmy->find_field(cmy, 0, "CMYK_K")) < 0)
			error("Input file '%s' doesn't contain field CMYK_Y",devname);
		if (cmy->t[0].ftype[f_k] != r_t)
			error("Field CMYK_K from file '%s' is wrong type - expect float",devname);
	}
	if (verb && ndchan > 0) printf("Read device values\n");

	if (cmy->find_field(cmy, 0, "XYZ_X") >= 0
	 || cmy->find_field(cmy, 0, "LAB_L") >= 0) {
		/* We've got a new combined device+cie file as the first one. */
		/* Shuffle it into ciename , and ciename into specname */

		strcpy(specname, ciename);
		strcpy(ciename, devname);

		if (verb) printf("We've got a combined device + instrument readings file\n");
	}

	/* Open up the input nCIE or Spectral device data file */
	ncie = new_cgats();	/* Create a CGATS structure */
	ncie->add_other(ncie, "LGOROWLENGTH"); 	/* Gretag/Logo Target file */
	ncie->add_other(ncie, "ECI2002"); 		/* Gretag/Logo Target file */
	ncie->add_other(ncie, ""); 				/* Wildcard */
	if (ncie->read_name(ncie, ciename))
		error ("Read: Can't read cie file '%s'. Unknown format, missing or corrupted file ?",ciename);
	if (ncie->ntables != 1)
		warning("Input file '%s' doesn't contain exactly one table",ciename);

	if (npat != ncie->t[0].nsets)
		error("Number of patches between '%s' and '%s' doesn't match",devname,ciename);

	if ((f_id2 = ncie->find_field(ncie, 0, "SampleName")) < 0
	 && (f_id2 = ncie->find_field(ncie, 0, "Sample_Name")) < 0
	 && (f_id2 = ncie->find_field(ncie, 0, "SAMPLE_NAME")) < 0
	 && (f_id2 = ncie->find_field(ncie, 0, "SAMPLE_ID")) < 0)
		error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",ciename);
	if (ncie->t[0].ftype[f_id2] != nqcs_t
	 && ncie->t[0].ftype[f_id2] != cs_t
	 && cmy->t[0].ftype[f_id2] != i_t)
		error("Field SampleName (%s) from cie file '%s' is wrong type",ncie->t[0].fsym[f_id2],ciename);

	if (ncie->find_field(ncie, 0, "XYZ_X") < 0
	 && ncie->find_field(ncie, 0, "LAB_L") < 0) {

		/* Not a cie file. See if it's a spectral file */
		if (ncie->find_field(ncie, 0, "nm500") < 0
		 && ncie->find_field(ncie, 0, "NM_500") < 0
		 && ncie->find_field(ncie, 0, "SPECTRAL_NM_500") < 0
		 && ncie->find_field(ncie, 0, "R_500") < 0
		 && ncie->find_field(ncie, 0, "SPECTRAL_500") < 0)
			error("Input file '%s' doesn't contain field XYZ_X or spectral",ciename);	/* Nope */

		/* We have a spectral file only. Fix things and drop through */
		ncie->del(ncie);
		ncie = NULL;
		strcpy(specname, ciename);
		ciename[0] = '\000';

	} else {	/* Continue dealing with cie value file */
		char *fields[2][3] = {
			{ "XYZ_X", "XYZ_Y", "XYZ_Z" },
			{ "LAB_L", "LAB_A", "LAB_B" }
		};

		if (ncie->find_field(ncie, 0, "nm500") >= 0
		 || ncie->find_field(ncie, 0, "NM_500") < 0
		 || ncie->find_field(ncie, 0, "SPECTRAL_NM_500") >= 0
		 || ncie->find_field(ncie, 0, "R_500") >= 0
		 || ncie->find_field(ncie, 0, "SPECTRAL_500") >= 0) {
			if (verb) printf("Found spectral values\n");
			/* It's got spectral data too. Make sure we read it */
			strcpy(specname, ciename);
		}

		if (ncie->find_field(ncie, 0, "LAB_L") >= 0)
			islab = 1;

		for (i = 0; i < 3; i++) {

			if ((f_cie[i] = ncie->find_field(ncie, 0, fields[islab][i])) < 0)
				error("Input file '%s' doesn't contain field XYZ_Y",fields[islab][i], ciename);

			if (ncie->t[0].ftype[f_cie[i]] != r_t)
				error("Field %s from file '%s' is wrong type - expect float",fields[islab][i], ciename);
		}
	
		if (verb) printf("Found CIE values\n");
	}

	/* Open up the input Spectral device data file */
	if (specname[0] != '\000') {
		char bufs[5][50];

		spec = new_cgats();	/* Create a CGATS structure */
		spec->add_other(spec, "LGOROWLENGTH"); 	/* Gretag/Logo Target file */
		spec->add_other(spec, "ECI2002"); 		/* Gretag/Logo Target file */
		spec->add_other(spec, ""); 				/* Wildcard */
		if (spec->read_name(spec, specname))
			error ("Read: Can't read spec file '%s'. Unknown format, missing or corrupted file ?",specname);
		if (spec->ntables != 1)
			warning("Input file '%s' doesn't contain exactly one table",specname);

		if (npat != spec->t[0].nsets)
			error("Number of patches between '%s' and '%s' doesn't match",specname);

		if ((f_id3 = spec->find_field(spec, 0, "SampleName")) < 0
		 && (f_id3 = spec->find_field(spec, 0, "Sample_Name")) < 0
		 && (f_id3 = spec->find_field(spec, 0, "SAMPLE_NAME")) < 0
		 && (f_id3 = spec->find_field(spec, 0, "SAMPLE_ID")) < 0)
			error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",specname);
		if (spec->t[0].ftype[f_id3] != nqcs_t
		 && spec->t[0].ftype[f_id3] != cs_t
		 && cmy->t[0].ftype[f_id3] != i_t)
			error("Field SampleName (%s) from spec file '%s' is wrong type",spec->t[0].fsym[f_id3],specname);

		/* Find the spectral readings nm range */
		for (specmin = 500; specmin >= 300; specmin -= 10) {
			sprintf(bufs[0],"nm%03d", specmin);
			sprintf(bufs[1],"NM_%03d", specmin);
			sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin);
			sprintf(bufs[3],"R_%03d", specmin);
			sprintf(bufs[4],"SPECTRAL_%03d", specmin);

			if (spec->find_field(spec, 0, bufs[0]) < 0
			 && spec->find_field(spec, 0, bufs[1]) < 0
			 && spec->find_field(spec, 0, bufs[2]) < 0
			 && spec->find_field(spec, 0, bufs[3]) < 0
			 && spec->find_field(spec, 0, bufs[4]) < 0)	/* Not found */
			break;
		}
		specmin += 10;
		for (specmax = 500; specmax <= 900; specmax += 10) {
			sprintf(bufs[0],"nm%03d", specmax);
			sprintf(bufs[1],"NM_%03d", specmax);
			sprintf(bufs[2],"SPECTRAL_NM_%03d", specmax);
			sprintf(bufs[3],"R_%03d", specmax);
			sprintf(bufs[4],"SPECTRAL_%03d", specmax);

			if (spec->find_field(spec, 0, bufs[0]) < 0
			 && spec->find_field(spec, 0, bufs[1]) < 0
			 && spec->find_field(spec, 0, bufs[2]) < 0
			 && spec->find_field(spec, 0, bufs[3]) < 0
			 && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */
			break;
		}
		specmax -= 10;
				
		if (specmin > 420 || specmax < 680) {	/* Not enough range to be useful */
			spec->del(spec);
			spec = NULL;
			specname[0] = '\000';
		} else {

			specnum = (specmax - specmin)/10 + 1;

			if (verb)
				printf("Found there are %d spectral values, from %d to %d nm\n",specnum,specmin,specmax);
			

			/* Locate the fields for spectral values */
			for (j = 0; j < specnum; j++) {
				sprintf(bufs[0],"nm%03d", specmin + 10 * j);
				sprintf(bufs[1],"NM_%03d", specmin + 10 * j);
				sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin + 10 * j);
				sprintf(bufs[3],"R_%03d", specmin + 10 * j);
				sprintf(bufs[4],"SPECTRAL_%03d", specmin + 10 * j);
	
				if ((spi[j] = spec->find_field(spec, 0, bufs[0])) < 0
				 && (spi[j] = spec->find_field(spec, 0, bufs[1])) < 0
				 && (spi[j] = spec->find_field(spec, 0, bufs[2])) < 0
				 && (spi[j] = spec->find_field(spec, 0, bufs[3])) < 0
				 && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0) {	/* Not found */
					
					spec->del(spec);
					spec = NULL;
					specname[0] = '\000';
					error("Failed to find spectral band %d nm in file '%s'\n",specmin + 10 * j,specname);
				} else {
					if (spec->t[0].ftype[spi[j]] != r_t)
						error("Field '%s' from file '%s' is wrong type - expect float",spec->t[0].fsym[spi[j]], specname);
				}

			}
		}
	}

	if (ciename[0] == '\000' && specname[0] == '\000')
		error("Input file doesn't contain either CIE or spectral data");

	/* Setup output cgats file */
	ocg = new_cgats();	/* Create a CGATS structure */
	ocg->add_other(ocg, "CTI3"); 	/* our special type is Calibration Target Information 3 */
	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */

	ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
	atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
	if (disp)
		ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);	/* What sort of device this is */
	else if (inp)
		ocg->add_kword(ocg, 0, "DEVICE_CLASS","INPUT", NULL);	/* What sort of device this is */
	else
		ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);	/* What sort of device this is */

	/* Note what instrument the chart was read with */
	/* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */
	ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL);

	/* Fields we want */
	ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
	if (f_id1 >= 0) 
		ocg->add_field(ocg, 0, "SAMPLE_NAME", cs_t);

	if (ndchan == 3) {
		ocg->add_field(ocg, 0, "RGB_R", r_t);
		ocg->add_field(ocg, 0, "RGB_G", r_t);
		ocg->add_field(ocg, 0, "RGB_B", r_t);
		if (inp) {
			if (islab)
				ocg->add_kword(ocg, 0, "COLOR_REP","LAB_RGB", NULL);
			else
				ocg->add_kword(ocg, 0, "COLOR_REP","XYZ_RGB", NULL);
		} else if (disp) {
			if (islab)
				ocg->add_kword(ocg, 0, "COLOR_REP","RGB_LAB", NULL);
			else
				ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
		} else {
			if (islab)
				ocg->add_kword(ocg, 0, "COLOR_REP","iRGB_LAB", NULL);
			else
				ocg->add_kword(ocg, 0, "COLOR_REP","iRGB_XYZ", NULL);
		}
	} else if (ndchan == 4) {
		ocg->add_field(ocg, 0, "CMYK_C", r_t);
		ocg->add_field(ocg, 0, "CMYK_M", r_t);
		ocg->add_field(ocg, 0, "CMYK_Y", r_t);
		ocg->add_field(ocg, 0, "CMYK_K", r_t);
		if (inp) {	/* Does this make any sense ? */
			if (islab)
				ocg->add_kword(ocg, 0, "COLOR_REP","LAB_CMYK", NULL);
			else
				ocg->add_kword(ocg, 0, "COLOR_REP","XYZ_CMYK", NULL);
		} else {
			if (islab)
				ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_LAB", NULL);
			else
				ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_XYZ", NULL);
		}
	}

	if (ncie != NULL) {
		if (islab) {
			ocg->add_field(ocg, 0, "LAB_L", r_t);
			ocg->add_field(ocg, 0, "LAB_A", r_t);
			ocg->add_field(ocg, 0, "LAB_B", r_t);
		} else {
			ocg->add_field(ocg, 0, "XYZ_X", r_t);
			ocg->add_field(ocg, 0, "XYZ_Y", r_t);
			ocg->add_field(ocg, 0, "XYZ_Z", r_t);
		}
	}

	/* Guess the device data scaling */
	if (ndchan > 0) {
		double maxv = 0.0;
		int f_dev[4] = { f_c, f_m, f_y, f_k };

		/* Guess what scale the spectral data is set to */
		for (i = 0; i < npat; i++) {
			for (j = 0; j < ndchan; j++) {
				double vv;
				vv = *((double *)cmy->t[0].fdata[i][f_dev[j]]);
				if (vv > maxv)
					maxv = vv;
			}
		}
		if (maxv < 10.0) {
			dev_scale = 100.0/1.0;
			if (verb) printf("Device max found = %f, scale by 100.0\n",maxv);
		} else if (maxv > 160.0) {
			dev_scale = 100.0/255.0;
			if (verb) printf("Device max found = %f, scale by 100/255\n",maxv);
		} else {
			dev_scale = 100.0/100.0;
			if (verb) printf("Device max found = %f, scale by 1.0\n",maxv);
		}
	}

	if (spec != NULL) {
		char buf[100];
		double maxv = 0.0;
		sprintf(buf,"%d", specnum);
		ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
		sprintf(buf,"%d", specmin);
		ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
		sprintf(buf,"%d", specmax);
		ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);

		/* Generate fields for spectral values */
		for (j = 0; j < specnum; j++) {
			sprintf(buf,"SPEC_%03d", specmin + 10 * j);
			ocg->add_field(ocg, 0, buf, r_t);
		}

		/* Guess what scale the spectral data is set to */
		for (i = 0; i < npat; i++) {
			for (j = 0; j < specnum; j++) {
				double vv;
				vv = *((double *)spec->t[0].fdata[i][spi[j]]);
				if (vv > maxv)
					maxv = vv;
			}
		}
		if (maxv < 10.0) {
			spec_scale = 100.0/1.0;
			if (verb) printf("Spectral max found = %f, scale by 100.0\n",maxv);
		} else if (maxv > 160.0) {
			spec_scale = 100.0/255.0;
			if (verb) printf("Spectral max found = %f, scale by 100/255\n",maxv);
		} else {
			spec_scale = 100.0/100.0;
			if (verb) printf("Spectral max found = %f, scale by 1.0\n",maxv);
		}
	}

	/* Write out the patch info to the output CGATS file */
	{
		cgats_set_elem *setel;	/* Array of set value elements */

		if ((setel = (cgats_set_elem *)malloc(
		     sizeof(cgats_set_elem) * ocg->t[0].nfields)) == NULL)
			error("Malloc failed!");

		/* Write out the patch info to the output CGATS file */
		for (i = 0; i < npat; i++) {
			char id[100];
			int k = 0;

			if (ncie != NULL) {
				if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]), 
				           ((char *)ncie->t[0].rfdata[i][f_id2])) != 0) {
					error("Patch label mismatch to CIE values, patch %d, '%s' != '%s'\n",
					       i, ((char *)cmy->t[0].rfdata[i][f_id1]), 
				              ((char *)ncie->t[0].rfdata[i][f_id2]));
				}
			}

			if (spec != NULL) {
				if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]), 
				           ((char *)spec->t[0].rfdata[i][f_id3])) != 0) {
					error("Patch label mismatch to spectral values, patch %d, '%s' != '%s'\n",
					       i, ((char *)cmy->t[0].rfdata[i][f_id1]), 
				              ((char *)spec->t[0].rfdata[i][f_id3]));
				}
			}

			/* SAMPLE ID */
			sprintf(id, "%d", i+1);
			setel[k++].c = id;

			/* SAMPLE NAME */
			if (f_id1 >= 0) 
				setel[k++].c = (char *)cmy->t[0].rfdata[i][f_id1];
			
			if (ndchan == 3) {
				setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]);
				setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_m]);
				setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_y]);
			} else if (ndchan == 4){
				double sum = 0.0;
				sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]);
				sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_m]);
				sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_y]);
				sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_k]);
				if (sum > mxsum) {
					mxsum = sum;
					mxsumix = i;
				}
			}
	
			if (ncie != NULL) {
				setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[0]]);	
				setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[1]]);
				setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[2]]);
			}
	
			if (spec) {
				for (j = 0; j < specnum; j++) {
					setel[k++].d = spec_scale * *((double *)spec->t[0].fdata[i][spi[j]]);
				}
			}

			ocg->add_setarr(ocg, 0, setel);
		}

		free(setel);
	}

	if (tlimit < 0 && mxsum > 0.0) {
		if (verb)
			printf("No ink limit given, using maximum %f found in file at %d\n",mxsum,mxsumix+1);

		tlimit = (int)(mxsum + 0.5);
	}

	if (tlimit > 0) {
		char buf[100];
		sprintf(buf, "%d", tlimit);
		ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT", buf, NULL);
	}

	if (ocg->write_name(ocg, outname))
		error("Write error : %s",ocg->err);

	/* Create a dummy .ti2 file (used with scanin -r) */
	if (out2) {

		/* Setup output cgats file */
		ocg2 = new_cgats();	/* Create a CGATS structure */
		ocg2->add_other(ocg2, "CTI2"); 	/* our special type is Calibration Target Information 2 */
		ocg2->add_table(ocg2, tt_other, 0);	/* Start the first table */

		ocg2->add_kword(ocg2, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 2",NULL);
		ocg2->add_kword(ocg2, 0, "ORIGINATOR", "Argyll txt2ti3", NULL);
		atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
		ocg2->add_kword(ocg2, 0, "CREATED",atm, NULL);
		if (disp)
			ocg2->add_kword(ocg2, 0, "DEVICE_CLASS","DISPLAY", NULL);	/* What sort of device this is */
		else
			ocg2->add_kword(ocg2, 0, "DEVICE_CLASS","OUTPUT", NULL);	/* What sort of device this is */
		/* Note what instrument the chart was read with */
		/* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */
		ocg2->add_kword(ocg2, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL);

		/* Fields we want */
		ocg2->add_field(ocg2, 0, "SAMPLE_ID", nqcs_t);
		ocg2->add_field(ocg2, 0, "SAMPLE_LOC", nqcs_t);

		/* We're missing lots of .ti2 stuff like: */
		/* ocg->add_kword(ocg, 0, "APPROX_WHITE_POINT",icg->t[0].kdata[fi], NULL); */
		/* ocg->add_kword(ocg, 0, "PATCH_LENGTH", buf, NULL); */
		/* ocg->add_kword(ocg, 0, "GAP_LENGTH", buf, NULL); */
		/* ocg->add_kword(ocg, 0, "TRAILER_LENGTH", buf, NULL); */
		/* ocg->add_kword(ocg, 0, "STEPS_IN_PASS", buf, NULL); */
		/* ocg->add_kword(ocg, 0, "PASSES_IN_STRIPS", pis, NULL); */
		/* ocg->add_kword(ocg, 0, "STRIP_INDEX_PATTERN", sixpat, NULL); */
		/* ocg->add_kword(ocg, 0, "PATCH_INDEX_PATTERN", pixpat, NULL); */
		/* ocg->add_kword(ocg, 0, "INDEX_ORDER", ixord ? "PATCH_THEN_STRIP" : "STRIP_THEN_PATCH", NULL); */

		if (tlimit > 0) {
			char buf[100];
			sprintf(buf, "%d", tlimit);
			ocg2->add_kword(ocg2, 0, "TOTAL_INK_LIMIT", buf, NULL);
		}

		if (ndchan == 3) {
			ocg2->add_field(ocg2, 0, "RGB_R", r_t);
			ocg2->add_field(ocg2, 0, "RGB_G", r_t);
			ocg2->add_field(ocg2, 0, "RGB_B", r_t);
			if (inp || disp) {
				ocg2->add_kword(ocg2, 0, "COLOR_REP","RGB", NULL);
			} else {
				ocg2->add_kword(ocg2, 0, "COLOR_REP","iRGB", NULL);
			}
		} else if (ndchan == 4) {
			ocg2->add_field(ocg2, 0, "CMYK_C", r_t);
			ocg2->add_field(ocg2, 0, "CMYK_M", r_t);
			ocg2->add_field(ocg2, 0, "CMYK_Y", r_t);
			ocg2->add_field(ocg2, 0, "CMYK_K", r_t);
			ocg2->add_kword(ocg2, 0, "COLOR_REP","CMYK", NULL);
		}

		if (ncie != NULL) {
			if (islab) {
				ocg2->add_field(ocg2, 0, "LAB_L", r_t);
				ocg2->add_field(ocg2, 0, "LAB_A", r_t);
				ocg2->add_field(ocg2, 0, "LAB_B", r_t);
			} else {
				ocg2->add_field(ocg2, 0, "XYZ_X", r_t);
				ocg2->add_field(ocg2, 0, "XYZ_Y", r_t);
				ocg2->add_field(ocg2, 0, "XYZ_Z", r_t);
			}
		}

		/* Write out the patch info to the output CGATS file */
		{
			cgats_set_elem *setel;	/* Array of set value elements */

			if ((setel = (cgats_set_elem *)malloc(
			     sizeof(cgats_set_elem) * (2 + (ndchan) + (ncie != NULL ? 3 : 0)))) == NULL)
				error("Malloc failed!");

			/* Write out the patch info to the output CGATS file */
			for (i = 0; i < npat; i++) {
				char id[100];
				int k = 0;

				if (ncie != NULL) {
					if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]), 
					           ((char *)ncie->t[0].rfdata[i][f_id2])) != 0) {
						error("Patch label mismatch to CIE values, patch %d, '%s' != '%s'\n",
						       i, ((char *)cmy->t[0].rfdata[i][f_id1]), 
					              ((char *)ncie->t[0].rfdata[i][f_id2]));
					}
				}

				if (spec != NULL) {
					if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]), 
					           ((char *)spec->t[0].rfdata[i][f_id3])) != 0) {
						error("Patch label mismatch to spectral values, patch %d, '%s' != '%s'\n",
						       i, ((char *)cmy->t[0].rfdata[i][f_id1]), 
					              ((char *)spec->t[0].rfdata[i][f_id3]));
					}
				}

				sprintf(id, "%d", i+1);
				setel[k++].c = id;						/* ID */
				setel[k++].c = ((char *)cmy->t[0].rfdata[i][f_id1]); 	/* Location */

				if (ndchan == 3) {
					setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_c]);
					setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_m]);
					setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_y]);
				} else if (ndchan == 4) {
					setel[k++].d = *((double *)cmy->t[0].fdata[i][f_c]);
					setel[k++].d = *((double *)cmy->t[0].fdata[i][f_m]);
					setel[k++].d = *((double *)cmy->t[0].fdata[i][f_y]);
					setel[k++].d = *((double *)cmy->t[0].fdata[i][f_k]);
				}
		
				if (ncie != NULL) {
					setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[0]]);	
					setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[1]]);
					setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[2]]);
				}
				ocg2->add_setarr(ocg2, 0, setel);
			}

			free(setel);
		}

		if (ocg2->write_name(ocg2, outname2))
			error("Write error : %s",ocg2->err);

	}

	/* Clean up */
	cmy->del(cmy);
	if (ncie != NULL)
		ncie->del(ncie);
	if (spec != NULL)
		spec->del(spec);
	ocg->del(ocg);

	return 0;
}
Exemplo n.º 5
0
int
main(int argc, char *argv[]) {
	int fa,nfa;				/* argument we're looking at */
	struct {
		char name[MAXNAMEL+1];	/* Patch filename  */
		int npat;				/* Number of patches */
		pval *pat;				/* patch values */
	} cg[2];					/* Target and current patch file information */
	char dev_name[MAXNAMEL+1];	/* Output device ICC filename for gamut */
	char rd_name[MAXNAMEL+1];	/* Abstract profile ICC to modify */
	char wr_name[MAXNAMEL+1];	/* Modified/created abstract profile ICC */

	int dorel = 0;				/* Do white point relative match */
	int *match;					/* Array mapping first list indexes to corresponding second */
	int fwacomp = 0;			/* FWA compensation on spectral ? */
	int spec = 0;				/* Use spectral data flag */
	icxIllumeType illum = icxIT_D50;	/* Spectral defaults */
	xspect cust_illum;					/* Custom illumination spectrum */
	icxObserverType observ = icxOT_Judd_Voss_2;
	callback cb;				/* Callback support stucture for setting abstract profile */

	icmFile *rd_fp = NULL;		/* Existing abstract profile to modify */
	icc *rd_icc = NULL;

	icmFile *wr_fp;				/* Modified/created abstract profile to write */
	icc *wr_icc;

	int verb = 0;
	int nogamut = 0;					/* Don't impose a gamut limit */
	int docreate = 0;					/* Create an initial abstract correction profile */
	int clutres = DEF_CLUTRES;			/* Output abstract profile clut resolution */
	double damp1 = DEF_DAMP1;			/* Initial damping factor */
	double damp2 = DEF_DAMP2;			/* Subsequent damping factor */
	double smoothf = SMOOTHF;			/* RSPL Smoothing factor */
	double avgdev[MXDO];				/* RSPL Average Deviation */
	double wweight = WWEIGHT;			/* weak default function weight */
	int whitepatch = -1;				/* Index of white patch */
	double merr = 0.0, aerr = 0.0;		/* Stats on color change */
	int i, j, e, n, rv = 0;

	error_program = argv[0];

	if (argc < 6)
		usage("Too few arguments");

	/* 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 */
					}
				}
			}

			if (argv[fa][1] == '?')
				usage("Usage requested");

			/* Verbosity */
			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
				verb = 1;
			}
			/* Create initial abstract correction profile */
			else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
				docreate = 1;
			}
			/* Don't impose a gamut limit */
			else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
				nogamut = 1;
			}
			/* Override the correction clut resolution */
			else if (argv[fa][1] == 'r') {
				fa = nfa;
				if (na == NULL) usage("Expect argument to -r");
				clutres = atoi(na);
			}
			/* Override the damping factor */
			else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
				fa = nfa;
				if (na == NULL) usage("Expect argument to -d");
				damp2 = atof(na);
			}
			/* Aim for white point relative match */
			else if (argv[fa][1] == 'R') {
				dorel = 1;
			}

			/* Spectral Illuminant type */
			else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
				fa = nfa;
				if (na == NULL) usage("Expect argument to -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, "D65") == 0) {
					spec = 1;
					illum = icxIT_D65;
				} 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 spectrum '%s'",na);
				}
			}

			/* Spectral Observer type */
			else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
				fa = nfa;
				if (na == NULL) usage("Expected argument to -o");
				if (strcmp(na, "1931_2") == 0) {			/* Classic 2 degree */
					spec = 1;
					observ = icxOT_CIE_1931_2;
				} else if (strcmp(na, "1964_10") == 0) {	/* Classic 10 degree */
					spec = 1;
					observ = icxOT_CIE_1964_10;
				} else if (strcmp(na, "1955_2") == 0) {		/* Stiles and Burch 1955 2 degree */
					spec = 1;
					observ = icxOT_Stiles_Burch_2;
				} else if (strcmp(na, "1978_2") == 0) {		/* Judd and Voss 1978 2 degree */
					spec = 1;
					observ = icxOT_Judd_Voss_2;
				} else if (strcmp(na, "shaw") == 0) {		/* Shaw and Fairchilds 1997 2 degree */
					spec = 1;
					observ = icxOT_Shaw_Fairchild_2;
				} else
					usage("Unrecogised argument '%s' to -o",na);
			}

			/* FWA compensation */
			else if (argv[fa][1] == 'f' || argv[fa][1] == 'F')
				fwacomp = 1;

			else 
				usage("Unrecognised flag -%c",argv[fa][1]);
		} else
			break;
	}

	/* Grab all the filenames: */

	/* The two CIE value files */
	if (fa >= argc || argv[fa][0] == '-') usage("Expected cietarget file argument");
	strncpy(cg[0].name,argv[fa++],MAXNAMEL); cg[0].name[MAXNAMEL] = '\000';

	if (fa >= argc || argv[fa][0] == '-') usage("Expected ciecurrent file argument");
	strncpy(cg[1].name,argv[fa++],MAXNAMEL); cg[1].name[MAXNAMEL] = '\000';

	/* Optional output device name */
	if (nogamut == 0) {
		if (fa >= argc || argv[fa][0] == '-') usage("Expected outdevicc file argument");
		strncpy(dev_name,argv[fa++],MAXNAMEL); dev_name[MAXNAMEL] = '\000';
	}

	/* Optional input abstract profile name */
	if (docreate == 0) {
		if (fa >= argc || argv[fa][0] == '-') usage("Expected inabs file argument");
		strncpy(rd_name,argv[fa++],MAXNAMEL); rd_name[MAXNAMEL] = '\000';
	}

	/* Output abstract profile name */
	if (fa >= argc || argv[fa][0] == '-') usage("Expected outabs file argument");
	strncpy(wr_name,argv[fa++],MAXNAMEL); wr_name[MAXNAMEL] = '\000';

	/* ======================= */
	/* Open up each CIE file in turn, target then measured, */
	/* and read in the CIE values. */
	for (n = 0; n < 2; n++) {
		cgats *cgf = NULL;			/* cgats file data */
		int isLab = 0;				/* 0 if file CIE is XYZ, 1 if is Lab */
		int sidx;					/* Sample ID index */
		int xix, yix, zix;

		/* Open CIE target values */
		cgf = new_cgats();			/* Create a CGATS structure */
		cgf->add_other(cgf, ""); 	/* Allow any signature file */
	
		if (cgf->read_name(cgf, cg[n].name))
			error("CGATS file '%s' read error : %s",cg[n].name,cgf->err);
	
		if (cgf->ntables < 1)
			error ("Input file '%s' doesn't contain at least one table",cg[n].name);
	
		/* Check if the file is suitable */
		if (!spec
		 && cgf->find_field(cgf, 0, "LAB_L") < 0
		 && cgf->find_field(cgf, 0, "XYZ_X") < 0) {
	
			if (cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
				error ("Neither CIE nor spectral data found in file '%s'",cg[n].name);
	
			/* Switch to using spectral information */
			if (verb)
				printf("No CIE data found, switching to spectral with standard observer & D50 for file '%s'\n",cg[n].name);
			spec = 1;
			illum = icxIT_D50;
			observ = icxOT_CIE_1931_2;
		}
		if (spec && cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
			error ("No spectral data data found in file '%s' when spectral expected",cg[n].name);
	
		if (!spec && cgf->find_field(cgf, 0, "LAB_L") >= 0)
			isLab = 1;
		
		cg[n].npat = cgf->t[0].nsets;		/* Number of patches */
	
		/* Read all the target patches */
		if (cg[n].npat <= 0)
			error("No sets of data in file '%s'",cg[n].name);
	
		if (verb && n == 0) {
			fprintf(verbo,"No of test patches = %d\n",cg[n].npat);
		}
	
		/* Allocate arrays to hold test patch input and output values */
		if ((cg[n].pat = (pval *)malloc(sizeof(pval) * cg[n].npat)) == NULL)
			error("Malloc failed - pat[]");
	
		/* Read in the CGATs fields */
		if ((sidx = cgf->find_field(cgf, 0, "SAMPLE_ID")) < 0
		 && (sidx = cgf->find_field(cgf, 0, "SampleName")) < 0
		 && (sidx = cgf->find_field(cgf, 0, "Sample_Name")) < 0
		 && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0
		 && (sidx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0)
			error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_LOC",cg[n].name);
		if (cgf->t[0].ftype[sidx] != nqcs_t
		 && cgf->t[0].ftype[sidx] != cs_t)
			error("Sample ID/Name field isn't a quoted or non quoted character string");

		if (spec == 0) { 		/* Using instrument tristimulous value */

			if (isLab) {		/* Expect Lab */
				if ((xix = cgf->find_field(cgf, 0, "LAB_L")) < 0)
					error("Input file '%s' doesn't contain field LAB_L",cg[n].name);
				if (cgf->t[0].ftype[xix] != r_t)
					error("Field LAB_L is wrong type");
				if ((yix = cgf->find_field(cgf, 0, "LAB_A")) < 0)
					error("Input file '%s' doesn't contain field LAB_A",cg[n].name);
				if (cgf->t[0].ftype[yix] != r_t)
					error("Field LAB_A is wrong type");
				if ((zix = cgf->find_field(cgf, 0, "LAB_B")) < 0)
					error("Input file '%s' doesn't contain field LAB_B",cg[n].name);
				if (cgf->t[0].ftype[zix] != r_t)
					error("Field LAB_B is wrong type");

			} else { 		/* Expect XYZ */
				if ((xix = cgf->find_field(cgf, 0, "XYZ_X")) < 0)
					error("Input file '%s' doesn't contain field XYZ_X",cg[n].name);
				if (cgf->t[0].ftype[xix] != r_t)
					error("Field XYZ_X is wrong type");
				if ((yix = cgf->find_field(cgf, 0, "XYZ_Y")) < 0)
					error("Input file '%s' doesn't contain field XYZ_Y",cg[n].name);
				if (cgf->t[0].ftype[yix] != r_t)
					error("Field XYZ_Y is wrong type");
				if ((zix = cgf->find_field(cgf, 0, "XYZ_Z")) < 0)
					error("Input file '%s' doesn't contain field XYZ_Z",cg[n].name);
				if (cgf->t[0].ftype[zix] != r_t)
					error("Field XYZ_Z is wrong type");
			}

			for (i = 0; i < cg[n].npat; i++) {
				strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]);
				cg[n].pat[i].v[0] = *((double *)cgf->t[0].fdata[i][xix]);
				cg[n].pat[i].v[1] = *((double *)cgf->t[0].fdata[i][yix]);
				cg[n].pat[i].v[2] = *((double *)cgf->t[0].fdata[i][zix]);
				if (!isLab) {
					cg[n].pat[i].v[0] /= 100.0;		/* Normalise XYZ to range 0.0 - 1.0 */
					cg[n].pat[i].v[1] /= 100.0;
					cg[n].pat[i].v[2] /= 100.0;
				}
				if (!isLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
					icmXYZ2Lab(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
				}
			}

		} else { 		/* Using spectral data */
			int ii;
			xspect sp;
			char buf[100];
			int  spi[XSPECT_MAX_BANDS];	/* CGATS indexes for each wavelength */
			xsp2cie *sp2cie;	/* Spectral conversion object */

			if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_BANDS")) < 0)
				error ("Input file doesn't contain keyword SPECTRAL_BANDS");
			sp.spec_n = atoi(cgf->t[0].kdata[ii]);
			if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_START_NM")) < 0)
				error ("Input file doesn't contain keyword SPECTRAL_START_NM");
			sp.spec_wl_short = atof(cgf->t[0].kdata[ii]);
			if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_END_NM")) < 0)
				error ("Input file doesn't contain keyword SPECTRAL_END_NM");
			sp.spec_wl_long = atof(cgf->t[0].kdata[ii]);
			sp.norm = 100.0;

			/* Find the fields for spectral values */
			for (j = 0; j < sp.spec_n; j++) {
				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] = cgf->find_field(cgf, 0, buf)) < 0)
					error("Input file doesn't contain field %s",buf);
			}

			/* Figure out what sort of device it is */
			{
				int ti;
		
				if ((ti = cgf->find_kword(cgf, 0, "DEVICE_CLASS")) < 0)
					error ("Input file '%s' doesn't contain keyword DEVICE_CLASS",cg[n].name);
		
				if (strcmp(cgf->t[0].kdata[ti],"DISPLAY") == 0) {
					illum = icxIT_none;		/* Displays are assumed to be self luminous */
				}
			}

			/* Create a spectral conversion object */
			if ((sp2cie = new_xsp2cie(illum, illum == icxIT_none ? NULL : &cust_illum,
			                          observ, NULL, icSigLabData)) == NULL)
				error("Creation of spectral conversion object failed");

			if (fwacomp) {
				int ti;
				xspect mwsp;			/* Medium spectrum */
				instType itype;			/* Spectral instrument type */
				xspect insp;			/* Instrument illuminant */

				mwsp = sp;		/* Struct copy */

	 			if ((ti = cgf->find_kword(cgf, 0, "TARGET_INSTRUMENT")) < 0)
					error ("Can't find target instrument in '%s' needed for FWA compensation",cg[n].name);

				if ((itype = inst_enum(cgf->t[0].kdata[ti])) == instUnknown)
					error ("Unrecognised target instrument '%s'", cgf->t[0].kdata[ti]);

				if (inst_illuminant(&insp, itype) != 0)
					error ("Instrument doesn't have an FWA illuminent");

				/* Determine a media white spectral reflectance */
				for (j = 0; j < mwsp.spec_n; j++)
					mwsp.spec[j] = 0.0;

				/* Track the maximum reflectance for any band to determine white. */
				/* This might silently fail, if there isn't white in the sampe set. */
				for (i = 0; i < cg[0].npat; i++) {
					for (j = 0; j < mwsp.spec_n; j++) {
						double rv = *((double *)cgf->t[0].fdata[i][spi[j]]);
						if (rv > mwsp.spec[j])
							mwsp.spec[j] = rv;
					}
				}
				if (sp2cie->set_fwa(sp2cie, &insp, &mwsp)) 
					error ("Set FWA on sp2cie failed");
			}

			for (i = 0; i < cg[0].npat; i++) {

				strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]);

				/* Read the spectral values for this patch */
				for (j = 0; j < sp.spec_n; j++) {
					sp.spec[j] = *((double *)cgf->t[0].fdata[i][spi[j]]);
				}

				/* Convert it to CIE space */
				sp2cie->convert(sp2cie, cg[n].pat[i].v, &sp);
			}

			sp2cie->del(sp2cie);		/* Done with this */

		}	/* End of reading in CGATs file */
		cgf->del(cgf);		/* Clean up */
	}

	/* Check that the number of test patches matches */
	if (cg[0].npat != cg[1].npat)
		error("Number of patches between '%s' and '%s' doesn't match",cg[0].name,cg[1].name);
	
	/* Create a list to map the second list (measured) of patches to the first (target) */
	if ((match = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL)
		error("Malloc failed - match[]");
	for (i = 0; i < cg[0].npat; i++) {
		for (j = 0; j < cg[1].npat; j++) {
			if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0)
				break;			/* Found it */
		}
		if (j < cg[1].npat) {
			match[i] = j;
		} else {
			error("Failed to find matching patch to '%s'",cg[0].pat[i].sid);
		}
	}

	/* Try and figure out which is the white patch */
	{
		double hL = -1.0;
		for (i = 0; i < cg[0].npat; i++) {
			if (cg[0].pat[i].v[0] > hL) {
				hL = cg[0].pat[i].v[0];
				whitepatch = i;
			}
		}
	}

	/* If we are aiming for a white point relative match, adjust the */
	/* measured and target values to have a D50 white point */
	if (dorel) {
		for (n = 0; n < 2; n++) {
			int wpix;			/* White patch index */
			double wp_xyz[3];
			icmXYZNumber wp;	/* White value */
			double mat[3][3];	/* Chromatic transform */
			
			if (n == 0)
				wpix = whitepatch;
			else
				wpix = match[whitepatch];
		

			/* Compute a chromatic correction matrix */
			icmLab2XYZ(&icmD50, wp_xyz, cg[n].pat[wpix].v);
			icmAry2XYZ(wp, wp_xyz);

			icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, wp, mat);

			for (i = 0; i < cg[n].npat; i++) {
				icmLab2XYZ(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
				icmMulBy3x3(cg[n].pat[i].v, mat, cg[n].pat[i].v);
				icmXYZ2Lab(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
//printf("Table %d, patch %d, Lab %f %f %f\n",n,i,cg[n].pat[i].v[0],cg[n].pat[i].v[1],cg[n].pat[i].v[2]);
			}
		}
	}

	/* Compute the delta E's just for information */
	for (i = 0; i < cg[0].npat; i++) {
		double de = icmLabDE(cg[0].pat[i].v, cg[1].pat[match[i]].v);
		cg[0].pat[i].de = de;
		if (de > merr)
			merr = de;
		aerr += de;
	}
	if (cg[0].npat > 0)
		aerr /= (double)cg[0].npat;

	if (verb) {
		fprintf(verbo,"No of correction patches = %d\n",cg[0].npat);
		fprintf(verbo,"Average dE = %f, Maximum dE = %f\n",aerr,merr);
		fprintf(verbo,"White patch assumed to be patch %s\n",cg[0].pat[whitepatch].sid);
	}

	/* ======================= */
	/* Possible limiting gamut */
	if (nogamut == 0) {
		icmFile *dev_fp;
		icc *dev_icc;
		xicc *dev_xicc;
		icxLuBase *dev_luo;
		icxInk ink;							/* Ink parameters */

		/* Open up the device ICC profile, so that we can create a gamut */
		/* and get an absolute PCS->device conversion */
		if ((dev_fp = new_icmFileStd_name(dev_name,"r")) == NULL)
			error ("Can't open file '%s'",dev_name);
	
		if ((dev_icc = new_icc()) == NULL)
			error("Creation of ICC object failed");
	
		/* Read header etc. */
		if ((rv = dev_icc->read(dev_icc,dev_fp,0)) != 0)
			error("Reading profile '%s' failed: %d, %s",dev_name,rv,dev_icc->err);
	
		/* Check that the profile is appropriate */
		if (dev_icc->header->deviceClass != icSigInputClass
		 && dev_icc->header->deviceClass != icSigDisplayClass
		 && dev_icc->header->deviceClass != icSigOutputClass)
			error("Device Profile '%s' isn't a device profile",dev_name);

		ink.tlimit = -1.0;		/* No ink limit by default */
		ink.klimit = -1.0;

		/* Wrap with an expanded icc */
		if ((dev_xicc = new_xicc(dev_icc)) == NULL)
			error ("Creation of xicc failed");

		/* Use a heuristic to guess the ink limit */
		icxGetLimits(dev_xicc, &ink.tlimit, &ink.klimit);
		ink.tlimit += 0.05;		/* allow a slight margine */

		if (verb)
			printf("Estimated Total inklimit is %f%%, Black %f%% \n",100.0 * ink.tlimit,ink.klimit < 0.0 ? 100.0 : 100.0 * ink.klimit);

		/* Get a expanded color conversion object suitable for gamut */
		if ((dev_luo = dev_xicc->get_luobj(dev_xicc, ICX_CLIP_NEAREST, icmFwd,
		     dorel ? icRelativeColorimetric : icAbsoluteColorimetric,
		     icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
			error ("%d, %s",dev_xicc->errc, dev_xicc->err);
	
		/* Creat a gamut surface */
		if ((cb.dev_gam = dev_luo->get_gamut(dev_luo, GAMRES)) == NULL)
			error ("%d, %s",dev_xicc->errc, dev_xicc->err);

		dev_luo->del(dev_luo);
		dev_xicc->del(dev_xicc);
		dev_icc->del(dev_icc);
		dev_fp->del(dev_fp);
	} else {
		cb.dev_gam = NULL;
	}

	/* ======================= */
	/* Open up the existing abstract profile that is to be refined. */
	if (docreate == 0) {
		if ((rd_fp = new_icmFileStd_name(rd_name,"r")) == NULL)
			error ("Can't open file '%s'",rd_name);
	
		if ((rd_icc = new_icc()) == NULL)
			error ("Creation of ICC object failed");
	
		/* Read header etc. */
		if ((rv = rd_icc->read(rd_icc,rd_fp,0)) != 0)
			error ("%d, %s",rv,rd_icc->err);
	
		if (rd_icc->header->deviceClass != icSigAbstractClass)
			error("Input Profile '%s' isn't abstract type",rd_name);

		if ((cb.rd_luo = rd_icc->get_luobj(rd_icc, icmFwd,
		        dorel ? icRelativeColorimetric : icAbsoluteColorimetric,
		        icSigLabData, icmLuOrdNorm)) == NULL)
				error ("%d, %s",rd_icc->errc, rd_icc->err);
	} else {
		cb.rd_luo = NULL;
	}

	/* ======================= */
	/* Create refining rspl */
	{
		cow *rp;		/* rspl setup points */
		int npnts = 0;	/* Total number of test points */
		int gres[MXDI];	/* rspl grid resolution */
		double damp;
		datai mn, mx;

		if ((rp = (cow *)malloc(sizeof(cow) * cg[0].npat)) == NULL)
			error("Malloc failed - rp[]");
		
		/* Create mapping points */
		for (i = 0; i < cg[0].npat; i++) {
			double temp[3];
			double ccor[3], cmag;				/* Current correction vector */
			double ncor[3], nmag;				/* New correction vector */

			/* Input is target [0] */
			for (j = 0; j < 3; j++)
				rp[i].p[j] = cg[0].pat[i].v[j];

			/* Cull out of range points */
			if (rp[i].p[0] < 0.0 || rp[i].p[0] > 100.0
			 || rp[i].p[1] < -127.0 || rp[i].p[1] > 127.0
			 || rp[i].p[2] < -127.0 || rp[i].p[2] > 127.0) {
#ifdef DEBUG1
			printf("Ignoring %f %f %f\n",rp[i].p[0],rp[i].p[1],rp[i].p[2]);
#endif
				continue;
			}
			
#ifdef DEBUG1
			printf("%d: Target        %f %f %f\n",i,rp[i].p[0],rp[i].p[1],rp[i].p[2]);
#endif

			damp = cb.rd_luo != NULL ? damp2 : damp1;
			ccor[0] = ccor[1] = ccor[2] = 0.0;
			cmag = 0.0;

			/* Lookup the current correction applied to the target */
			if (cb.rd_luo != NULL) {		/* Subsequent pass */
				double corval[3];
				cb.rd_luo->lookup(cb.rd_luo, corval, cg[0].pat[i].v);
				icmSub3(ccor, corval, cg[0].pat[i].v);
				cmag = icmNorm3(ccor);
#ifdef DEBUG1
				printf("%d: ccor          %f %f %f, mag %f\n",i, ccor[0],ccor[1],ccor[2],cmag);
#endif
			}

			/* Create a trial 100% full correction point */
			for (j = 0; j < 3; j++)
				rp[i].v[j] = ccor[j] + 2.0 * cg[0].pat[i].v[j] - cg[1].pat[match[i]].v[j];

			/* If a first pass and the target or the correction are out of gamut, */
			/* use a damping factor of 1.0 */
			if (cb.rd_luo == NULL
			 && cb.dev_gam != NULL
			 && cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].p) > 1.0
			 && cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].v) > 1.0) {
				damp = 1.0;
			}

#ifdef DEBUG1
			printf("%d: damp =         %f\n",i, damp);
#endif

			/* Create a new correction that does a damped correction to the current error */
			/* [0] = target, [1] = measured */
			for (j = 0; j < 3; j++)
				ncor[j] = ccor[j] + damp * (cg[0].pat[i].v[j] - cg[1].pat[match[i]].v[j]);
			nmag = icmNorm3(ncor);

#ifdef DEBUG1
			printf("%d: ncor          %f %f %f, mag %f\n",i, ncor[0],ncor[1],ncor[2],nmag);
#endif

			/* If this is not the first pass, limit the new correction */
			/* to be 1 + damp as big as the previous correction */
			if (cb.rd_luo != NULL) {
				if ((nmag/cmag) > (1.0 + damp2)) {
#ifdef DEBUG1
					printf("%d: Limited cor mag from %f to %f\n",i, nmag, (1.0 + damp2) * cmag);
#endif
					icmScale3(ncor, ncor, (1.0 + damp2) * cmag/nmag);
				}
			}

			/* Create correction point */
			for (j = 0; j < 3; j++)
				rp[i].v[j] = cg[0].pat[i].v[j] + ncor[j];

			/* If the target point or corrected point is likely to be outside */
			/* the gamut, limit the magnitude of the correction to be the same */
			/* as the previous correction. */ 
			if (cb.rd_luo != NULL && cb.dev_gam != NULL) {
				if (cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].p) > 1.0
				 || cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].v) > 1.0) {
#ifdef DEBUG1
					printf("%d: Limited cor mag from %f to %f\n",i, nmag, cmag);
#endif
					icmScale3(ncor, ncor, cmag/nmag);
				}
				/* Create correction point again */
				for (j = 0; j < 3; j++)
					rp[i].v[j] = cg[0].pat[i].v[j] + ncor[j];
			}

#ifdef DEBUG1
			printf("%d: Was           %f %f %f\n",i, cg[1].pat[match[i]].v[0], cg[1].pat[match[i]].v[1], cg[1].pat[match[i]].v[2]);
			printf("%d: Correction to %f %f %f\n",i, rp[i].v[0], rp[i].v[1], rp[i].v[2]);
#endif

#ifdef COMPLOOKUP
			/* Remove current correction from new change */
			for (j = 0; j < 3; j++)
				rp[i].v[j] -= ccor[j];
#endif
			/* Set weighting */
			if (i == whitepatch)
				rp[i].w = WHITEWEIGHT;
			else
				rp[i].w = 1.0;
			npnts++;

#ifdef DEBUG3
			{
				char fname[50], tmp[50];
				FILE *lf;
				int mi = match[i];
				double tig, cig, rig;  
				double vv[3], temp[3];
				double del[3], delt;
				double corrdel[3], corrdelt;
				double pcval[3], pcorrdel[3], pcorrdelt;

				for (j = 0;; j++) {
					if (poi[j] == (i+1) || poi[j] < 0)
						break;
				}
				if (poi[j] < 0) {
					continue;
				}

#ifdef COMPLOOKUP
				/* Compute total correction point */
				for (j = 0; j < 3; j++)
					vv[j] = rp[i].v[j] + ccor[j];
#else
				for (j = 0; j < 3; j++)
					vv[j] = rp[i].v[j];
#endif
				sprintf(fname,"patch%04d.log",i+1);
				if ((lf = fopen(fname, "a")) == NULL)
					error("Unable to open debug3 log file '%s'\n",fname);

	 			cig = cb.dev_gam->nradial(cb.dev_gam, temp, cg[1].pat[mi].v) - 1.0;
				if (cig > 0.0)
					sprintf(tmp, " OUT %f",cig);
				else
					sprintf(tmp, "");
				fprintf(lf,"Currently  %f %f %f%s\n", cg[1].pat[mi].v[0], cg[1].pat[mi].v[1], cg[1].pat[mi].v[2], tmp);

	 			tig = cb.dev_gam->nradial(cb.dev_gam, temp, cg[0].pat[i].v) - 1.0;
				if (tig > 0.0)
					sprintf(tmp, " OUT %f",tig);
				else
					sprintf(tmp, "");
				fprintf(lf,"Target     %f %f %f%s\n", cg[0].pat[i].v[0], cg[0].pat[i].v[1], cg[0].pat[i].v[2], tmp);

				icmSub3(del, cg[1].pat[mi].v, cg[0].pat[i].v);
				delt = icmNorm3(del);
				fprintf(lf,"DE         %f %f %f (%f)\n", del[0], del[1], del[2], delt);
				
				rig = cb.dev_gam->nradial(cb.dev_gam, temp, vv) - 1.0;
				if (rig > 0.0)
					sprintf(tmp, " OUT %f",rig);
				else
					sprintf(tmp, "");
				fprintf(lf,"Correction %f %f %f%s\n", vv[0], vv[1], vv[2], tmp);
				icmSub3(corrdel, vv, cg[0].pat[i].v);
				corrdelt = icmNorm3(corrdel);
				fprintf(lf,"CorrDelta  %f %f %f (%f)\n", corrdel[0], corrdel[1], corrdel[2], corrdelt);
				/* Note the previous correction we're compunded with */
				if (cb.rd_luo != NULL) {
					cb.rd_luo->lookup(cb.rd_luo, pcval, cg[0].pat[i].v);
					icmSub3(pcorrdel, pcval, cg[0].pat[i].v);
					pcorrdelt = icmNorm3(pcorrdel);
					fprintf(lf,"PrevCorrDelta %f %f %f (%f)\n", pcorrdel[0], pcorrdel[1], pcorrdel[2], pcorrdelt);
				}
				fprintf(lf,"\n");

				fclose(lf);
			}
#endif /* DEBUG3 */
		}

		/* Create refining rspl */
		mn[0] =   0.0, mn[1] = mn[2] = -128.0;			/* Allow for 16 bit grid range */
		mx[0] = 100.0, mx[1] = mx[2] =  (65535.0 * 255.0)/65280.0 - 128.0;
		cb.verb = verb;
		if ((cb.r = new_rspl(RSPL_NOFLAGS, 3, 3)) == NULL)
			error("new_rspl failed");

		for (e = 0; e < 3; e++)
			gres[e] = clutres;
		for (e = 0; e < 3; e++)
			avgdev[e] = AVGDEV;

		cb.r->fit_rspl_w_df(cb.r,
		           RSPLFLAGS			/* Extra flags */
		           | verb ? RSPL_VERBOSE : 0,
		           rp,					/* Test points */
		           npnts,				/* Number of test points */
		           mn, mx, gres,		/* Low, high, resolution of grid */
		           NULL, NULL,			/* Default data scale */
		           smoothf,				/* Smoothing */
		           avgdev,				/* Average Deviation */
		           NULL,				/* Grid width */
                   wweight,				/* weak default function weight */
				   NULL,				/* No context */
		           wfunc				/* Weak function */
		);
		if (verb) printf("\n");

		/* Report how good the fit is */
		if (verb) {
			co tco;	/* Test point */
			double maxe = -1e6, avge = 0.0;

			for (i = 0; i < npnts; i++) {
				double de;

				icmAry2Ary(tco.p, rp[i].p);
				cb.r->interp(cb.r, &tco);

				de = icmLabDE(tco.v, rp[i].v);
				if (de > maxe)
					maxe = de;
				avge += de;
			}
			avge /= (double)npnts;
			printf("Refining transform has error to defining points avg: %f, max %f\n",avge,maxe);
		}
		free(rp);
	}

	/* ======================= */
	/* Create new abstract ICC profile */
	if ((wr_fp = new_icmFileStd_name(wr_name,"w")) == NULL)
		error ("Can't open file '%s' for writing",wr_name);

	if ((wr_icc = new_icc()) == NULL)
		error ("Creation of write ICC object failed");

	/* Add all the tags required */

	/* The header: */
	{
		icmHeader *wh = wr_icc->header;

		/* Values that must be set before writing */
		wh->deviceClass     = icSigAbstractClass;
    	wh->colorSpace      = icSigLabData;
    	wh->pcs             = icSigLabData;
		if (dorel)
	    	wh->renderingIntent = icRelativeColorimetric;	/* White point relative */
		else
	    	wh->renderingIntent = icAbsoluteColorimetric;	/* Instrument reading based */
	}
	/* Profile Description Tag: */
	{
		icmTextDescription *wo;
		char *dst = "Argyll refine output";
		if ((wo = (icmTextDescription *)wr_icc->add_tag(
		           wr_icc, icSigProfileDescriptionTag,	icSigTextDescriptionType)) == NULL) 
			error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);

		wo->size = strlen(dst)+1; 	/* Allocated and used size of desc, inc null */
		wo->allocate((icmBase *)wo);/* Allocate space */
		strcpy(wo->desc, dst);		/* Copy the string in */
	}
	/* Copyright Tag: */
	{
		icmText *wo;
		char *crt = "Copyright the user who created it";
		if ((wo = (icmText *)wr_icc->add_tag(
		           wr_icc, icSigCopyrightTag,	icSigTextType)) == NULL) 
			error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);

		wo->size = strlen(crt)+1; 	/* Allocated and used size of text, inc null */
		wo->allocate((icmBase *)wo);/* Allocate space */
		strcpy(wo->data, crt);		/* Copy the text in */
	}
	/* White Point Tag: */
	{
		icmXYZArray *wo;
		/* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
		if ((wo = (icmXYZArray *)wr_icc->add_tag(
		           wr_icc, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL) 
			error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);

		wo->size = 1;
		wo->allocate((icmBase *)wo);	/* Allocate space */
		wo->data[0] = icmD50;			/* So absolute/relative rendering is the same */
	}
	/* 16 bit pcs -> pcs lut: */
	{
		icmLut *wo;
		int flags = ICM_CLUT_SET_EXACT;	/* Assume we're setting from RSPL's */

		/* Intent 0 = default/perceptual */
		if ((wo = (icmLut *)wr_icc->add_tag(
		           wr_icc, icSigAToB0Tag,	icSigLut16Type)) == NULL) 
			error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);

		wo->inputChan = 3;
		wo->outputChan = 3;
    	wo->clutPoints = clutres;
    	wo->inputEnt = 256;				/* Not actually used */
    	wo->outputEnt = 256;
		wo->allocate((icmBase *)wo);/* Allocate space */

		/* The matrix is only applicable to XYZ input space, */
		/* so it is not used here. */

		/* Use helper function to do the hard work. */
		if (cb.verb) {
			int extra;
			for (cb.total = 1, i = 0; i < 3; i++, cb.total *= wo->clutPoints)
				; 
			/* Add in cell center points */
			for (extra = 1, i = 0; i < wo->inputChan; i++, extra *= (wo->clutPoints-1))
				;
			cb.total += extra;
			cb.count = 0;
			cb.last = -1;
			printf(" 0%%"), fflush(stdout);
		}

#ifdef COMPLOOKUP
		/* Compound with previous correction */
		if (cb.rd_luo != NULL)
			flags = ICM_CLUT_SET_APXLS;	/* Won't be least squares, so do extra sampling */
#endif

		if (wo->set_tables(wo,
				flags,
				&cb,
				icSigLabData, 			/* Input color space */
				icSigLabData, 			/* Output color space */
				NULL,					/* Linear input transform Lab->Lab' (NULL = default) */
				NULL, NULL,				/* Use default Maximum range of Lab' values */
				PCSp_PCSp,				/* Lab' -> Lab' transfer function */
				NULL, NULL,				/* Use default Maximum range of Lab' values */
				NULL					/* Linear output transform Lab'->Lab */
		) != 0)
			error("Setting 16 bit Lab->Lab Lut failed: %d, %s",wr_icc->errc,wr_icc->err);

		if (verb)
			printf("\n");
#ifdef WARN_CLUT_CLIPPING
		if (wr_icc->warnc)
			warning("Values clipped in setting abstract LUT");
#endif /* WARN_CLUT_CLIPPING */
		if (verb)
			printf("Done filling abstract table\n");
	}
	/* Write the file out */
	if ((rv = wr_icc->write(wr_icc,wr_fp,0)) != 0)
		error ("Write file: %d, %s",rv,wr_icc->err);
	
	/* ======================================= */
	
	/* Clean everything up */
	wr_icc->del(wr_icc);
	wr_fp->del(wr_fp);

	if (docreate == 0) {
		cb.rd_luo->del(cb.rd_luo);
		rd_icc->del(rd_icc);
		rd_fp->del(rd_fp);
	}

	if (nogamut == 0) {
		cb.dev_gam->del(cb.dev_gam);
	}

	cb.r->del(cb.r);

	free(match);
	free(cg[0].pat);
	free(cg[1].pat);

	return 0;
}
Exemplo n.º 6
0
int main(int argc, char *argv[])
{
	int i;
	int fa,nfa;				/* current argument we're looking at */
	int verb = 0;
	int limit = -1;
	static char tarname[200] = { 0 };		/* optional 928 patch reference file */
	static char inname[200] = { 0 };		/* Input .pat file base name */
	static char outname[200] = { 0 };		/* Output cgats .ti3 file base name */
	FILE *d928_fp = NULL;
	FILE *pat_fp;
	cgats *ocg;			/* output cgats structure */
	time_t clk = time(0);
	struct tm *tsp = localtime(&clk);
	char *atm = asctime(tsp); /* Ascii time */

	error_program = "kodak2ti3";

	if (argc <= 1)
		usage();

	/* 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 */
						}
					}
				}

			if (argv[fa][1] == '?')
				usage();

			else if (argv[fa][1] == 'l') {
				if (na == NULL) usage();
				fa = nfa;
				limit = atoi(na);
				if (limit < 1)
					limit = 1;
			}

			else if (argv[fa][1] == 'r') {
				if (na == NULL) usage();
				fa = nfa;
				strcpy(tarname, na);
			}

			else if (argv[fa][1] == 'v')
				verb = 1;
			else 
				usage();
			}
		else
			break;
		}

	/* Get the file name argument */
	if (fa >= argc || argv[fa][0] == '-') usage();

	strcpy(inname,argv[fa++]);
	strcat(inname,".pat");

	if (fa >= argc || argv[fa][0] == '-') usage();
	strcpy(outname, argv[fa++]);
	strcat(outname,".ti3");

	/* Open up the Test chart reference file if we were given one */
	if (tarname[0] != '\000') {
		if (verb)
			printf("Using alternate reference file '%s'\n",tarname);
		if ((d928_fp = open_928(tarname)) == NULL)
			error ("Read: Can't open file '%s'",tarname);
	}

	if ((pat_fp = open_pat(inname)) == NULL)
		error ("Read: Can't open file '%s'",inname);

	/* Setup output cgats file */
	ocg = new_cgats();	/* Create a CGATS structure */
	ocg->add_other(ocg, "CTI3"); 	/* our special type is Calibration Target Information 3 */
	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */

	ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
	atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
	ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);	/* What sort of device this is */

	/* Fields we want */
	ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);

	if (limit > 0) {
		char buf[100];
		sprintf(buf, "%d", limit);
		ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT", buf, NULL);
	}

	ocg->add_field(ocg, 0, "CMYK_C", r_t);
	ocg->add_field(ocg, 0, "CMYK_M", r_t);
	ocg->add_field(ocg, 0, "CMYK_Y", r_t);
	ocg->add_field(ocg, 0, "CMYK_K", r_t);
	ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_LAB", NULL);
	ocg->add_field(ocg, 0, "LAB_L", r_t);
	ocg->add_field(ocg, 0, "LAB_A", r_t);
	ocg->add_field(ocg, 0, "LAB_B", r_t);

	/* Write out the patch info to the output CGATS file */
	for (i = 0; i < NPAT; i++) {
		char id[100];
		double cmykv[4]; 
		double labv[3]; 

		if (next_928(d928_fp, i, cmykv) != 0)
			error("Error reading reference information from '%s' file",tarname);

		if (next_pat(pat_fp, labv) != 0)
			error("Error reading Kodak .pat file");

		sprintf(id, "%d", i+1);
		ocg->add_set(ocg, 0, id, 100.0 * cmykv[0], 100.0 * cmykv[1],
		                         100.0 * cmykv[2], 100.0 * cmykv[3],
		                         labv[0], labv[1], labv[2]);
	}

	{
		double wp[3];			/* Paper white XYZ */
		double D50wp[3] 		/* D50 white point Kodak uses */
		    = { 0.9642, 1.0000, 0.8249 };
		double tt[3];
		int li;

		/* Get offset of Lab values in cgats file */
		if ((li = ocg->find_field(ocg, 0, "LAB_L")) < 0)
			error("Internal - cgats doesn't field LAB_L");

		/* Get last line of pat file - this is the paper white in XYZ */
		if (next_pat(pat_fp, wp) != 0)
			error("Error reading Kodak .pat file");

//printf("~1 white point is XYZ %f %f %f\n",wp[0],wp[1],wp[2]);

		/* Run through all the data points, and adjust them back to the absolute */
		/* white point. */

		for (i = 0; i < NPAT; i++) {
			double in[3], out[3];
	
			tt[0] = *((double *)ocg->t[0].fdata[i][li+0]);
			tt[1] = *((double *)ocg->t[0].fdata[i][li+1]);
			tt[2] = *((double *)ocg->t[0].fdata[i][li+2]);

			icmLab2XYZ(&icmD50, in, tt);

			/* Undo Kodak's D50->paper white point adjustment */
			out[0] = in[0] * (D50wp[1] * wp[0])/(D50wp[0] * wp[1]);
			out[1] = in[1];		/* Y remains unchanged */
			out[2] = in[2] * (D50wp[1] * wp[2])/(D50wp[2] * wp[1]);

			icmXYZ2Lab(&icmD50, tt, out);

			*((double *)ocg->t[0].fdata[i][li+0]) = tt[0];
			*((double *)ocg->t[0].fdata[i][li+1]) = tt[1];
			*((double *)ocg->t[0].fdata[i][li+2]) = tt[2];
		}


	}

	if (ocg->write_name(ocg, outname))
		error("Write error : %s",ocg->err);

	ocg->del(ocg);		/* Clean up */

	if (d928_fp != NULL)
		close_928(d928_fp);
	close_pat(pat_fp);

	return 0;
}
Exemplo n.º 7
0
int
main(int argc, char *argv[]) {
	int fa,nfa;					/* argument we're looking at */
	char prof_name[MAXNAMEL+1] = { '\000' };	/* ICC profile name, "" if none */
	char in_name[MAXNAMEL+1];			/* TIFF input file */
	char *xl = NULL, out_name[MAXNAMEL+4+1] = "locus.ts";	/* locus output file */
	int verb = 0;
	int dovrml = 0;
	int doaxes = 1;
	int usevec = 0;
	double vec[3];
	int rv = 0;

	icc *icco = NULL;
	xicc *xicco = NULL;
	icxViewCond vc;				/* Viewing Condition for CIECAM */
	int vc_e = -1;				/* Enumerated viewing condition */
	int vc_s = -1;				/* Surround override */
	double vc_wXYZ[3] = {-1.0, -1.0, -1.0};	/* Adapted white override in XYZ */
	double vc_wxy[2] = {-1.0, -1.0};		/* Adapted white override in x,y */
	double vc_a = -1.0;			/* Adapted luminance */
	double vc_b = -1.0;			/* Background % overid */
	double vc_f = -1.0;			/* Flare % overid */
	double vc_fXYZ[3] = {-1.0, -1.0, -1.0};	/* Flare color override in XYZ */
	double vc_fxy[2] = {-1.0, -1.0};		/* Flare color override in x,y */
	icxLuBase *luo = NULL;					/* Generic lookup object */
	icColorSpaceSignature ins = icSigLabData, outs;	/* Type of input and output spaces */
	int inn, outn;						/* Number of components */
	icmLuAlgType alg;					/* Type of lookup algorithm */
	icmLookupFunc     func   = icmFwd;				/* Must be */
	icRenderingIntent intent = -1;					/* Default */
	icColorSpaceSignature pcsor = icSigLabData;		/* Default */
	icmLookupOrder    order  = icmLuOrdNorm;		/* Default */

	TIFF *rh = NULL;
	int x, y, width, height;					/* Size of image */
	uint16 samplesperpixel, bitspersample;
	uint16 pconfig, photometric, pmtc;
	uint16 resunits;
	float resx, resy;
	tdata_t *inbuf;
	void (*cvt)(double *out, double *in);		/* TIFF conversion function, NULL if none */
	icColorSpaceSignature tcs;					/* TIFF colorspace */
	uint16 extrasamples;						/* Extra "alpha" samples */
	uint16 *extrainfo;							/* Info about extra samples */
	int sign_mask;								/* Handling of encoding sign */

	int i, j;
	int nipoints = 0;					/* Number of raster sample points */ 
	co *inp = NULL;						/* Input point values */
	double tdel = 0.0;					/* Total delta along locus */
	rspl *rr = NULL;
	int nopoints = 0;					/* Number of raster sample points */ 
	co *outp = NULL;

	error_program = argv[0];

	if (argc < 2)
		usage();

	/* 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 */
					}
				}
			}

			if (argv[fa][1] == '?')
				usage();

			/* Verbosity */
			else if (argv[fa][1] == 'v') {
				verb = 1;
			}

			/* Intent */
			else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
				fa = nfa;
				if (na == NULL) usage();
    			switch (na[0]) {
					case 'd':
						intent = icmDefaultIntent;
						break;
					case 'a':
						intent = icAbsoluteColorimetric;
						break;
					case 'p':
						intent = icPerceptual;
						break;
					case 'r':
						intent = icRelativeColorimetric;
						break;
					case 's':
						intent = icSaturation;
						break;
					/* Argyll special intents to check spaces underlying */
					/* icxPerceptualAppearance & icxSaturationAppearance */
					case 'P':
						intent = icmAbsolutePerceptual;
						break;
					case 'S':
						intent = icmAbsoluteSaturation;
						break;
					default:
						usage();
				}
			}

			/* Search order */
			else if (argv[fa][1] == 'o') {
				fa = nfa;
				if (na == NULL) usage();
    			switch (na[0]) {
					case 'n':
					case 'N':
						order = icmLuOrdNorm;
						break;
					case 'r':
					case 'R':
						order = icmLuOrdRev;
						break;
					default:
						usage();
				}
			}

			/* PCS override */
			else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
				fa = nfa;
				if (na == NULL) usage();
    			switch (na[0]) {
					case 'l':
						pcsor = icSigLabData;
						break;
					case 'j':
						pcsor = icxSigJabData;
						break;
					default:
						usage();
				}
			}

			/* Viewing conditions */
			else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
				fa = nfa;
				if (na == NULL) usage();

				/* Switch to Jab automatically */
				pcsor = icxSigJabData;

				/* Set the viewing conditions */
				if (na[1] != ':') {
					if ((vc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
						usage();
				} else if (na[0] == 's' || na[0] == 'S') {
					if (na[1] != ':')
						usage();
					if (na[2] == 'a' || na[2] == 'A') {
						vc_s = vc_average;
					} else if (na[2] == 'm' || na[2] == 'M') {
						vc_s = vc_dim;
					} else if (na[2] == 'd' || na[2] == 'D') {
						vc_s = vc_dark;
					} else if (na[2] == 'c' || na[2] == 'C') {
						vc_s = vc_cut_sheet;
					} else
						usage();
				} else if (na[0] == 'w' || na[0] == 'W') {
					double x, y, z;
					if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
						vc_wXYZ[0] = x; vc_wXYZ[1] = y; vc_wXYZ[2] = z;
					} else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
						vc_wxy[0] = x; vc_wxy[1] = y;
					} else
						usage();
				} else if (na[0] == 'a' || na[0] == 'A') {
					if (na[1] != ':')
						usage();
					vc_a = atof(na+2);
				} else if (na[0] == 'b' || na[0] == 'B') {
					if (na[1] != ':')
						usage();
					vc_b = atof(na+2);
				} else if (na[0] == 'f' || na[0] == 'F') {
					double x, y, z;
					if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
						vc_fXYZ[0] = x; vc_fXYZ[1] = y; vc_fXYZ[2] = z;
					} else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
						vc_fxy[0] = x; vc_fxy[1] = y;
					} else if (sscanf(na+1,":%lf",&x) == 1) {
						vc_f = x;
					} else
						usage();
				} else
					usage();
			}

			/* VRML output */
			else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
				dovrml = 1;
			}
			/* No axis output */
			else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
				doaxes = 0;
			}
			/* Vector direction for span */
			else if (argv[fa][1] == 'V') {
				usevec = 1;
				if (na == NULL) usage();
				fa = nfa;
				if (sscanf(na, " %lf , %lf , %lf ",&vec[0], &vec[1], &vec[2]) != 3)
						usage();
			}
			/* Output file name */
			else if (argv[fa][1] == 'O') {
				fa = nfa;
				if (na == NULL) usage();
				strncpy(out_name,na,MAXNAMEL); out_name[MAXNAMEL] = '\000';
			}

			else 
				usage();
		} else
			break;
	}

	if (fa >= argc || argv[fa][0] == '-') usage();
	if (fa < (argc-1))
		strncpy(prof_name,argv[fa++],MAXNAMEL); prof_name[MAXNAMEL] = '\000';

	if (fa >= argc || argv[fa][0] == '-') usage();
	strncpy(in_name,argv[fa],MAXNAMEL); in_name[MAXNAMEL] = '\000';

	if ((xl = strrchr(out_name, '.')) == NULL)	/* Figure where extention is */
		xl = out_name + strlen(out_name);

	if (verb) {
		printf("Profile     = '%s'\n",prof_name);
		printf("Input TIFF  = '%s'\n",in_name);
		printf("Output file = '%s'\n",out_name);
	}

	if (intent == -1) {
		if (pcsor == icxSigJabData)
			intent = icRelativeColorimetric;	/* Default to icxAppearance */
		else
			intent = icAbsoluteColorimetric;	/* Default to icAbsoluteColorimetric */
	}

	/* - - - - - - - - - - - - - - - - */
	/* If we were provided an ICC profile to use */
	if (prof_name[0] != '\000') {

		/* Open up the profile or TIFF embedded profile for reading */
		if ((icco = read_embedded_icc(prof_name)) == NULL)
			error ("Can't open profile in file '%s'",prof_name);
	
		if (verb) {
			icmFile *op;
			if ((op = new_icmFileStd_fp(stdout)) == NULL)
				error ("Can't open stdout");
			icco->header->dump(icco->header, op, 1);
			op->del(op);
		}
	
		/* Check that the profile is appropriate */
		if (icco->header->deviceClass != icSigInputClass
		 && icco->header->deviceClass != icSigDisplayClass
		 && icco->header->deviceClass != icSigOutputClass
		 && icco->header->deviceClass != icSigColorSpaceClass)
			error("Profile type isn't device or colorspace");
	
		/* Wrap with an expanded icc */
		if ((xicco = new_xicc(icco)) == NULL)
			error ("Creation of xicc failed");
	
		/* Setup the default viewing conditions */
		if (xicc_enum_viewcond(xicco, &vc, -1, NULL, 0, NULL) == -999)
			error ("%d, %s",xicco->errc, xicco->err);
	
		if (vc_e != -1)
			if (xicc_enum_viewcond(xicco, &vc, vc_e, NULL, 0, NULL) == -999)
				error ("%d, %s",xicco->errc, xicco->err);
		if (vc_s >= 0)
			vc.Ev = vc_s;
		if (vc_wXYZ[1] > 0.0) {
			/* Normalise it to current media white */
			vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
			vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
		} 
		if (vc_wxy[0] >= 0.0) {
			double x = vc_wxy[0];
			double y = vc_wxy[1];	/* If Y == 1.0, then X+Y+Z = 1/y */
			double z = 1.0 - x - y;
			vc.Wxyz[0] = x/y * vc.Wxyz[1];
			vc.Wxyz[2] = z/y * vc.Wxyz[1];
		}
		if (vc_a >= 0.0)
			vc.La = vc_a;
		if (vc_b >= 0.0)
			vc.Yb = vc_b/100.0;
		if (vc_f >= 0.0)
			vc.Yf = vc_f/100.0;
		if (vc_fXYZ[1] > 0.0) {
			/* Normalise it to current media white */
			vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
			vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
		}
		if (vc_fxy[0] >= 0.0) {
			double x = vc_fxy[0];
			double y = vc_fxy[1];	/* If Y == 1.0, then X+Y+Z = 1/y */
			double z = 1.0 - x - y;
			vc.Fxyz[0] = x/y * vc.Fxyz[1];
			vc.Fxyz[2] = z/y * vc.Fxyz[1];
		}
	
		/* Get a expanded color conversion object */
		if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST
		           , func, intent, pcsor, order, &vc, NULL)) == NULL)
			error ("%d, %s",xicco->errc, xicco->err);
	
		luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL);
	
	}

	/* Establish the PCS range if we are filtering */
	{
		double pcsmin[3], pcsmax[3];		/* PCS range for filter stats array */
	
		if (luo) {
			gamut *csgam;

			if ((csgam = luo->get_gamut(luo, 20.0)) == NULL)
				error("Getting the gamut of the source colorspace failed");
			
			csgam->getrange(csgam, pcsmin, pcsmax);
			csgam->del(csgam);
		} else {
			pcsmin[0] = 0.0;
			pcsmax[0] = 100.0;
			pcsmin[1] = -128.0;
			pcsmax[1] = 128.0;
			pcsmin[2] = -128.0;
			pcsmax[2] = 128.0;
		}

		if (verb)
			printf("PCS range = %f..%f, %f..%f. %f..%f\n\n", pcsmin[0], pcsmax[0], pcsmin[1], pcsmax[1], pcsmin[2], pcsmax[2]);

		/* Allocate and initialize the filter */
		set_fminmax(pcsmin, pcsmax);
	}

	/* - - - - - - - - - - - - - - - */
	/* Open up input tiff file ready for reading */
	/* Got arguments, so setup to process the file */

	if ((rh = TIFFOpen(in_name, "r")) == NULL)
		error("error opening read file '%s'",in_name);

	TIFFGetField(rh, TIFFTAG_IMAGEWIDTH,  &width);
	TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);

	TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
	TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
	if (bitspersample != 8 && bitspersample != 16)
		error("TIFF Input file must be 8 bit/channel");

	TIFFGetFieldDefaulted(rh, TIFFTAG_EXTRASAMPLES, &extrasamples, &extrainfo);
	TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);

	if (inn != (samplesperpixel-extrasamples))
		error ("TIFF Input file has %d input chanels mismatched to colorspace '%s'",
		       samplesperpixel, icm2str(icmColorSpaceSignature, ins));

	if ((tcs = TiffPhotometric2ColorSpaceSignature(&cvt, &sign_mask, photometric,
	                                     bitspersample, samplesperpixel, extrasamples)) == 0)
		error("Can't handle TIFF file photometric %s", Photometric2str(photometric));

	if (tcs != ins) {
		if (luo != NULL)
			error("TIFF photometric '%s' doesn't match ICC input colorspace '%s' !",
			      Photometric2str(photometric), icm2str(icmColorSpaceSignature,ins));
		else
			error("No profile provided and TIFF photometric '%s' isn't Lab !",
			      Photometric2str(photometric));
	}

	TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
	if (pconfig != PLANARCONFIG_CONTIG)
		error ("TIFF Input file must be planar");

	TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
	TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
	TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);

	if (verb) {
		printf("Input TIFF file '%s'\n",in_name);
		printf("TIFF file colorspace is %s\n",icm2str(icmColorSpaceSignature,tcs));
		printf("TIFF file photometric is %s\n",Photometric2str(photometric));
		printf("\n");
	}

	/* - - - - - - - - - - - - - - - */
	/* Process colors to translate */
	/* (Should fix this to process a group of lines at a time ?) */

	nipoints = width * height;

//	if ((inp = malloc(sizeof(co) * nipoints)) == NULL)
//		error("Unable to allocate co array");

	inbuf  = _TIFFmalloc(TIFFScanlineSize(rh));

	for (i = y = 0; y < height; y++) {

		/* Read in the next line */
		if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
			error ("Failed to read TIFF line %d",y);

		/* Do floating point conversion */
		for (x = 0; x < width; x++) {
			int e;
			double in[MAX_CHAN], out[MAX_CHAN];
			
			if (bitspersample == 8) {
				for (e = 0; e < samplesperpixel; e++) {
					int v = ((unsigned char *)inbuf)[x * samplesperpixel + e];
					if (sign_mask & (1 << i))		/* Treat input as signed */
						v = (v & 0x80) ? v - 0x80 : v + 0x80;
					in[e] = v/255.0;
				}
			} else {
				for (e = 0; e < samplesperpixel; e++) {
					int v = ((unsigned short *)inbuf)[x * samplesperpixel + e];
					if (sign_mask & (1 << i))		/* Treat input as signed */
						v = (v & 0x8000) ? v - 0x8000 : v + 0x8000;
					in[e] = v/65535.0;
				}
			}
			if (cvt != NULL) {	/* Undo TIFF encoding */
				cvt(in, in);
			}
			if (luo != NULL) {
				if ((rv = luo->lookup(luo, out, in)) > 1)
					error ("%d, %s",icco->errc,icco->err);
				
				if (outs == icSigXYZData)	/* Convert to Lab */
					icmXYZ2Lab(&icco->header->illuminant, out, out);
			} else {
				for (e = 0; e < samplesperpixel; e++)
					out[e] = in[e];
			}

//printf("~1 %f %f %f -> %f %f %f\n", in[0], in[1], in[2], out[0], out[1], out[2]);

			add_fpixel(out);

#ifdef NEVER
	 		/* Store PCS value in array */
			inp[i].v[0] = out[0];
			inp[i].v[1] = out[1];
			inp[i].v[2] = out[2];
			i++;
#endif
		}
	}

	_TIFFfree(inbuf);

	TIFFClose(rh);		/* Close Input file */

	/* Done with lookup object */
	if (luo != NULL) {
		luo->del(luo);
		xicco->del(xicco);		/* Expansion wrapper */
		icco->del(icco);		/* Icc */
	}


	nipoints = flush_filter(verb, 80.0);

	if ((inp = malloc(sizeof(co) * nipoints)) == NULL)
		error("Unable to allocate co array");

	get_filter(inp);

printf("~1 There are %d points\n",nipoints);
//for (i = 0; i < nipoints; i++)
//printf("~1 point %d = %f %f %f\n", i, inp[i].v[0], inp[i].v[1], inp[i].v[2]);

	del_filter();

	/* Create the locus */
	{
		double s0[3], s1[3];
		double t0[3], t1[3];
		double mm[3][4];
		double im[3][4];
		int gres[MXDI] = { 256 } ;

		if (usevec) {
			double max = -1e6; 
			double min = 1e6; 
			double dist;
					
			icmScale3(vec, vec, 1.0/icmNorm3(vec));

			/* Locate the two furthest distant points measured along the vector */
			for (i = 0; i < nipoints; i++) {
				double tt;
				tt = icmDot3(vec, inp[i].v);
				if (tt > max) {
					max = tt;
					icmAry2Ary(s1, inp[i].v);
				}
				if (tt < min) {
					min = tt;
					icmAry2Ary(s0, inp[i].v);
				}
			}
			dist = icmNorm33sq(s0, s1);

printf("~1 most distant in vector %f %f %f = %f %f %f -> %f %f %f dist %f\n",
vec[0], vec[1], vec[2], s0[0], s0[1], s0[2], s1[0], s1[1], s1[2], sqrt(dist));

			t0[0] = 0.0;
			t0[1] = 0.0;
			t0[2] = 0.0;
			t1[0] = sqrt(dist);
			t1[1] = 0.0;
			t1[2] = 0.0;

		} else {
			double dist = 0.0;

			/* Locate the two furthest distant points (brute force) */
			for (i = 0; i < (nipoints-1); i++) {
				for (j = i+1; j < nipoints; j++) {
					double tt;
					if ((tt = icmNorm33sq(inp[i].v, inp[j].v)) > dist) {
						dist = tt;
						icmAry2Ary(s0, inp[i].v);
						icmAry2Ary(s1, inp[j].v);
					}
				}
			}
printf("~1 most distant = %f %f %f -> %f %f %f dist %f\n",
s0[0], s0[1], s0[2], s1[0], s1[1], s1[2], sqrt(dist));

			t0[0] = 0.0;
			t0[1] = 0.0;
			t0[2] = 0.0;
			t1[0] = sqrt(dist);
			t1[1] = 0.0;
			t1[2] = 0.0;
		}

		/* Transform our direction vector to the L* axis, and create inverse too */
		icmVecRotMat(mm, s1, s0, t1, t0);
		icmVecRotMat(im, t1, t0, s1, s0);

		/* Setup for rspl to create smoothed locus */
		for (i = 0; i < nipoints; i++) {
			icmMul3By3x4(inp[i].v, mm, inp[i].v);
			inp[i].p[0] = inp[i].v[0];
			inp[i].v[0] = inp[i].v[1];
			inp[i].v[1] = inp[i].v[2];
//printf("~1 point %d = %f -> %f %f\n", i, inp[i].p[0], inp[i].v[0], inp[i].v[1]);
		}

		/* Create rspl */
		if ((rr = new_rspl(RSPL_NOFLAGS, 1, 2)) == NULL)
			error("Creating rspl failed");

		rr->fit_rspl(rr, RSPL_NOFLAGS,inp, nipoints, NULL, NULL, gres, NULL, NULL, 5.0, NULL, NULL);       
#ifdef DEBUG_PLOT
		{
#define	XRES 100
			double xx[XRES];
			double y1[XRES];
			double y2[XRES];

			for (i = 0; i < XRES; i++) {
				co pp;
				double x;
				x = i/(double)(XRES-1);
				xx[i] = x * (t1[0] - t0[0]);
				pp.p[0] = xx[i];
				rr->interp(rr, &pp);
				y1[i] = pp.v[0];
				y2[i] = pp.v[1];
			}
			do_plot(xx,y1,y2,NULL,XRES);
		}
#endif /* DEBUG_PLOT */

		free(inp);

		nopoints = t1[0] / DE_SPACE;
		if (nopoints < 2)
			nopoints = 2;

		/* Create the output points */
		if ((outp = malloc(sizeof(co) * nopoints)) == NULL)
			error("Unable to allocate co array");

		/* Setup initial division of locus */
		for (i = 0; i < nopoints; i++) {
			double xx;

			xx = i/(double)(nopoints-1);
			xx *= (t1[0] - t0[0]);
			
			outp[i].p[0] = xx;
//printf("~1 div %d = %f\n",i,outp[i].p[0]);
		}
		for (i = 0; i < (nopoints-1); i++) {
			outp[i].p[1] = outp[i+1].p[0] - outp[i].p[0];
//printf("~1 del div  %d = %f\n",i,outp[i].p[1]);
		}

		/* Itterate until the delta between samples is even */
		for (j = 0; j < 10; j++) {
			double alen, minl, maxl;
			double tdiv;
			
			alen = 0.0;
			minl = 1e38;
			maxl = -1.0;
			for (i = 0; i < nopoints; i++) {
				rr->interp(rr, &outp[i]);
				outp[i].v[2] = outp[i].v[1];
				outp[i].v[1] = outp[i].v[0];
				outp[i].v[0] = outp[i].p[0];
				icmMul3By3x4(outp[i].v, im, outp[i].v);

//printf("~1 locus pnt %d = %f %f %f\n", i,outp[i].v[0],outp[i].v[1],outp[i].v[1]);

				if (i > 0) {
					double tt[3], len;
					icmSub3(tt, outp[i].v, outp[i-1].v);
					len = icmNorm3(tt);
					outp[i-1].p[2] = len;
					if (len > maxl)
						maxl = len;
					if (len < minl)
						minl = len;
					alen += len;
				}
			}
			alen /= (nopoints-1.0);
printf("~1 itter %d, alen = %f, minl = %f, maxl = %f\n",j,alen,minl,maxl);

			/* Adjust spacing */
			tdiv = 0.0;
			for (i = 0; i < (nopoints-1); i++) {
				outp[i].p[1] *= pow(alen/outp[i].p[2], 1.0);
				tdiv += outp[i].p[1];
			}
//printf("~1 tdiv = %f\n",tdiv);
			for (i = 0; i < (nopoints-1); i++) {
				outp[i].p[1] *= (t1[0] - t0[0])/tdiv;
//printf("~1 del div %d = %f\n",i,outp[i].p[1]);
			}
			tdiv = 0.0;
			for (i = 0; i < (nopoints-1); i++) {
				tdiv += outp[i].p[1];
			}
//printf("~1 tdiv now = %f\n",tdiv);
			for (i = 1; i < nopoints; i++) {
				outp[i].p[0] = outp[i-1].p[0] + outp[i-1].p[1];
//printf("~1 div %d = %f\n",i,outp[i].p[0]);
			}
		}

		/* Write the CGATS file */
		{
			time_t clk = time(0);
			struct tm *tsp = localtime(&clk);
			char *atm = asctime(tsp); /* Ascii time */
			cgats *pp;

			pp = new_cgats();	/* Create a CGATS structure */
			pp->add_other(pp, "TS"); 	/* Test Set */

			pp->add_table(pp, tt_other, 0);	/* Add the first table for target points */
			pp->add_kword(pp, 0, "DESCRIPTOR", "Argyll Test Point set",NULL);
			pp->add_kword(pp, 0, "ORIGINATOR", "Argyll tiffgmts", NULL);
			atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
			pp->add_kword(pp, 0, "CREATED",atm, NULL);

			pp->add_field(pp, 0, "SAMPLE_ID", cs_t);
			pp->add_field(pp, 0, "LAB_L", r_t);
			pp->add_field(pp, 0, "LAB_A", r_t);
			pp->add_field(pp, 0, "LAB_B", r_t);

			for (i = 0; i < nopoints; i++) {
				char buf[100];
				cgats_set_elem ary[1 + 3];

				sprintf(buf,"%d",i+1);
				ary[0].c = buf;
				ary[1 + 0].d = outp[i].v[0];
				ary[1 + 1].d = outp[i].v[1];
				ary[1 + 2].d = outp[i].v[2];
		
				pp->add_setarr(pp, 0, ary);
			}

			if (pp->write_name(pp, out_name))
			    error("Write error : %s",pp->err);
		}

		/* Create the VRML file */
		if (dovrml) {
			vrml *vv;
			
			strcpy(xl,".wrl");
			printf("Output vrml file '%s'\n",out_name);
			if ((vv = new_vrml(out_name, doaxes)) == NULL)
				error ("Creating VRML object failed");

#ifdef NEVER
			vv->start_line_set(vv);
			for (i = 0; i < nopoints; i++) {
				vv->add_vertex(vv, outp[i].v);
			}
			vv->make_lines(vv, nopoints);
#else
			for (i = 1; i < nopoints; i++) {
				vv->add_cone(vv, outp[i-1].v, outp[i].v, NULL, 0.5);
			}
#endif

			vv->del(vv);
		}
		free(outp);
	}

	rr->del(rr);

	return 0;
}
Exemplo n.º 8
0
int
main(
	int argc,
	char *argv[]
) {
	int fa,nfa;				/* argument we're looking at */
	int verb = 0;
	int chan = 0;			/* Chosen channel to plot against */
	char in_name[100];

	char *buf, *outc;
	int ti;
	cgats *cgf = NULL;			/* cgats file data */
	int isLab = 0;				/* cgats output is Lab, else XYZ */
	char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
	char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
	int npat;					/* Number of patches */ 
	inkmask nmask;				/* Device inkmask */
	int nchan;					/* Number of input chanels */
	char *bident;				/* Base ident */
	int chix[ICX_MXINKS];	/* Device chanel indexes */
	int pcsix[3];	/* Device chanel indexes */
	pval *pat;					/* patch values */
	int i, j;
	
	error_program = argv[0];

	if (argc < 2)
		usage();

	/* 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 */
					}
				}
			}

			/* Verbosity */
			if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
				verb = 1;
			}

			else if (argv[fa][1] >= '0' && argv[fa][1] <= '9') {
				chan = argv[fa][1] - '0';
			}
			else if (argv[fa][1] == '?')
				usage();
			else 
				usage();
		}
		else
			break;
	}

	if (fa >= argc || argv[fa][0] == '-') usage();
	strcpy(in_name,argv[fa]);

	/* Open CIE target values */
	cgf = new_cgats();			/* Create a CGATS structure */
	cgf->add_other(cgf, "CTI3");/* our special input type is Calibration Target Information 3 */
	if (cgf->read_name(cgf, in_name))
		error("CGATS file read error %s on file '%s'",cgf->err, in_name);

	if (cgf->ntables == 0 || cgf->t[0].tt != tt_other || cgf->t[0].oi != 0)
		error ("Profile file '%s' isn't a CTI3 format file",in_name);

	if (cgf->ntables < 1)
		error ("Input file '%s' doesn't contain at least one table",in_name);

	if ((ti = cgf->find_kword(cgf, 0, "COLOR_REP")) < 0)
		error("Input file doesn't contain keyword COLOR_REPS");
	
	if ((buf = strdup(cgf->t[0].kdata[ti])) == NULL)
		error("Malloc failed");
	
	/* Split COLOR_REP into device and PCS space */
	if ((outc = strchr(buf, '_')) == NULL)
		error("COLOR_REP '%s' invalid", cgf->t[0].kdata[ti]);
	*outc++ = '\000';
	
	if (strcmp(outc, "XYZ") == 0) {
		isLab = 0;
	} else if (strcmp(outc, "LAB") == 0) {
		isLab = 1;
	} else
		error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", cgf->t[0].kdata[ti]);

	if ((nmask = icx_char2inkmask(buf)) == 0) {
		error ("File '%s' keyword COLOR_REPS has unknown device value '%s'",in_name,buf);
	}

	free(buf);

	nchan = icx_noofinks(nmask);
	bident = icx_inkmask2char(nmask, 0);		/* Base ident (No possible 'i') */ 

	/* Find device fields */
	for (j = 0; j < nchan; j++) {
		int ii, imask;
		char fname[100];

		imask = icx_index2ink(nmask, j);
		sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
		                      icx_ink2char(imask));

		if ((ii = cgf->find_field(cgf, 0, fname)) < 0)
			error ("Input file doesn't contain field %s",fname);
		if (cgf->t[0].ftype[ii] != r_t)
			error ("Field %s is wrong type",fname);
		chix[j] = ii;
	}

	/* Find PCS fields */
	for (j = 0; j < 3; j++) {
		int ii;

		if ((ii = cgf->find_field(cgf, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
			error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
		if (cgf->t[0].ftype[ii] != r_t)
			error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
		pcsix[j] = ii;
	}

	npat = cgf->t[0].nsets;		/* Number of patches */

	if (npat <= 0)
		error("No sets of data in file '%s'",in_name);

	/* Allocate arrays to hold test patch input and output values */
	if ((pat = (pval *)malloc(sizeof(pval) * npat)) == NULL)
		error("Malloc failed - pat[]");

	/* Grab all the values */
	for (i = 0; i < npat; i++) {
		pat[i].v[0] = *((double *)cgf->t[0].fdata[i][pcsix[0]]);
		pat[i].v[1] = *((double *)cgf->t[0].fdata[i][pcsix[1]]);
		pat[i].v[2] = *((double *)cgf->t[0].fdata[i][pcsix[2]]);
		if (!isLab) {
			pat[i].v[0] /= 100.0;		/* Normalise XYZ to range 0.0 - 1.0 */
			pat[i].v[1] /= 100.0;
			pat[i].v[2] /= 100.0;
		}
		if (!isLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
			icmXYZ2Lab(&icmD50, pat[i].v, pat[i].v);
		}
		for (j = 0; j < nchan; j++) {
			pat[i].d[j] = *((double *)cgf->t[0].fdata[i][chix[j]]);
		}
	}

	/* Sort by the selected channel */
#define HEAP_COMPARE(A,B) (A.d[chan] < B.d[chan])
	HEAPSORT(pval, pat, npat);
#undef HEAP_COMPARE

	/* Create the plot */
	{
		int i;
		double *xx;
		double *y0;
		double *y1;
		double *y2;

		if ((xx = (double *)malloc(sizeof(double) * npat)) == NULL)
			error("Malloc failed - xx[]");
		if ((y0 = (double *)malloc(sizeof(double) * npat)) == NULL)
			error("Malloc failed - y0[]");
		if ((y1 = (double *)malloc(sizeof(double) * npat)) == NULL)
			error("Malloc failed - y1[]");
		if ((y2 = (double *)malloc(sizeof(double) * npat)) == NULL)
			error("Malloc failed - y2[]");
		
		for (i = 0; i < npat; i++) {
			xx[i] = pat[i].d[chan];
			y0[i] = pat[i].v[0];
			y1[i] = 50 + pat[i].v[1]/2.0;
			y2[i] = 50 + pat[i].v[2]/2.0;

//			printf("~1 %d: xx = %f, y = %f %f %f\n",i,xx[i],y0[i],y1[i],y2[i]);
		}
		do_plot6(xx,y0,y1,NULL,NULL,y2,NULL,npat);

		free(y2);
		free(y1);
		free(y0);
		free(xx);
	}

	free(pat);
	cgf->del(cgf);

	return 0;
}
Exemplo n.º 9
0
int main(int argc, char *argv[])
{
	int i;
	int fa,nfa;				/* current argument we're looking at */
	int verb = 0;
	static char tarname[200] = { 0 };		/* Input .CMY file */
	static char inname[200] = { 0 };		/* Input .nCIE file */
	static char outname[200] = { 0 };		/* Output cgats .ti3 file base name */
	cgats *cmy;			/* Input RGB reference file */
	int f_id1, f_c, f_m, f_y;	/* Field indexes */
	cgats *ncie;		/* Inpit CIE readings file */
	int f_id2, f_xx, f_yy, f_zz;	/* Field indexes */
	cgats *ocg;			/* output cgats structure */
	time_t clk = time(0);
	struct tm *tsp = localtime(&clk);
	char *atm = asctime(tsp); /* Ascii time */
	int npat = 0;		/* Number of patches */

	if (argc <= 1)
		usage();

	/* 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 */
						}
					}
				}

			if (argv[fa][1] == '?')
				usage();

			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
				verb = 1;
			else 
				usage();
			}
		else
			break;
		}

	/* Get the file name argument */
	if (fa >= argc || argv[fa][0] == '-') usage();

	strcpy(inname,argv[fa]);
	strcpy(tarname,argv[fa++]);
	strcat(inname,".CMY");
	strcat(tarname,".nCIE");

	if (fa >= argc || argv[fa][0] == '-') usage();
	strcpy(outname, argv[fa++]);
	strcat(outname,".ti3");

	/* Open up the Input CMY reference file */
	cmy = new_cgats();	/* Create a CGATS structure */
	cmy->add_other(cmy, "CBTA"); 	/* Colorblind Target file */
	if (cmy->read_name(cmy, inname))
		error ("Read: Can't open file '%s'",inname);
	if (cmy->ntables == 0 || cmy->t[0].tt != tt_other || cmy->t[0].oi != 0)
		error ("Input file isn't a 'CBTA' format file");
	if (cmy->ntables != 1)
		fprintf(stderr,"Input file '%s' doesn't contain exactly one table",inname);

	if ((npat = cmy->t[0].nsets) <= 0)
		error("No patches");

	if ((f_id1 = cmy->find_field(cmy, 0, "SAMPLE_ID")) < 0)
		error("Input file doesn't contain field SAMPLE_ID");
	if (cmy->t[0].ftype[f_id1] != nqcs_t)
		error("Field SAMPLE_ID is wrong type");

	if ((f_c = cmy->find_field(cmy, 0, "C")) < 0)
		error("Input file doesn't contain field C");
	if (cmy->t[0].ftype[f_c] != r_t)
		error("Field C is wrong type");

	if ((f_m = cmy->find_field(cmy, 0, "M")) < 0)
		error("Input file doesn't contain field M");
	if (cmy->t[0].ftype[f_m] != r_t)
		error("Field M is wrong type");

	if ((f_y = cmy->find_field(cmy, 0, "Y")) < 0)
		error("Input file doesn't contain field Y");
	if (cmy->t[0].ftype[f_y] != r_t)
		error("Field Y is wrong type");

	/* Open up the input nCIE device data file */
	ncie = new_cgats();	/* Create a CGATS structure */
	ncie->add_other(ncie, "CBPR"); 	/* Colorblind Printer Response file */
	if (ncie->read_name(ncie, tarname))
		error ("Read: Can't open file '%s'",tarname);
	if (ncie->ntables == 0 || ncie->t[0].tt != tt_other || ncie->t[0].oi != 0)
		error ("Input file isn't a 'CBTA' format file");
	if (ncie->ntables != 1)
		fprintf(stderr,"Input file '%s' doesn't contain exactly one table",tarname);

	if (npat != ncie->t[0].nsets)
		error("Number of patches doesn't match");

	if ((f_id2 = ncie->find_field(ncie, 0, "SAMPLE_ID")) < 0)
		error("Input file doesn't contain field SAMPLE_ID");
	if (ncie->t[0].ftype[f_id2] != nqcs_t)
		error("Field SAMPLE_ID is wrong type");

	if ((f_xx = ncie->find_field(ncie, 0, "XYZ_X")) < 0)
		error("Input file doesn't contain field XYZ_X");
	if (ncie->t[0].ftype[f_xx] != r_t)
		error("Field XYZ_X is wrong type");

	if ((f_yy = ncie->find_field(ncie, 0, "XYZ_Y")) < 0)
		error("Input file doesn't contain field XYZ_Y");
	if (ncie->t[0].ftype[f_yy] != r_t)
		error("Field XYZ_Y is wrong type");

	if ((f_zz = ncie->find_field(ncie, 0, "XYZ_Z")) < 0)
		error("Input file doesn't contain field XYZ_Z");
	if (ncie->t[0].ftype[f_zz] != r_t)
		error("Field XYZ_Z is wrong type");

	/* Setup output cgats file */
	ocg = new_cgats();	/* Create a CGATS structure */
	ocg->add_other(ocg, "CTI3"); 	/* our special type is Calibration Target Information 3 */
	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */

	ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
	atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
	ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);	/* What sort of device this is */

	/* Fields we want */
	ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);

	ocg->add_field(ocg, 0, "RGB_R", r_t);
	ocg->add_field(ocg, 0, "RGB_G", r_t);
	ocg->add_field(ocg, 0, "RGB_B", r_t);
	ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
	ocg->add_field(ocg, 0, "XYZ_X", r_t);
	ocg->add_field(ocg, 0, "XYZ_Y", r_t);
	ocg->add_field(ocg, 0, "XYZ_Z", r_t);

	/* Write out the patch info to the output CGATS file */
	for (i = 0; i < npat; i++) {
		char id[100];
		double rgb[3]; 
		double xyz[3]; 

		if (strcmp(((char *)cmy->t[0].fdata[i][f_id1]), 
		           ((char *)ncie->t[0].fdata[i][f_id2])) != 0) {
			error("Patch label mismatch, patch %d, '%s' != '%s'\n",
			       i, ((char *)cmy->t[0].fdata[i][f_id1]), 
		              ((char *)ncie->t[0].fdata[i][f_id2]));
		}

		rgb[0] = 100.0 - *((double *)cmy->t[0].fdata[i][f_c]);	/* Convert to RGB */
		rgb[1] = 100.0 - *((double *)cmy->t[0].fdata[i][f_m]);
		rgb[2] = 100.0 - *((double *)cmy->t[0].fdata[i][f_y]);

		xyz[0] = *((double *)ncie->t[0].fdata[i][f_xx]);	
		xyz[1] = *((double *)ncie->t[0].fdata[i][f_yy]);
		xyz[2] = *((double *)ncie->t[0].fdata[i][f_zz]);

		sprintf(id, "%d", i+1);
		ocg->add_set(ocg, 0, id, rgb[0], rgb[1], rgb[2], 
		                         xyz[0], xyz[1], xyz[2]);
	}

	if (ocg->write_name(ocg, outname))
		error("Write error : %s",ocg->err);

	ncie->del(ncie);		/* Clean up */
	cmy->del(cmy);
	ocg->del(ocg);

	return 0;
}
Exemplo n.º 10
0
int
main(int argc, char *argv[]) {
	int fa, nfa, mfa;		/* argument we're looking at */
	int n, ng = 0;			/* Current allocation, number of input gamuts */
	gamdisp *gds;			/* Definition of each gamut */
	int doaxes = 1;
	int docusps = 0;
	int isect = 0;
	FILE *wrl;
	char out_name[MAXNAMEL+1];
	char iout_name[MAXNAMEL+1] = "\000";;
	if (argc < 3)
		usage("Too few arguments, got %d expect at least 2",argc-1);

	mfa = 1;		/* Minimum final arguments */

	if ((gds = (gamdisp *)malloc((ng+1) * sizeof(gamdisp))) == NULL)
		error("Malloc failed on gamdisp");
	set_default(gds, 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+mfa) < argc) {
					if (argv[fa+1][0] != '-') {
						nfa = fa + 1;
						na = argv[nfa];		/* next is seperate non-flag argument */
					}
				}
			}

			if (argv[fa][1] == '?')
				usage("Usage requested");

			/* Color */
			else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
				fa = nfa;
				if (na == NULL) usage("Expect argument after flag -c");
    			switch (na[0]) {
					case 'r':
					case 'R':
						gds[ng].in_colors = gam_red;
						break;
					case 'g':
					case 'G':
						gds[ng].in_colors = gam_green;
						break;
					case 'b':
					case 'B':
						gds[ng].in_colors = gam_blue;
						break;
					case 'c':
					case 'C':
						gds[ng].in_colors = gam_cyan;
						break;
					case 'm':
					case 'M':
						gds[ng].in_colors = gam_magenta;
						break;
					case 'y':
					case 'Y':
						gds[ng].in_colors = gam_yellow;
						break;
					case 'e':
					case 'E':
						gds[ng].in_colors = gam_grey;
						break;
					case 'w':
					case 'W':
						gds[ng].in_colors = gam_white;
						break;
					case 'n':
					case 'N':
						gds[ng].in_colors = gam_natural;
						break;
					default:
						usage("Unknown argument after flag -c '%c'",na[0]);
				}
			}

			/* Transparency */
			else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
				double v;
				fa = nfa;
				if (na == NULL) usage("Expect argument after flag -t");
				v = atof(na);
				if (v < 0.0)
					v = 0.0;
				else if (v > 1.0)
					v = 1.0;
				gds[ng].in_trans = v;
			}

			/* Solid output */
			else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
				gds[ng].in_rep = gam_solid;
			}

			/* Wireframe output */
			else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
				gds[ng].in_rep = gam_wire;
			}

			/* No axis output */
			else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
				doaxes = 0;
			}

			/* Add cusp markers */
			else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
				docusps = 1;
			}

			/* Print intersecting volume */
			else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
				isect = 1;

				/* There is an intersection output gamut file */
				if (argv[fa][1] == 'I' && na != NULL) {
					fa = nfa;
					strncpy(iout_name, na, MAXNAMEL); iout_name[MAXNAMEL] = '\000';
				}
			}

			else 
				usage("Unknown flag '%c'",argv[fa][1]);

		} else if (argv[fa][0] != '\000') { /* Got a non-flag */
			strncpy(gds[ng].in_name,argv[fa],MAXNAMEL); gds[ng].in_name[MAXNAMEL] = '\000';

			ng++;
			if ((gds = (gamdisp *)realloc(gds, (ng+1) * sizeof(gamdisp))) == NULL)
				error("Realloc failed on gamdisp");
			set_default(gds, ng);
		} else {
			break;
		}
	}

	/* The last "gamut" is actually the output VRML filename, */
	/* so unwind it. */

	if (ng < 2)
		usage("Not enough arguments to specify output VRML files");

	strncpy(out_name,gds[--ng].in_name,MAXNAMEL); out_name[MAXNAMEL] = '\000';

#ifdef DEBUG
	for (n = 0; n < ng; n++) {
		printf("Input file %d is '%s'\n",n,gds[n].in_name);
		printf("Input file %d has color %d\n",n,gds[n].in_colors);
		printf("Input file %d has rep %d\n",n,gds[n].in_rep);
		printf("Input file %d has trans %f\n",n,gds[n].in_trans);
		
	}
	printf("Output file is '%s'\n",out_name);
#endif	/* DEBUG */

	/* Open up the output file */
	if ((wrl = fopen(out_name,"w")) == NULL)
		error("Error opening output file '%s'\n",out_name);
	
	/* Write the header info */

	fprintf(wrl,"#VRML V2.0 utf8\n");
	fprintf(wrl,"\n");
	fprintf(wrl,"# Created by the Argyll CMS\n");
	fprintf(wrl,"Transform {\n");
  	fprintf(wrl,"  children [\n");
    fprintf(wrl,"    NavigationInfo {\n");
	fprintf(wrl,"      type \"EXAMINE\"        # It's an object we examine\n");
	fprintf(wrl,"    } # We'll add our own light\n");
	fprintf(wrl,"\n");
#ifdef NEVER
	fprintf(wrl,"    DirectionalLight {\n");
	fprintf(wrl,"      direction 0 0 -1      # Light illuminating the scene\n");
	fprintf(wrl,"      direction 0 -1 0      # Light illuminating the scene\n");
	fprintf(wrl,"    }\n");
#else
	fprintf(wrl,"    DirectionalLight {\n");
	fprintf(wrl,"        intensity 0.2\n");
	fprintf(wrl,"        ambientIntensity 0.1\n");
	fprintf(wrl,"        direction -1 -1 -1\n");
	fprintf(wrl,"    }\n");
	fprintf(wrl,"    DirectionalLight {\n");
	fprintf(wrl,"        intensity 0.6\n");
	fprintf(wrl,"        ambientIntensity 0.2\n");
	fprintf(wrl,"        direction 1 1 1\n");
	fprintf(wrl,"    }\n");
#endif
	fprintf(wrl,"\n");
	fprintf(wrl,"    Viewpoint {\n");
	fprintf(wrl,"      position 0 0 340      # Position we view from\n");
	fprintf(wrl,"    }\n");
	fprintf(wrl,"\n");
	if (doaxes) {
		/* Define the axis boxes */
		struct {
			double x, y, z;			/* Box center */
			double wx, wy, wz;		/* Box size */
			double r, g, b;			/* Box color */
		} axes[5] = {
			{ 0, 0,   50-GCENT, 2, 2, 100, .7, .7, .7 },	/* L axis */
			{ 50, 0,  0-GCENT,  100, 2, 2,  1,  0,  0 },	/* +a (red) axis */
			{ 0, -50, 0-GCENT,  2, 100, 2,  0,  0,  1 },	/* -b (blue) axis */
			{ -50, 0, 0-GCENT,  100, 2, 2,  0,  1,  0 },	/* -a (green) axis */
			{ 0,  50, 0-GCENT,  2, 100, 2,  1,  1,  0 },	/* +b (yellow) axis */
		};

		/* Define the labels */
		struct {
			double x, y, z;
			double size;
			char *string;
			double r, g, b;
		} labels[6] = {
			{ -2, 2, -GCENT + 100 + 10, 10, "+L*",  .7, .7, .7 },	/* Top of L axis */
			{ -2, 2, -GCENT - 10,      10, "0",    .7, .7, .7 },	/* Bottom of L axis */
			{ 100 + 5, -3,  0-GCENT,  10, "+a*",  1,  0,  0 },	/* +a (red) axis */
			{ -5, -100 - 10, 0-GCENT,  10, "-b*",  0,  0,  1 },	/* -b (blue) axis */
			{ -100 - 15, -3, 0-GCENT,  10, "-a*",  0,  0,  1 },	/* -a (green) axis */
			{ -5,  100 + 5, 0-GCENT,  10, "+b*",  1,  1,  0 },	/* +b (yellow) axis */
		};

		fprintf(wrl,"    # Lab axes as boxes:\n");
		for (n = 0; n < 5; n++) {
			fprintf(wrl,"    Transform { translation %f %f %f\n", axes[n].x, axes[n].y, axes[n].z);
			fprintf(wrl,"      children [\n");
			fprintf(wrl,"        Shape{\n");
			fprintf(wrl,"          geometry Box { size %f %f %f }\n",
			                       axes[n].wx, axes[n].wy, axes[n].wz);
			fprintf(wrl,"          appearance Appearance { material Material ");
			fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[n].r, axes[n].g, axes[n].b);
			fprintf(wrl,"        }\n");
			fprintf(wrl,"      ]\n");
			fprintf(wrl,"    }\n");
		}
		fprintf(wrl,"    # Axes identification:\n");
		for (n = 0; n < 6; n++) {
			fprintf(wrl,"    Transform { translation %f %f %f\n", labels[n].x, labels[n].y, labels[n].z);
			fprintf(wrl,"      children [\n");
			fprintf(wrl,"        Shape{\n");
			fprintf(wrl,"          geometry Text { string [\"%s\"]\n",labels[n].string);
			fprintf(wrl,"            fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
			                                  labels[n].size);
			fprintf(wrl,"                        }\n");
			fprintf(wrl,"          appearance Appearance { material Material ");
			fprintf(wrl,"{ diffuseColor %f %f %f} }\n", labels[n].r, labels[n].g, labels[n].b);
			fprintf(wrl,"        }\n");
			fprintf(wrl,"      ]\n");
			fprintf(wrl,"    }\n");
		}
	}

	/* Read each input in turn */
	for (n = 0; n < ng; n++) {
		int i;
		cgats *pp;
		int nverts;
		int ntris;
		int Lf, af, bf;			/* Fields holding L, a & b data */
		int v0f, v1f, v2f;		/* Fields holding verticies 0, 1 & 2 */

		pp = new_cgats();	/* Create a CGATS structure */
	
		/* Setup to cope with a gamut file */
		pp->add_other(pp, "GAMUT");
	
		if (pp->read_name(pp, gds[n].in_name))
			error("Input file '%s' error : %s",gds[n].in_name, pp->err);
	
		if (pp->t[0].tt != tt_other || pp->t[0].oi != 0)
			error("Input file isn't a GAMUT format file");
		if (pp->ntables != 2)
			error("Input file doesn't contain exactly two tables");

		if ((nverts = pp->t[0].nsets) <= 0)
			error("No verticies");
		if ((ntris = pp->t[1].nsets) <= 0)
			error("No triangles");

		if ((Lf = pp->find_field(pp, 0, "LAB_L")) < 0)
			error("Input file doesn't contain field LAB_L");
		if (pp->t[0].ftype[Lf] != r_t)
			error("Field LAB_L is wrong type");
		if ((af = pp->find_field(pp, 0, "LAB_A")) < 0)
			error("Input file doesn't contain field LAB_A");
		if (pp->t[0].ftype[af] != r_t)
			error("Field LAB_A is wrong type");
		if ((bf = pp->find_field(pp, 0, "LAB_B")) < 0)
			error("Input file doesn't contain field LAB_B");
		if (pp->t[0].ftype[bf] != r_t)
			error("Field LAB_B is wrong type");

		/* Write the vertexes out */
		fprintf(wrl,"\n");
		fprintf(wrl,"    Transform {\n");
		fprintf(wrl,"      translation 0 0 0\n");
		fprintf(wrl,"      children [\n");
		fprintf(wrl,"        Shape { \n");
		if (gds[n].in_rep == gam_wire) {
			fprintf(wrl,"          geometry IndexedLineSet {\n");
		} else {
			fprintf(wrl,"          geometry IndexedFaceSet {\n");
			fprintf(wrl,"            ccw FALSE\n");
			fprintf(wrl,"            convex TRUE\n");
		}
		fprintf(wrl,"\n");
		fprintf(wrl,"            coord Coordinate { \n");
		fprintf(wrl,"              point [			# Verticy coordinates\n");

		/* Spit out the point values, in order. */
		/* Note that a->x, b->y, L->z */
		for (i = 0; i < nverts; i++) {
			double L, a, b;
			L = *((double *)pp->t[0].fdata[i][Lf]);
			a = *((double *)pp->t[0].fdata[i][af]);
			b = *((double *)pp->t[0].fdata[i][bf]);
			fprintf(wrl,"                %f %f %f,\n",a, b, L - GCENT);
		}
		fprintf(wrl,"              ]\n");
		fprintf(wrl,"            }\n");
		fprintf(wrl,"\n");

		/* Write the triangles/wires out */
		if ((v0f = pp->find_field(pp, 1, "VERTEX_0")) < 0)
			error("Input file doesn't contain field VERTEX_0");
		if (pp->t[1].ftype[v0f] != i_t)
			error("Field VERTEX_0 is wrong type");
		if ((v1f = pp->find_field(pp, 1, "VERTEX_1")) < 0)
			error("Input file doesn't contain field VERTEX_1");
		if (pp->t[1].ftype[v1f] != i_t)
			error("Field VERTEX_1 is wrong type");
		if ((v2f = pp->find_field(pp, 1, "VERTEX_2")) < 0)
			error("Input file doesn't contain field VERTEX_2");
		if (pp->t[1].ftype[v2f] != i_t)
			error("Field VERTEX_2 is wrong type");

		fprintf(wrl,"            coordIndex [ 		# Indexes of poligon Verticies \n");

		for (i = 0; i < ntris; i++) {
			int v0, v1, v2;
			v0 = *((int *)pp->t[1].fdata[i][v0f]);
			v1 = *((int *)pp->t[1].fdata[i][v1f]);
			v2 = *((int *)pp->t[1].fdata[i][v2f]);

#ifdef HALF_HACK 
			if (*((double *)pp->t[0].fdata[v0][Lf]) < HALF_HACK
			 || *((double *)pp->t[0].fdata[v1][Lf]) < HALF_HACK
			 || *((double *)pp->t[0].fdata[v2][Lf]) < HALF_HACK)
				continue;
#endif /* HALF_HACK */

			if (gds[n].in_rep == gam_wire) {
				if (v0 < v1)				/* Only output 1 wire of two on an edge */
					fprintf(wrl,"              %d, %d, -1\n", v0, v1);
				if (v1 < v2)
					fprintf(wrl,"              %d, %d, -1\n", v1, v2);
				if (v2 < v0)
					fprintf(wrl,"              %d, %d, -1\n", v2, v0);
			} else {
				fprintf(wrl,"              %d, %d, %d, -1\n", v0, v1, v2);
			}
		}
		fprintf(wrl,"            ]\n");
		fprintf(wrl,"\n");

		/* Write the colors out */
		if (gds[n].in_colors == gam_natural) {
			fprintf(wrl,"            colorPerVertex TRUE\n");
			fprintf(wrl,"            color Color {\n");
			fprintf(wrl,"              color [			# RGB colors of each vertex\n");

			for (i = 0; i < nverts; i++) {
				double rgb[3], Lab[3];
				Lab[0] = *((double *)pp->t[0].fdata[i][Lf]);
				Lab[1] = *((double *)pp->t[0].fdata[i][af]);
				Lab[2] = *((double *)pp->t[0].fdata[i][bf]);
				gamut_Lab2RGB(rgb, Lab);
				fprintf(wrl,"                %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
			}
			fprintf(wrl,"              ] \n");
			fprintf(wrl,"            }\n");
		}
		fprintf(wrl,"          }\n");
		fprintf(wrl,"          appearance Appearance { \n");
		fprintf(wrl,"            material Material {\n");
		if (gds[n].in_trans > 0.0) {
			fprintf(wrl,"              transparency %f\n", gds[n].in_trans);
		}
		fprintf(wrl,"              ambientIntensity 0.3\n");
		fprintf(wrl,"              shininess 0.5\n");
		if (gds[n].in_colors != gam_natural) {
			fprintf(wrl,"              emissiveColor %f %f %f\n",
			   color_rgb[gds[n].in_colors].r, color_rgb[gds[n].in_colors].g, color_rgb[gds[n].in_colors].b);
		}
		fprintf(wrl,"            }\n");
		fprintf(wrl,"          }\n");
		fprintf(wrl,"        }	# end Shape\n");
		fprintf(wrl,"      ] # end children\n");
		fprintf(wrl,"    } # end Transform\n");
		fprintf(wrl,"\n");

		/* See if there are cusp values */
		if (docusps) {
			int kk;
			double rgb[3], Lab[3];
			char buf1[50];
			char *cnames[6] = { "RED", "YELLOW", "GREEN", "CYAN", "BLUE", "MAGENTA" };
	
			for (i = 0; i < 6; i++) {
				sprintf(buf1,"CUSP_%s", cnames[i]);
				if ((kk = pp->find_kword(pp, 0, buf1)) < 0)
					break;
	
				if (sscanf(pp->t[0].kdata[kk], "%lf %lf %lf",
			           &Lab[0], &Lab[1], &Lab[2]) != 3) {
					break;
				}

				gamut_Lab2RGB(rgb, Lab);

				fprintf(wrl,"\n");
				fprintf(wrl,"    Transform {\n");
				fprintf(wrl,"      translation %f %f %f\n",Lab[1], Lab[2], Lab[0]-GCENT);
				fprintf(wrl,"      children [\n");
				fprintf(wrl,"		Shape { \n");
				fprintf(wrl,"		 geometry Sphere { radius 2.0 }\n");
				fprintf(wrl,"         appearance Appearance { material Material {\n");
				if (gds[n].in_trans > 0.0)
				fprintf(wrl,"         transparency %f\n", gds[n].in_trans);
				if (gds[n].in_colors != gam_natural)
				fprintf(wrl,"          diffuseColor %f %f %f\n", color_rgb[gds[n].in_colors].r, color_rgb[gds[n].in_colors].g, color_rgb[gds[n].in_colors].b);
				else
				fprintf(wrl,"          diffuseColor  %f %f %f\n", rgb[0], rgb[1], rgb[2]);
				fprintf(wrl,"		  }\n");
				fprintf(wrl,"		}\n");
				fprintf(wrl,"      }\n");
				fprintf(wrl,"     ]\n");
				fprintf(wrl,"    }\n");
			}
			fprintf(wrl,"\n");
		}

		pp->del(pp);		/* Clean up */
	}

	/* Write the trailer */
	fprintf(wrl,"  ] # end of children for world\n");
	fprintf(wrl,"}\n");

	/* Close the file */
	fclose(wrl);

	if (isect && ng >= 2) {
		gamut *s, *s1, *s2;
		double v1, v2, vi;

		if ((s = new_gamut(0.0, 0, 0)) == NULL)
			error("Creating gamut object failed");
		
		if ((s1 = new_gamut(0.0, 0, 0)) == NULL)
			error("Creating gamut object failed");
		
		if ((s2 = new_gamut(0.0, 0, 0)) == NULL)
			error("Creating gamut object failed");
		
		if (s1->read_gam(s1, gds[0].in_name))
			error("Input file '%s' read failed",gds[n].in_name[0]);

		if (s2->read_gam(s2, gds[1].in_name))
			error("Input file '%s' read failed",gds[n].in_name[1]);

		v1 = s1->volume(s1);
		v2 = s2->volume(s2);

		if (s->intersect(s, s1, s2))
			error("Gamuts are not compatible! (Colorspace, gamut center ?)");
		vi = s->volume(s);

		if (iout_name[0] != '\000') {
			if (s->write_gam(s, iout_name))
				error("Writing intersection gamut to '%s' failed",iout_name);
		}

		printf("Intersecting volume = %.1f cubic units\n",vi);
		printf("'%s' volume = %.1f cubic units, intersect = %.2f%%\n",gds[0].in_name,v1,100.0 * vi/v1);
		printf("'%s' volume = %.1f cubic units, intersect = %.2f%%\n",gds[1].in_name,v2,100.0 * vi/v2);

		s1->del(s1);
		s2->del(s2);
	}

	if (ng > 0)
		free(gds);

	return 0;
}
Exemplo n.º 11
0
int main(int argc, char *argv[])
{
	int i,j,k;
	int fa,nfa;				/* current argument we're looking at */
	int verb = 0;
	static char inname[200] = { 0 };		/* Input cgats file base name */
	static char outname[200] = { 0 };		/* Output cgats file base name */
	cgats *icg;			/* input cgats structure */
	cgats *ocg;			/* output cgats structure */
	time_t clk = time(0);
	struct tm *tsp = localtime(&clk);
	char *atm = asctime(tsp); /* Ascii time */
	int ti;				/* Temporary index */
	edatas ed;			/* Optimising function data structure */
	double resid[4];
	double presid,dresid;
	double sarea;

	error_program = argv[0];
	if (argc <= 1)
		usage();

	/* 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 */
						}
					}
				}

			if (argv[fa][1] == '?')
				usage();

			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
				verb = 1;
			else 
				usage();
			}
		else
			break;
		}

	/* Get the file name argument */
	if (fa >= argc || argv[fa][0] == '-') usage();
	strcpy(inname,argv[fa]);
	strcat(inname,".ti3");
	strcpy(outname,argv[fa]);
	strcat(outname,".pr1");

	icg = new_cgats();			/* Create a CGATS structure */
	icg->add_other(icg, "CTI3"); 	/* our special input type is Calibration Target Information 3 */

	if (icg->read_name(icg, inname))
		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 != 1)
		error ("Input file doesn't contain exactly one table");

	if ((ed.npat = icg->t[0].nsets) <= 0)
		error ("No sets of data");

	if (verb) {
		printf("No of test patches = %d\n",ed.npat);
	}

	if ((ed.cols = (col *)malloc(sizeof(col) * ed.npat)) == NULL)
		error("Malloc failed!");

	/* Setup output cgats file */
	/* This is a simple interpolation CMYK -> XYZ device profile */
	ocg = new_cgats();	/* Create a CGATS structure */
	ocg->add_other(ocg, "PROF1"); 		/* our special type is Profile type 1 */
	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */

	ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Device Profile Type 1",NULL);
	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll sprof", NULL);
	atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);

	/* Figure out the color space */
	if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
		error ("Input file doesn't contain keyword COLOR_REPS");
	if (strcmp(icg->t[0].kdata[ti],"CMYK_XYZ") == 0) {
		int ci, mi, yi, ki;
		int Xi, Yi, Zi;
		if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0)
			error ("Input file doesn't contain field CMYK_C");
		if (icg->t[0].ftype[ci] != r_t)
			error ("Field CMYK_C is wrong type");
		if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0)
			error ("Input file doesn't contain field CMYK_M");
		if (icg->t[0].ftype[mi] != r_t)
			error ("Field CMYK_M is wrong type");
		if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0)
			error ("Input file doesn't contain field CMYK_Y");
		if (icg->t[0].ftype[yi] != r_t)
			error ("Field CMYK_Y is wrong type");
		if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0)
			error ("Input file doesn't contain field CMYK_K");
		if (icg->t[0].ftype[ki] != r_t)
			error ("Field CMYK_K is wrong type");
		if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
			error ("Input file doesn't contain field XYZ_X");
		if (icg->t[0].ftype[Xi] != r_t)
			error ("Field XYZ_X is wrong type");
		if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
			error ("Input file doesn't contain field XYZ_Y");
		if (icg->t[0].ftype[Yi] != r_t)
			error ("Field XYZ_Y is wrong type");
		if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
			error ("Input file doesn't contain field XYZ_Z");
		if (icg->t[0].ftype[Zi] != r_t)
			error ("Field XYZ_Z is wrong type");
		for (i = 0; i < ed.npat; i++) {
			double XYZ[3];
			ed.cols[i].c = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
			ed.cols[i].m = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
			ed.cols[i].y = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
			ed.cols[i].k = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
			XYZ[0] = *((double *)icg->t[0].fdata[i][Xi]) / 100.0;
			XYZ[1] = *((double *)icg->t[0].fdata[i][Yi]) / 100.0;
			XYZ[2] = *((double *)icg->t[0].fdata[i][Zi]) / 100.0;
			icmXYZ2Lab(&icmD50, ed.cols[i].Lab, XYZ);
		}

		/* Initialise the model */
		ed.gam[0] = 1.0;		/* First four are CMYK gamma values */
		ed.gam[1] = 1.0;
		ed.gam[2] = 1.0;
		ed.gam[3] = 1.0;

		/* Initialise interpolation end points for each combination of primary, */
		/* with all combinations close to black being represented by param[7]. */
		ed.k[0][0] = .82; ed.k[1][0] = .83; ed.k[2][0] = .75;		/* White */
		ed.k[0][1] = .66; ed.k[1][1] = .72; ed.k[2][1] = .05;		/*   Y  */
		ed.k[0][2] = .27; ed.k[1][2] = .12; ed.k[2][2] = .06;		/*  M   */
		ed.k[0][3] = .27; ed.k[1][3] = .12; ed.k[2][3] = .00;		/*  MY  */
		ed.k[0][4] = .09; ed.k[1][4] = .13; ed.k[2][4] = .44;		/* C    */
		ed.k[0][5] = .03; ed.k[1][5] = .10; ed.k[2][5] = .04;		/* C Y  */
		ed.k[0][6] = .02; ed.k[1][6] = .01; ed.k[2][6] = .05;		/* CM   */
		ed.k[0][7] = .01; ed.k[1][7] = .01; ed.k[2][7] = .01;		/* Black */

		sarea = 0.3;
		presid = dresid = 100.0;
		for (k=0; /* dresid > 0.0001 && */ k < 40; k++) {	/* Untill we're done */
			double sresid;
			double sr[8];
			double p[8];

			/* Adjust the gamma */
			for (i = 0; i < 4; i++)
				sr[i] = 0.1;			/* Device space search radius */
			if (powell(&resid[3], 4, &ed.gam[0], sr,  0.1, 1000, efunc1, (void *)&ed, NULL, NULL) != 0)
				error ("Powell failed");

			/* Adjust the primaries */
			calc_bc(&ed);		/* Calculate blend coefficients */
			for (i = 0; i < 8; i++)
				sr[i] = 0.2;			/* Device space search radius */
			sresid = 99.0;
			for (j = 0; j < 3; j++) {	/* For each of X, Y and Z */
				ed.xyzi = j;

				for (i = 0; i < 8; i++)
					p[i] = ed.k[j][i];
printf("##############\n");
printf("XYZ = %d\n",j);
				if (powell(&resid[j], 8, p, sr,  0.1, 1000, efunc2, (void *)&ed, NULL, NULL) != 0)
					error ("Powell failed");

				for (i = 0; i < 8; i++)
					ed.k[j][i] = p[i];

				if (sresid > resid[j])
					sresid = resid[j];
			}
			dresid = presid - sresid;
			if (dresid < 0.0)
				dresid = 100.0;
			presid = sresid;
printf("~1 presid = %f, sresid = %f, dresid = %f\n",presid, sresid, dresid);
		}

		/* Fields we want */
		ocg->add_kword(ocg, 0, "DSPACE","CMYK", NULL);
		ocg->add_kword(ocg, 0, "DTYPE","PRINTER", NULL);
		ocg->add_field(ocg, 0, "PARAM_ID", i_t);
		ocg->add_field(ocg, 0, "PARAM", r_t);

		/* Output model parameters */
		for (j = 0; j < 4; j++)
			ocg->add_set(ocg, 0, j, ed.gam[j]);

		for (j = 0; j < 3; j++) {
			for (i = 0; i < 8; i++)
				ocg->add_set(ocg, 0, 10 * (j + 1) + i, 100.0 * ed.k[j][i]);
		}

		if (verb) {
			double aver = 0.0;
			double maxer = 0.0;
			for (i = 0; i < ed.npat; i++) {
				double err = sqrt(ed.cols[i].err);
				if (err > maxer)
					maxer = err;
				aver += err;
			}
			aver = aver/((double)i);
			printf("Average fit error = %f, maximum = %f\n",aver,maxer);
		}
	} else if (strcmp(icg->t[0].kdata[ti],"RGB") == 0) {
		error ("We can't handle RGB !");
	} else if (strcmp(icg->t[0].kdata[ti],"W") == 0) {
		error ("We can't handle Grey !");
	} else
		error ("Input file keyword COLOR_REPS has unknown value");

	if (ocg->write_name(ocg, outname))
		error("Write error : %s",ocg->err);

	free(ed.cols);
	ocg->del(ocg);		/* Clean up */
	icg->del(icg);		/* Clean up */

	return 0;
}