1 
2 /*
3  * Extract a CGATS file from an ICC profile tag.
4  * (Can also extract a tag of unknown format as a binary lump).
5  *
6  * Author:  Graeme W. Gill
7  * Date:    2008/5/18
8  * Version: 1.00
9  *
10  * Copyright 2008 Graeme W. Gill
11  * All rights reserved.
12  * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
13  * see the License.txt file for licencing details.
14  */
15 
16 /*
17  * TTBD:
18  *
19  * Should uncompress ZXML type tag using zlib.
20  *
21  */
22 
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <math.h>
30 #include "copyright.h"
31 #include "aconfig.h"
32 #include "numlib.h"
33 #include "icc.h"
34 #include "xicc.h"
35 
36 #define MXTGNMS 30
37 
usage(char * diag,...)38 void usage(char *diag, ...) {
39 	int i;
40 	fprintf(stderr,"Extract a text tag from an ICC profile, Version %s\n",ARGYLL_VERSION_STR);
41 	fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
42 	if (diag != NULL) {
43 		va_list args;
44 		fprintf(stderr,"Diagnostic: ");
45 		va_start(args, diag);
46 		vfprintf(stderr, diag, args);
47 		va_end(args);
48 		fprintf(stderr,"\n");
49 	}
50 	fprintf(stderr,"usage: extractttag  [-v] infile%s outfile\n",ICC_FILE_EXT);
51 	fprintf(stderr," -v            Verbose\n");
52 	fprintf(stderr," -t tag        Extract this tag rather than default 'targ'\n");
53 	fprintf(stderr," -c            Extract calibration file from 'targ' tag\n");
54 	exit(1);
55 }
56 
57 int
main(int argc,char * argv[])58 main(int argc, char *argv[]) {
59 	int fa,nfa;					/* argument we're looking at */
60 	char in_name[MAXNAMEL+1];	/* TIFF input name */
61 	char out_name[MAXNAMEL+1];	/* ICC output name */
62 	char tag_name[MXTGNMS] = { 't','a','r','g' };
63 	int docal = 0;
64 	icc *icco;
65 	icTagSignature sig;
66 	icmText *ro;
67 	icmUnknown *uro;
68 	icmFile *ifp, *ofp;
69 	int verb = 0;
70 	int  size = 0;
71 	void *buf = NULL;
72 	int rv = 0;
73 
74 	error_program = argv[0];
75 
76 	if (argc < 3)
77 		usage("Too few parameters");
78 
79 	/* Process the arguments */
80 	for(fa = 1;fa < argc;fa++) {
81 		nfa = fa;					/* skip to nfa if next argument is used */
82 		if (argv[fa][0] == '-')	{	/* Look for any flags */
83 			char *na = NULL;		/* next argument after flag, null if none */
84 
85 			if (argv[fa][2] != '\000')
86 				na = &argv[fa][2];		/* next is directly after flag */
87 			else {
88 				if ((fa+1) < argc) {
89 					if (argv[fa+1][0] != '-') {
90 						nfa = fa + 1;
91 						na = argv[nfa];		/* next is seperate non-flag argument */
92 					}
93 				}
94 			}
95 
96 			if (argv[fa][1] == '?')
97 				usage(NULL);
98 
99 			/* Verbosity */
100 			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
101 				verb = 1;
102 			}
103 
104 			/* Tag name */
105 			else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
106 				fa = nfa;
107 				if (na == NULL) usage("Expect tag name after -t");
108 				strncpy(tag_name,na,4);
109 				tag_name[4] = '\000';
110 			}
111 
112 			/* Calibration */
113 			else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
114 				docal = 1;
115 			}
116 
117 			else
118 				usage("Unknown flag '%c'",argv[fa][1]);
119 		} else
120 			break;
121 	}
122 
123     if (fa >= argc || argv[fa][0] == '-') usage("Missing input ICC profile");
124     strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
125 
126     if (fa >= argc || argv[fa][0] == '-') usage("Missing output filename");
127     strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
128 
129 	/* - - - - - - - - - - - - - - - */
130 
131 	/* Open up the file for reading */
132 	if ((ifp = new_icmFileStd_name(in_name,"r")) == NULL)
133 		error ("Can't open file '%s'",in_name);
134 
135 	if ((icco = new_icc()) == NULL)
136 		error ("Creation of ICC object failed");
137 
138 	if ((rv = icco->read(icco,ifp,0)) != 0)
139 		error ("%d, %s",rv,icco->err);
140 
141 	sig = str2tag(tag_name);
142 
143 	if ((ro = (icmText *)icco->read_tag_any(icco, sig)) == NULL) {
144 		error("%d, %s",icco->errc, icco->err);
145 	}
146 
147 	if (ro->ttype == icmSigUnknownType) {
148 		uro = (icmUnknown *)ro;
149 	} else if (ro->ttype != icSigTextType) {
150 		error("Tag isn't TextType or UnknownType");
151 	}
152 
153 	if (docal) {
154 		cgatsFile *cgf;
155 		cgats *icg;
156 		int tab, oi;
157 		xcal *cal;
158 
159 		if ((icg = new_cgats()) == NULL) {
160 			error("new_cgats() failed");
161 		}
162 		if ((cgf = new_cgatsFileMem(ro->data, ro->size)) == NULL)  {
163 			error("new_cgatsFileMem() failed");
164 		}
165 		icg->add_other(icg, "CTI3");
166 		oi = icg->add_other(icg, "CAL");
167 
168 		if (icg->read(icg, cgf) != 0) {
169 			error("failed to parse tag contents as a CGATS file");
170 		}
171 
172 		for (tab = 0; tab < icg->ntables; tab++) {
173 			if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
174 				break;
175 			}
176 		}
177 		if (tab >= icg->ntables) {
178 			error("Failed to locate CAL table in CGATS");
179 		}
180 
181 		if ((cal = new_xcal()) == NULL) {
182 			error("new_xcal() failed");
183 		}
184 		if (cal->read_cgats(cal, icg, tab, in_name) != 0)  {
185 			error("Parsing CAL table failed");
186 		}
187 		icg->del(icg);
188 		cgf->del(cgf);
189 
190 		if (cal->write(cal, out_name) != 0) {
191 			error("writing to file '%s' failed\n",out_name);
192 		}
193 	} else {
194 		if ((ofp = new_icmFileStd_name(out_name, "w")) == NULL) {
195 			error("unable to open output file '%s'",out_name);
196 		}
197 
198 		if (ro->ttype == icmSigUnknownType) {
199 			if (ofp->write(ofp, uro->data, 1, uro->size) != (uro->size)) {
200 				error("writing to file '%s' failed",out_name);
201 			}
202 		} else {
203 			if (ofp->write(ofp, ro->data, 1, ro->size-1) != (ro->size-1)) {
204 				error("writing to file '%s' failed",out_name);
205 			}
206 		}
207 
208 		if (ofp->del(ofp) != 0) {
209 			error("closing file '%s' failed",out_name);
210 		}
211 	}
212 
213 	icco->del(icco);
214 	ifp->del(ifp);
215 
216 	return 0;
217 }
218