1 
2 /*
3  * Argyll Color Correction System
4  *
5  * Read in the device data from Colorblind device files,
6  * and convert it into a .ti3 CGATs format suitable for
7  * the Argyll CMM.
8  *
9  * Derived from  kodak2cgats.c
10  * Author: Graeme W. Gill
11  * Date:   16/11/00
12  *
13  * Copyright 2000, 2010, Graeme W. Gill
14  *
15  * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
16  * see the License.txt file for licencing details.
17  */
18 
19 #define VERSION "1.0"
20 
21 /* TTBD
22  */
23 
24 #undef DEBUG
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <sys/types.h>
30 #include <time.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include "copyright.h"
34 #include "aconfig.h"
35 #include "numlib.h"
36 #include "cgats.h"
37 
38 void
usage(void)39 usage(void) {
40 	fprintf(stderr,"Convert Colorblind raw device profile data to Argyll data, Version %s\n",ARGYLL_VERSION_STR);
41 	fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
42 	fprintf(stderr,"usage: cb2ti3 [-v] [-l limit] infile outfile\n");
43 	fprintf(stderr," -v              Verbose mode\n");
44 	fprintf(stderr," -l limit        Set inklimit in .ti3 file\n");
45 	fprintf(stderr," infile	         Base name for input.CMY and input.nCIE file\n");
46 	fprintf(stderr," outfile         Base name for output.ti3 file\n");
47 	exit(1);
48 	}
49 
main(int argc,char * argv[])50 int main(int argc, char *argv[])
51 {
52 	int i;
53 	int fa,nfa;				/* current argument we're looking at */
54 	int verb = 0;
55 	static char tarname[200] = { 0 };		/* Input .CMY file */
56 	static char inname[200] = { 0 };		/* Input .nCIE file */
57 	static char outname[200] = { 0 };		/* Output cgats .ti3 file base name */
58 	cgats *cmy;			/* Input RGB reference file */
59 	int f_id1, f_c, f_m, f_y;	/* Field indexes */
60 	cgats *ncie;		/* Inpit CIE readings file */
61 	int f_id2, f_xx, f_yy, f_zz;	/* Field indexes */
62 	cgats *ocg;			/* output cgats structure */
63 	time_t clk = time(0);
64 	struct tm *tsp = localtime(&clk);
65 	char *atm = asctime(tsp); /* Ascii time */
66 	int npat = 0;		/* Number of patches */
67 
68 	error_program = "cb2ti3";
69 
70 	if (argc <= 1)
71 		usage();
72 
73 	/* Process the arguments */
74 	for(fa = 1;fa < argc;fa++)
75 		{
76 		nfa = fa;					/* skip to nfa if next argument is used */
77 		if (argv[fa][0] == '-')		/* Look for any flags */
78 			{
79 			char *na = NULL;		/* next argument after flag, null if none */
80 
81 			if (argv[fa][2] != '\000')
82 				na = &argv[fa][2];		/* next is directly after flag */
83 			else
84 				{
85 				if ((fa+1) < argc)
86 					{
87 					if (argv[fa+1][0] != '-')
88 						{
89 						nfa = fa + 1;
90 						na = argv[nfa];		/* next is seperate non-flag argument */
91 						}
92 					}
93 				}
94 
95 			if (argv[fa][1] == '?')
96 				usage();
97 
98 			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
99 				verb = 1;
100 			else
101 				usage();
102 			}
103 		else
104 			break;
105 		}
106 
107 	/* Get the file name argument */
108 	if (fa >= argc || argv[fa][0] == '-') usage();
109 
110 	strcpy(inname,argv[fa]);
111 	strcpy(tarname,argv[fa++]);
112 	strcat(inname,".CMY");
113 	strcat(tarname,".nCIE");
114 
115 	if (fa >= argc || argv[fa][0] == '-') usage();
116 	strcpy(outname, argv[fa++]);
117 	strcat(outname,".ti3");
118 
119 	/* Open up the Input CMY reference file */
120 	cmy = new_cgats();	/* Create a CGATS structure */
121 	cmy->add_other(cmy, "CBTA"); 	/* Colorblind Target file */
122 	if (cmy->read_name(cmy, inname))
123 		error ("Read: Can't open file '%s'",inname);
124 	if (cmy->ntables == 0 || cmy->t[0].tt != tt_other || cmy->t[0].oi != 0)
125 		error ("Input file isn't a 'CBTA' format file");
126 	if (cmy->ntables != 1)
127 		fprintf(stderr,"Input file '%s' doesn't contain exactly one table",inname);
128 
129 	if ((npat = cmy->t[0].nsets) <= 0)
130 		error("No patches");
131 
132 	if ((f_id1 = cmy->find_field(cmy, 0, "SAMPLE_ID")) < 0)
133 		error("Input file doesn't contain field SAMPLE_ID");
134 	if (cmy->t[0].ftype[f_id1] != nqcs_t)
135 		error("Field SAMPLE_ID is wrong type");
136 
137 	if ((f_c = cmy->find_field(cmy, 0, "C")) < 0)
138 		error("Input file doesn't contain field C");
139 	if (cmy->t[0].ftype[f_c] != r_t)
140 		error("Field C is wrong type");
141 
142 	if ((f_m = cmy->find_field(cmy, 0, "M")) < 0)
143 		error("Input file doesn't contain field M");
144 	if (cmy->t[0].ftype[f_m] != r_t)
145 		error("Field M is wrong type");
146 
147 	if ((f_y = cmy->find_field(cmy, 0, "Y")) < 0)
148 		error("Input file doesn't contain field Y");
149 	if (cmy->t[0].ftype[f_y] != r_t)
150 		error("Field Y is wrong type");
151 
152 	/* Open up the input nCIE device data file */
153 	ncie = new_cgats();	/* Create a CGATS structure */
154 	ncie->add_other(ncie, "CBPR"); 	/* Colorblind Printer Response file */
155 	if (ncie->read_name(ncie, tarname))
156 		error ("Read: Can't open file '%s'",tarname);
157 	if (ncie->ntables == 0 || ncie->t[0].tt != tt_other || ncie->t[0].oi != 0)
158 		error ("Input file isn't a 'CBTA' format file");
159 	if (ncie->ntables != 1)
160 		fprintf(stderr,"Input file '%s' doesn't contain exactly one table",tarname);
161 
162 	if (npat != ncie->t[0].nsets)
163 		error("Number of patches doesn't match");
164 
165 	if ((f_id2 = ncie->find_field(ncie, 0, "SAMPLE_ID")) < 0)
166 		error("Input file doesn't contain field SAMPLE_ID");
167 	if (ncie->t[0].ftype[f_id2] != nqcs_t)
168 		error("Field SAMPLE_ID is wrong type");
169 
170 	if ((f_xx = ncie->find_field(ncie, 0, "XYZ_X")) < 0)
171 		error("Input file doesn't contain field XYZ_X");
172 	if (ncie->t[0].ftype[f_xx] != r_t)
173 		error("Field XYZ_X is wrong type");
174 
175 	if ((f_yy = ncie->find_field(ncie, 0, "XYZ_Y")) < 0)
176 		error("Input file doesn't contain field XYZ_Y");
177 	if (ncie->t[0].ftype[f_yy] != r_t)
178 		error("Field XYZ_Y is wrong type");
179 
180 	if ((f_zz = ncie->find_field(ncie, 0, "XYZ_Z")) < 0)
181 		error("Input file doesn't contain field XYZ_Z");
182 	if (ncie->t[0].ftype[f_zz] != r_t)
183 		error("Field XYZ_Z is wrong type");
184 
185 	/* Setup output cgats file */
186 	ocg = new_cgats();	/* Create a CGATS structure */
187 	ocg->add_other(ocg, "CTI3"); 	/* our special type is Calibration Target Information 3 */
188 	ocg->add_table(ocg, tt_other, 0);	/* Start the first table */
189 
190 	ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
191 	ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
192 	atm[strlen(atm)-1] = '\000';	/* Remove \n from end */
193 	ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
194 	ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);	/* What sort of device this is */
195 
196 	/* Fields we want */
197 	ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
198 
199 	ocg->add_field(ocg, 0, "RGB_R", r_t);
200 	ocg->add_field(ocg, 0, "RGB_G", r_t);
201 	ocg->add_field(ocg, 0, "RGB_B", r_t);
202 	ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
203 	ocg->add_field(ocg, 0, "XYZ_X", r_t);
204 	ocg->add_field(ocg, 0, "XYZ_Y", r_t);
205 	ocg->add_field(ocg, 0, "XYZ_Z", r_t);
206 
207 	/* Write out the patch info to the output CGATS file */
208 	for (i = 0; i < npat; i++) {
209 		char id[100];
210 		double rgb[3];
211 		double xyz[3];
212 
213 		if (strcmp(((char *)cmy->t[0].fdata[i][f_id1]),
214 		           ((char *)ncie->t[0].fdata[i][f_id2])) != 0) {
215 			error("Patch label mismatch, patch %d, '%s' != '%s'\n",
216 			       i, ((char *)cmy->t[0].fdata[i][f_id1]),
217 		              ((char *)ncie->t[0].fdata[i][f_id2]));
218 		}
219 
220 		rgb[0] = 100.0 - *((double *)cmy->t[0].fdata[i][f_c]);	/* Convert to RGB */
221 		rgb[1] = 100.0 - *((double *)cmy->t[0].fdata[i][f_m]);
222 		rgb[2] = 100.0 - *((double *)cmy->t[0].fdata[i][f_y]);
223 
224 		xyz[0] = *((double *)ncie->t[0].fdata[i][f_xx]);
225 		xyz[1] = *((double *)ncie->t[0].fdata[i][f_yy]);
226 		xyz[2] = *((double *)ncie->t[0].fdata[i][f_zz]);
227 
228 		sprintf(id, "%d", i+1);
229 		ocg->add_set(ocg, 0, id, rgb[0], rgb[1], rgb[2],
230 		                         xyz[0], xyz[1], xyz[2]);
231 	}
232 
233 	if (ocg->write_name(ocg, outname))
234 		error("Write error : %s",ocg->err);
235 
236 	ncie->del(ncie);		/* Clean up */
237 	cmy->del(cmy);
238 	ocg->del(ocg);
239 
240 	return 0;
241 }
242 
243 
244 
245