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