1 
2 /*
3  * xicc standalone utilities
4  *
5  * Author:  Graeme W. Gill
6  * Date:    2/7/00
7  * Version: 1.00
8  *
9  * Copyright 2000 - 2006 Graeme W. Gill
10  * All rights reserved.
11  * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
12  * see the License.txt file for licencing details.
13  *
14  */
15 
16 /*
17  * This module provides expanded capabilities,
18  * but is independent of other modules.
19  */
20 
21 #include <sys/types.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <setjmp.h>
25 #ifdef __sun
26 #include <unistd.h>
27 #endif
28 #if defined(__IBMC__) && defined(_M_IX86)
29 #include <float.h>
30 #endif
31 #include "copyright.h"
32 #include "aconfig.h"
33 #include "icc.h"
34 #include "tiffio.h"
35 #include "jpeglib.h"
36 #include "iccjpeg.h"
37 #include "xutils.h"		/* definitions for this library */
38 
39 
40 #undef DEBUG
41 
42 #ifdef DEBUG
43 # define errout stderr
44 # define debug(xx)	fprintf(errout, xx )
45 # define debug2(xx)	fprintf xx
46 #else
47 # define debug(xx)
48 # define debug2(xx)
49 #endif
50 
51 #if !defined(O_CREAT) && !defined(_O_CREAT)
52 # error "Need to #include fcntl.h!"
53 #endif
54 
55 /* ------------------------------------------------------ */
56 /* Common clut table code */
57 
58 /* Default table of clut resolutions */
59 /* See discussion in imdi/imdi_gen.c for ideal numbers */
60 static int lut_resolutions[9][4] = {
61 	/* low, med, high, vhigh */
62 	{ 0,     0,    0,    0 },		/* 0 */
63 	{ 256, 772, 4370, 4370 },		/* 1 */
64 	{  86, 256,  256,  256 },		/* 2 */
65 	{   9,  17,   33,   52 },		/* 3 */
66 	{   6,   9,   18,   33 },		/* 4 */
67 	{   6,   9,   16,   18 },		/* 5 */
68 	{   6,   6,    9,   12 },		/* 6 */
69 	{   6,   7,    7,    9 },		/* 7 */
70 	{   3,   5,    5,    7 }		/* 8 */
71 };
72 
73 
74 /* return a lut resolution given the input dimesion and quality */
75 /* Input dimension [0-8], quality: low 0, medium 1, high 2, very high 3 . */
76 /* A returned value of 0 indicates illegal.  */
dim_to_clutres(int dim,int quality)77 int dim_to_clutres(int dim, int quality) {
78 	if (dim < 0)
79 		dim = 0;
80 	else if (dim > 8)
81 		dim = 8;
82 	if (quality < 0)
83 		quality = 0;
84 	if (quality > 3)
85 		quality = 3;
86 	return lut_resolutions[dim][quality];
87 }
88 
89 /* ------------------------------------------------------ */
90 
91 /* JPEG error information */
92 typedef struct {
93 	jmp_buf env;		/* setjmp/longjmp environment */
94 	char message[JMSG_LENGTH_MAX];
95 } jpegerrorinfo;
96 
97 /* JPEG error handler */
jpeg_error(j_common_ptr cinfo)98 static void jpeg_error(j_common_ptr cinfo) {
99 	jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
100 	(*cinfo->err->format_message) (cinfo, p->message);
101 	longjmp(p->env, 1);
102 }
103 
104 /* ------------------------------------------------------ */
105 
106 /* Open an ICC file or a TIFF or JPEG  file with an embedded ICC profile for reading. */
107 /* Return NULL on error */
read_embedded_icc(char * file_name)108 icc *read_embedded_icc(char *file_name) {
109 	TIFF *rh = NULL;
110 	int  size;
111 	void *tag, *buf;
112 	icmAlloc *al;
113 	icmFile *fp;
114 	icc *icco;
115 	TIFFErrorHandler olderrh, oldwarnh;
116 	TIFFErrorHandlerExt olderrhx, oldwarnhx;
117 	int rv;
118 
119 	/* First see if the file can be opened as an ICC profile */
120 	if ((fp = new_icmFileStd_name(file_name,"r")) == NULL) {
121 		debug2((errout,"Can't open file '%s'\n",file_name));
122 		return NULL;
123 	}
124 
125 	if ((icco = new_icc()) == NULL) {
126 		debug("Creation of ICC object failed\n");
127 		fp->del(fp);
128 		return NULL;
129 	}
130 
131 	if ((rv = icco->read_x(icco,fp,0,1)) == 0) {
132 		debug2((errout,"Opened '%s' as an icc profile\n",file_name));
133 		return icco;
134 	}
135 
136 	debug2((errout,"icc read failed with %d, %s\n",rv,icco->err));
137 	icco->del(icco);		/* icc wil fp->del() */
138 
139 	/* Not an ICC profile, see if it's a TIFF file */
140 	olderrh = TIFFSetErrorHandler(NULL);
141 	oldwarnh = TIFFSetWarningHandler(NULL);
142 	olderrhx = TIFFSetErrorHandlerExt(NULL);
143 	oldwarnhx = TIFFSetWarningHandlerExt(NULL);
144 
145 	if ((rh = TIFFOpen(file_name, "r")) != NULL) {
146 		TIFFSetErrorHandler(olderrh);
147 		TIFFSetWarningHandler(oldwarnh);
148 		TIFFSetErrorHandlerExt(olderrhx);
149 		TIFFSetWarningHandlerExt(oldwarnhx);
150 		debug("TIFFOpen suceeded\n");
151 
152 		if (TIFFGetField(rh, TIFFTAG_ICCPROFILE, &size, &tag) == 0 || size == 0) {
153 			debug2((errout,"no ICC profile found in '%s'\n",file_name));
154 			TIFFClose(rh);
155 			return NULL;
156 		}
157 
158 		/* Make a copy of the profile to a memory buffer */
159 		if ((al = new_icmAllocStd()) == NULL) {
160 			debug("new_icmAllocStd failed\n");
161 			TIFFClose(rh);
162 		    return NULL;
163 		}
164 		if ((buf = al->malloc(al, size)) == NULL) {
165 			debug("malloc of profile buffer failed\n");
166 			al->del(al);
167 			TIFFClose(rh);
168 		    return NULL;
169 		}
170 
171 		memmove(buf, tag, size);
172 		TIFFClose(rh);
173 
174 	} else {
175 		jpegerrorinfo jpeg_rerr;
176 		FILE *rf = NULL;
177 		struct jpeg_decompress_struct rj;
178 		struct jpeg_error_mgr jerr;
179 		unsigned char *pdata;
180 		unsigned int plen;
181 
182 		debug2((errout,"TIFFOpen failed for '%s'\n",file_name));
183 		TIFFSetErrorHandler(olderrh);
184 		TIFFSetWarningHandler(oldwarnh);
185 		TIFFSetErrorHandlerExt(olderrhx);
186 		TIFFSetWarningHandlerExt(oldwarnhx);
187 
188 		/* We cope with the horrible ijg jpeg library error handling */
189 		/* by using a setjmp/longjmp. */
190 		jpeg_std_error(&jerr);
191 		jerr.error_exit = jpeg_error;
192 		if (setjmp(jpeg_rerr.env)) {
193 			debug2((errout,"jpeg_read_header failed for '%s'\n",file_name));
194 			jpeg_destroy_decompress(&rj);
195 			fclose(rf);
196 			return NULL;
197 		}
198 
199 		rj.err = &jerr;
200 		rj.client_data = &jpeg_rerr;
201 		jpeg_create_decompress(&rj);
202 
203 #if defined(O_BINARY) || defined(_O_BINARY)
204 	    if ((rf = fopen(file_name,"rb")) == NULL)
205 #else
206 	    if ((rf = fopen(file_name,"r")) == NULL)
207 #endif
208 		{
209 			debug2((errout,"fopen failed for '%s'\n",file_name));
210 			jpeg_destroy_decompress(&rj);
211 			return NULL;
212 		}
213 
214 		jpeg_stdio_src(&rj, rf);
215 		setup_read_icc_profile(&rj);
216 
217 		/* we'll longjmp on error */
218 		jpeg_read_header(&rj, TRUE);
219 
220 		if (!read_icc_profile(&rj, &pdata, &plen)) {
221 			debug2((errout,"no ICC profile found in '%s'\n",file_name));
222 			jpeg_destroy_decompress(&rj);
223 			fclose(rf);
224 			return NULL;
225 		}
226 		jpeg_destroy_decompress(&rj);
227 		fclose(rf);
228 
229 		/* Make a copy of the profile to a memory buffer */
230 		/* (icmAllocStd may not be the same as malloc ?) */
231 		if ((al = new_icmAllocStd()) == NULL) {
232 			debug("new_icmAllocStd failed\n");
233 		    return NULL;
234 		}
235 		if ((buf = al->malloc(al, plen)) == NULL) {
236 			debug("malloc of profile buffer failed\n");
237 			al->del(al);
238 			TIFFClose(rh);
239 		    return NULL;
240 		}
241 		memmove(buf, pdata, plen);
242 		size = (int)plen;
243 		free(pdata);
244 	}
245 
246 	/* Memory File fp that will free the buffer when deleted: */
247 	if ((fp = new_icmFileMem_ad(buf, size, al)) == NULL) {
248 		debug("Creating memory file from CMProfileLocation failed");
249 		al->free(al, buf);
250 		al->del(al);
251 		return NULL;
252 	}
253 
254 	if ((icco = new_icc()) == NULL) {
255 		debug("Creation of ICC object failed\n");
256 		fp->del(fp);	/* fp will delete al */
257 		return NULL;
258 	}
259 
260 	if ((rv = icco->read_x(icco,fp,0,1)) == 0) {
261 		debug2((errout,"Opened '%s' embedded icc profile\n",file_name));
262 		return icco;
263 	}
264 
265 	debug2((errout,"Failed to read '%s' embedded icc profile\n",file_name));
266 	icco->del(icco);	/* icco will delete fp and al */
267 	return NULL;
268 }
269 
270 /* ------------------------------------------------------ */
271 
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 
282 
283 
284 
285 
286 
287 
288 
289 
290 
291 
292 
293 
294 
295