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