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