1
2 /*
3 * International Color Consortium Format Library (icclib)
4 * Check the device chanel to PCS monotonicity.
5 *
6 * Author: Graeme W. Gill
7 * Date: 2000/12/11
8 * Version: 2.15
9 *
10 * Copyright 2000 - 2012 Graeme W. Gill
11 *
12 * This material is licensed with an "MIT" free use license:-
13 * see the License4.txt file in this directory for licensing details.
14 */
15
16 /* TTBD:
17 *
18 * Make general device input, not just CMYK
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <math.h>
27 #include "vrml.h"
28 #include "icc.h"
29
30 void error(char *fmt, ...), warning(char *fmt, ...);
31
usage(void)32 void usage(void) {
33 fprintf(stderr,"Check device to PCS monotonicity of a CMYK ICC file, V%s\n",ICCLIB_VERSION_STR);
34 fprintf(stderr,"Author: Graeme W. Gill\n");
35 fprintf(stderr,"usage: mcheck [-v] [-w] infile\n");
36 fprintf(stderr," -v verbose\n");
37 fprintf(stderr," -c Check just Cyan monotonicity\n");
38 fprintf(stderr," -m Check just Magenta monotonicity\n");
39 fprintf(stderr," -y Check just Yellow monotonicity\n");
40 fprintf(stderr," -k Check just Black monotonicity\n");
41 fprintf(stderr," -w create %s visualisation\n",vrml_format());
42 fprintf(stderr," -x use %s axes\n",vrml_format());
43 exit(1);
44 }
45
46 #define MGR 50 /* Maximum grid resolution handled */
47
48 int
main(int argc,char * argv[])49 main(
50 int argc,
51 char *argv[]
52 ) {
53 int fa,nfa; /* argument we're looking at */
54 int verb = 0;
55 int cchan = -1; /* default all */
56 int dovrml = 0;
57 int doaxes = 0;
58 char in_name[500];
59 char out_name[500], *xl;
60 icmFile *rd_fp;
61 icc *wr_icco, *rd_icco; /* Keep object separate */
62 int rv = 0;
63
64 /* Check variables */
65 icmLuBase *luo;
66 icmLuLut *luluto; /* Lookup xLut type object */
67 int gres; /* Grid resolution */
68 icColorSpaceSignature ins, outs; /* Type of input and output spaces */
69 int inn; /* Number of input chanels */
70 icmLuAlgType alg;
71 vrml *wrl;
72 int dx[4]; /* Device index mapping */
73 int chan, cs, ce;
74
75 if (argc < 2)
76 usage();
77
78 /* Process the arguments */
79 for(fa = 1;fa < argc;fa++) {
80 nfa = fa; /* skip to nfa if next argument is used */
81 if (argv[fa][0] == '-') { /* Look for any flags */
82 char *na = NULL; /* next argument after flag, null if none */
83
84 if (argv[fa][2] != '\000')
85 na = &argv[fa][2]; /* next is directly after flag */
86 else {
87 if ((fa+1) < argc) {
88 if (argv[fa+1][0] != '-') {
89 nfa = fa + 1;
90 na = argv[nfa]; /* next is seperate non-flag argument */
91 }
92 }
93 }
94
95 /* Verbosity */
96 if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
97 verb = 1;
98 }
99 /* VRML/X3D */
100 else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
101 dovrml = 1;
102 }
103 /* Cyan */
104 else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
105 cchan = 0;
106 }
107 /* Magenta */
108 else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
109 cchan = 1;
110 }
111 /* Yellow */
112 else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y') {
113 cchan = 2;
114 }
115 /* Black */
116 else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
117 cchan = 3;
118 }
119 else if (argv[fa][1] == 'x') {
120 doaxes = 1;
121 }
122 else if (argv[fa][1] == '?')
123 usage();
124 else
125 usage();
126 }
127 else
128 break;
129 }
130
131 if (fa >= argc || argv[fa][0] == '-') usage();
132 strcpy(in_name,argv[fa]);
133
134 strcpy(out_name, in_name);
135 if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
136 xl = out_name + strlen(out_name);
137 xl[0] = '\000'; /* Remove extension */
138
139 /* Open up the file for reading */
140 if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
141 error ("Read: Can't open file '%s'",in_name);
142
143 if ((rd_icco = new_icc()) == NULL)
144 error ("Read: Creation of ICC object failed");
145
146 /* Read the header and tag list */
147 if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
148 error ("Read: %d, %s",rv,rd_icco->err);
149
150 /* Get a Device to PCS conversion object */
151 if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icRelativeColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
152 if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
153 error ("%d, %s",rd_icco->errc, rd_icco->err);
154 }
155 /* Get details of conversion */
156 luo->spaces(luo, &ins, &inn, &outs, NULL, &alg, NULL, NULL, NULL, NULL);
157
158 if (alg != icmLutType) {
159 error("Expecting Lut based profile");
160 }
161
162 if (ins != icSigCmykData) {
163 error("Expecting CMYK device");
164 }
165
166 if (outs != icSigLabData) {
167 error("Expecting Lab PCS");
168 }
169
170 luluto = (icmLuLut *)luo; /* Lookup xLut type object */
171
172 gres = luluto->lut->clutPoints;
173 if (gres > MGR) {
174 error("Can't handle grid resolution greater than %d\n",MGR);
175 }
176
177 if (dovrml) {
178 wrl = new_vrml(out_name, doaxes, vrml_lab);
179 if (wrl == NULL)
180 error("new_vrml for '%s%s' failed",out_name,vrml_ext());
181 wrl->start_line_set(wrl, 0);
182 }
183
184 /* For all the device chanels chosen */
185 if (cchan < 0) {
186 cs = 0;
187 ce = inn;
188 } else {
189 cs = cchan;
190 ce = cs + 1;
191 }
192 for (chan = cs; chan < ce; chan++) {
193
194 /* Check the monotonicity of the output for a given device input */
195 int co[4];
196 if (chan == 0) {
197 dx[0] = 1;
198 dx[1] = 2;
199 dx[2] = 3;
200 dx[3] = 0; /* Cyan is variable */
201 } else if (chan == 1) {
202 dx[0] = 0;
203 dx[1] = 2;
204 dx[2] = 3;
205 dx[3] = 1; /* Magenta is variable */
206 } else if (chan == 2) {
207 dx[0] = 0;
208 dx[1] = 1;
209 dx[2] = 3;
210 dx[3] = 2; /* Yellow is variable */
211 } else if (chan == 3) {
212 dx[0] = 0;
213 dx[1] = 1;
214 dx[2] = 2;
215 dx[3] = 3; /* Black is variable */
216 }
217
218 /* Itterate throught the CMY clut grid points */
219 for (co[0] = 0; co[0] < gres; co[0]++) {
220 for (co[1] = 0; co[1] < gres; co[1]++) {
221 for (co[2] = 0; co[2] < gres; co[2]++) {
222 int j, k, ck, nm;
223 double dev[MGR][4];
224 double pcs[MGR][3];
225 double apcs[3], ss;
226
227 /* Run up the variable axis */
228 for (ck = 0; ck < gres; ck++) {
229
230 dev[ck][dx[0]] = co[0]/(gres-1.0);
231 dev[ck][dx[1]] = co[1]/(gres-1.0);
232 dev[ck][dx[2]] = co[2]/(gres-1.0);
233 dev[ck][dx[3]] = ck/(gres-1.0);
234
235 /* Device to PCS */
236 if ((rv = luluto->clut(luluto, pcs[ck], dev[ck])) > 1)
237 error ("%d, %s",rd_icco->errc,rd_icco->err);
238
239 // if (dovrml)
240 // wrl->add_vertex(wrl, 0, pcs[ck]);
241 }
242
243 /* Compute average vector direction */
244 for (ss = 0.0, k = 0; k < 3; k++) {
245 double tt;
246 tt = pcs[gres-1][k] - pcs[0][k];
247 ss += tt * tt;
248 apcs[k] = tt;
249 }
250 for (k = 0; k < 3; k++)
251 apcs[k] /= ss;
252
253 /* Now compute the dot product for each vector, */
254 /* and check for reversals. */
255 j = 0;
256 //printf("Checking CMYK %f %f %f %f Lab %f %f %f\n",
257 // dev[j][0], dev[j][1], dev[j][2], dev[j][3],
258 // pcs[j][0], pcs[j][1], pcs[j][2]);
259 for (nm = 0, j = 1; j < gres; j++) {
260 for (ss = 0.0, k = 0; k < 3; k++) /* Dot product */
261 ss += (pcs[j][k] - pcs[j-1][k]) * apcs[k];
262
263 //printf("Checking %f CMYK %f %f %f %f Lab %f %f %f\n",
264 // ss, dev[j][0], dev[j][1], dev[j][2], dev[j][3],
265 // pcs[j][0], pcs[j][1], pcs[j][2]);
266
267 if (ss <= 0.0) {
268 nm = 1;
269 printf("NonMon %f at CMYK %f %f %f %f Lab %f %f %f\n",
270 ss, dev[j][0], dev[j][1], dev[j][2], dev[j][3],
271 pcs[j][0], pcs[j][1], pcs[j][2]);
272 }
273 }
274 //printf("\n");
275
276 /* Display just the non mono threads */
277 if (nm && dovrml) {
278 for (j = 0; j < gres; j++)
279 wrl->add_vertex(wrl, 0, pcs[j]);
280 }
281 if (verb) {
282 printf("."); fflush(stdout);
283 }
284 }
285 }
286 }
287 }
288
289 if (dovrml) {
290 wrl->make_lines(wrl, 0, gres);
291 wrl->del(wrl);
292 }
293
294 /* Done with lookup object */
295 luo->del(luo);
296
297 rd_icco->del(rd_icco);
298 rd_fp->del(rd_fp);
299
300 return 0;
301 }
302
303 /* ------------------------------------------------ */
304 /* Basic printf type error() and warning() routines */
305
306 void
error(char * fmt,...)307 error(char *fmt, ...)
308 {
309 va_list args;
310
311 fprintf(stderr,"icctest: Error - ");
312 va_start(args, fmt);
313 vfprintf(stderr, fmt, args);
314 va_end(args);
315 fprintf(stderr, "\n");
316 exit (-1);
317 }
318
319 void
warning(char * fmt,...)320 warning(char *fmt, ...)
321 {
322 va_list args;
323
324 fprintf(stderr,"icctest: Warning - ");
325 va_start(args, fmt);
326 vfprintf(stderr, fmt, args);
327 va_end(args);
328 fprintf(stderr, "\n");
329 }
330