1 /*
2 * JPEG image routines for CUPS.
3 *
4 * Copyright 2007-2011 by Apple Inc.
5 * Copyright 1993-2007 by Easy Software Products.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "COPYING"
10 * which should have been included with this file.
11 *
12 * Contents:
13 *
14 * _cupsImageReadJPEG() - Read a JPEG image file.
15 */
16
17 /*
18 * Include necessary headers...
19 */
20
21 #include "image-private.h"
22
23 #ifdef HAVE_LIBJPEG
24 # include <jpeglib.h> /* JPEG/JFIF image definitions */
25
26 #define JPEG_APP0 0xE0 /* APP0 marker code */
27
28 /*
29 * '_cupsImageReadJPEG()' - Read a JPEG image file.
30 */
31
32 int /* O - Read status */
_cupsImageReadJPEG( cups_image_t *img, FILE *fp, cups_icspace_t primary, cups_icspace_t secondary, int saturation, int hue, const cups_ib_t *lut)33 _cupsImageReadJPEG(
34 cups_image_t *img, /* IO - cupsImage */
35 FILE *fp, /* I - cupsImage file */
36 cups_icspace_t primary, /* I - Primary choice for colorspace */
37 cups_icspace_t secondary, /* I - Secondary choice for colorspace */
38 int saturation, /* I - Color saturation (%) */
39 int hue, /* I - Color hue (degrees) */
40 const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
41 {
42 struct jpeg_decompress_struct cinfo; /* Decompressor info */
43 struct jpeg_error_mgr jerr; /* Error handler info */
44 cups_ib_t *in, /* Input pixels */
45 *out; /* Output pixels */
46 jpeg_saved_marker_ptr marker; /* Pointer to marker data */
47 int psjpeg = 0; /* Non-zero if Photoshop CMYK JPEG */
48 static const char *cspaces[] =
49 { /* JPEG colorspaces... */
50 "JCS_UNKNOWN",
51 "JCS_GRAYSCALE",
52 "JCS_RGB",
53 "JCS_YCbCr",
54 "JCS_CMYK",
55 "JCS_YCCK"
56 };
57
58
59 /*
60 * Read the JPEG header...
61 */
62
63 cinfo.err = jpeg_std_error(&jerr);
64 jpeg_create_decompress(&cinfo);
65 jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 0xffff); /* Adobe JPEG */
66 jpeg_stdio_src(&cinfo, fp);
67 jpeg_read_header(&cinfo, 1);
68
69 /*
70 * Parse any Adobe APPE data embedded in the JPEG file. Since Adobe doesn't
71 * bother following standards, we have to invert the CMYK JPEG data written by
72 * Adobe apps...
73 */
74
75 for (marker = cinfo.marker_list; marker; marker = marker->next)
76 if (marker->marker == (JPEG_APP0 + 14) && marker->data_length >= 12 &&
77 !memcmp(marker->data, "Adobe", 5))
78 {
79 fputs("DEBUG: Adobe CMYK JPEG detected (inverting color values)\n",
80 stderr);
81 psjpeg = 1;
82 }
83
84 cinfo.quantize_colors = 0;
85
86 fprintf(stderr, "DEBUG: num_components = %d\n", cinfo.num_components);
87 fprintf(stderr, "DEBUG: jpeg_color_space = %s\n",
88 cspaces[cinfo.jpeg_color_space]);
89
90 if (cinfo.num_components == 1)
91 {
92 fputs("DEBUG: Converting image to grayscale...\n", stderr);
93
94 cinfo.out_color_space = JCS_GRAYSCALE;
95 cinfo.out_color_components = 1;
96 cinfo.output_components = 1;
97
98 img->colorspace = secondary;
99 }
100 else if (cinfo.num_components == 4)
101 {
102 fputs("DEBUG: Converting image to CMYK...\n", stderr);
103
104 cinfo.out_color_space = JCS_CMYK;
105 cinfo.out_color_components = 4;
106 cinfo.output_components = 4;
107
108 img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_CMYK : primary;
109 }
110 else
111 {
112 fputs("DEBUG: Converting image to RGB...\n", stderr);
113
114 cinfo.out_color_space = JCS_RGB;
115 cinfo.out_color_components = 3;
116 cinfo.output_components = 3;
117
118 img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
119 }
120
121 jpeg_calc_output_dimensions(&cinfo);
122
123 if (cinfo.output_width <= 0 || cinfo.output_width > CUPS_IMAGE_MAX_WIDTH ||
124 cinfo.output_height <= 0 || cinfo.output_height > CUPS_IMAGE_MAX_HEIGHT)
125 {
126 fprintf(stderr, "DEBUG: Bad JPEG dimensions %dx%d!\n",
127 cinfo.output_width, cinfo.output_height);
128
129 jpeg_destroy_decompress(&cinfo);
130
131 fclose(fp);
132 return (1);
133 }
134
135 img->xsize = cinfo.output_width;
136 img->ysize = cinfo.output_height;
137
138 int temp = -1;
139
140 #ifdef HAVE_EXIF
141 /*
142 scan image file for exif data
143 */
144
145 temp = _cupsImageReadEXIF(img, fp);
146 #endif
147 /*
148 check headers only if EXIF contains no info about ppi
149 */
150
151 if (temp != 1 && cinfo.X_density > 0 && cinfo.Y_density > 0 && cinfo.density_unit > 0)
152 {
153 if (cinfo.density_unit == 1)
154 {
155 img->xppi = cinfo.X_density;
156 img->yppi = cinfo.Y_density;
157 }
158 else
159 {
160 img->xppi = (int)((float)cinfo.X_density * 2.54);
161 img->yppi = (int)((float)cinfo.Y_density * 2.54);
162 }
163
164 if (img->xppi == 0 || img->yppi == 0)
165 {
166 fprintf(stderr, "DEBUG: Bad JPEG image resolution %dx%d PPI.\n",
167 img->xppi, img->yppi);
168 img->xppi = img->yppi = 200;
169 }
170 }
171
172 fprintf(stderr, "DEBUG: JPEG image %dx%dx%d, %dx%d PPI\n",
173 img->xsize, img->ysize, cinfo.output_components,
174 img->xppi, img->yppi);
175
176 cupsImageSetMaxTiles(img, 0);
177
178 in = malloc(img->xsize * cinfo.output_components);
179 out = malloc(img->xsize * cupsImageGetDepth(img));
180
181 jpeg_start_decompress(&cinfo);
182
183 while (cinfo.output_scanline < cinfo.output_height)
184 {
185 jpeg_read_scanlines(&cinfo, (JSAMPROW *)&in, (JDIMENSION)1);
186
187 if (psjpeg && cinfo.output_components == 4)
188 {
189 /*
190 * Invert CMYK data from Photoshop...
191 */
192
193 cups_ib_t *ptr; /* Pointer into buffer */
194 int i; /* Looping var */
195
196
197 for (ptr = in, i = img->xsize * 4; i > 0; i --, ptr ++)
198 *ptr = 255 - *ptr;
199 }
200
201 if ((saturation != 100 || hue != 0) && cinfo.output_components == 3)
202 cupsImageRGBAdjust(in, img->xsize, saturation, hue);
203
204 if ((img->colorspace == CUPS_IMAGE_WHITE && cinfo.out_color_space == JCS_GRAYSCALE) ||
205 (img->colorspace == CUPS_IMAGE_CMYK && cinfo.out_color_space == JCS_CMYK))
206 {
207 #ifdef DEBUG
208 int i, j;
209 cups_ib_t *ptr;
210
211
212 fputs("DEBUG: Direct Data...\n", stderr);
213
214 fputs("DEBUG:", stderr);
215
216 for (i = 0, ptr = in; i < img->xsize; i ++)
217 {
218 putc(' ', stderr);
219 for (j = 0; j < cinfo.output_components; j ++, ptr ++)
220 fprintf(stderr, "%02X", *ptr & 255);
221 }
222
223 putc('\n', stderr);
224 #endif /* DEBUG */
225
226 if (lut)
227 cupsImageLut(in, img->xsize * cupsImageGetDepth(img), lut);
228
229 _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, in);
230 }
231 else if (cinfo.out_color_space == JCS_GRAYSCALE)
232 {
233 switch (img->colorspace)
234 {
235 default :
236 break;
237
238 case CUPS_IMAGE_BLACK :
239 cupsImageWhiteToBlack(in, out, img->xsize);
240 break;
241 case CUPS_IMAGE_RGB :
242 cupsImageWhiteToRGB(in, out, img->xsize);
243 break;
244 case CUPS_IMAGE_CMY :
245 cupsImageWhiteToCMY(in, out, img->xsize);
246 break;
247 case CUPS_IMAGE_CMYK :
248 cupsImageWhiteToCMYK(in, out, img->xsize);
249 break;
250 }
251
252 if (lut)
253 cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
254
255 _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
256 }
257 else if (cinfo.out_color_space == JCS_RGB)
258 {
259 switch (img->colorspace)
260 {
261 default :
262 break;
263
264 case CUPS_IMAGE_RGB :
265 cupsImageRGBToRGB(in, out, img->xsize);
266 break;
267 case CUPS_IMAGE_WHITE :
268 cupsImageRGBToWhite(in, out, img->xsize);
269 break;
270 case CUPS_IMAGE_BLACK :
271 cupsImageRGBToBlack(in, out, img->xsize);
272 break;
273 case CUPS_IMAGE_CMY :
274 cupsImageRGBToCMY(in, out, img->xsize);
275 break;
276 case CUPS_IMAGE_CMYK :
277 cupsImageRGBToCMYK(in, out, img->xsize);
278 break;
279 }
280
281 if (lut)
282 cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
283
284 _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
285 }
286 else /* JCS_CMYK */
287 {
288 fputs("DEBUG: JCS_CMYK\n", stderr);
289
290 switch (img->colorspace)
291 {
292 default :
293 break;
294
295 case CUPS_IMAGE_WHITE :
296 cupsImageCMYKToWhite(in, out, img->xsize);
297 break;
298 case CUPS_IMAGE_BLACK :
299 cupsImageCMYKToBlack(in, out, img->xsize);
300 break;
301 case CUPS_IMAGE_CMY :
302 cupsImageCMYKToCMY(in, out, img->xsize);
303 break;
304 case CUPS_IMAGE_RGB :
305 cupsImageCMYKToRGB(in, out, img->xsize);
306 break;
307 }
308
309 if (lut)
310 cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
311
312 _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
313 }
314 }
315
316 free(in);
317 free(out);
318
319 jpeg_finish_decompress(&cinfo);
320 jpeg_destroy_decompress(&cinfo);
321
322 fclose(fp);
323
324 return (0);
325 }
326 #endif /* HAVE_LIBJPEG */
327
328