Revert manifest to default one
[external/cups.git] / filter / image-png.c
1 /*
2  * "$Id: image-png.c 9771 2011-05-12 05:21:56Z mike $"
3  *
4  *   PNG 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  *   _cupsImageReadPNG() - Read a PNG image file.
20  */
21
22 /*
23  * Include necessary headers...
24  */
25
26 #include "image-private.h"
27
28 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
29 #  include <png.h>      /* Portable Network Graphics (PNG) definitions */
30
31
32 /*
33  * '_cupsImageReadPNG()' - Read a PNG image file.
34  */
35
36 int                                     /* O - Read status */
37 _cupsImageReadPNG(
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   int           y;                      /* Looping var */
47   png_structp   pp;                     /* PNG read pointer */
48   png_infop     info;                   /* PNG info pointers */
49   png_uint_32   width,                  /* Width of image */
50                 height;                 /* Height of image */
51   int           bit_depth,              /* Bit depth */
52                 color_type,             /* Color type */
53                 interlace_type,         /* Interlace type */
54                 compression_type,       /* Compression type */
55                 filter_type;            /* Filter type */
56   png_uint_32   xppm,                   /* X pixels per meter */
57                 yppm;                   /* Y pixels per meter */
58   int           bpp;                    /* Bytes per pixel */
59   int           pass,                   /* Current pass */
60                 passes;                 /* Number of passes required */
61   cups_ib_t     *in,                    /* Input pixels */
62                 *inptr,                 /* Pointer into pixels */
63                 *out;                   /* Output pixels */
64   png_color_16  bg;                     /* Background color */
65
66
67  /*
68   * Setup the PNG data structures...
69   */
70
71   pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
72   info = png_create_info_struct(pp);
73
74  /*
75   * Initialize the PNG read "engine"...
76   */
77
78   png_init_io(pp, fp);
79
80  /*
81   * Get the image dimensions and load the output image...
82   */
83
84   png_read_info(pp, info);
85
86   png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type,
87                &interlace_type, &compression_type, &filter_type);
88
89   fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
90           (int)width, (int)height, bit_depth, color_type,
91           (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
92           (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
93           (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");
94
95   if (color_type & PNG_COLOR_MASK_PALETTE)
96     png_set_expand(pp);
97   else if (bit_depth < 8)
98   {
99     png_set_packing(pp);
100     png_set_expand(pp);
101   }
102   else if (bit_depth == 16)
103     png_set_strip_16(pp);
104
105   if (color_type & PNG_COLOR_MASK_COLOR)
106     img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB :
107                                                          primary;
108   else
109     img->colorspace = secondary;
110
111   if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH ||
112       height == 0 || height > CUPS_IMAGE_MAX_HEIGHT)
113   {
114     fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n",
115             (unsigned)width, (unsigned)height);
116     fclose(fp);
117     return (1);
118   }
119
120   img->xsize = width;
121   img->ysize = height;
122
123   if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 &&
124       (yppm = png_get_y_pixels_per_meter(pp, info)) != 0)
125   {
126     img->xppi = (int)((float)xppm * 0.0254);
127     img->yppi = (int)((float)yppm * 0.0254);
128
129     if (img->xppi == 0 || img->yppi == 0)
130     {
131       fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n",
132               img->xppi, img->yppi);
133
134       img->xppi = img->yppi = 128;
135     }
136   }
137
138   cupsImageSetMaxTiles(img, 0);
139
140   passes = png_set_interlace_handling(pp);
141
142  /*
143   * Handle transparency...
144   */
145
146   if (png_get_valid(pp, info, PNG_INFO_tRNS))
147     png_set_tRNS_to_alpha(pp);
148
149   bg.red   = 65535;
150   bg.green = 65535;
151   bg.blue  = 65535;
152
153   png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
154
155   if (passes == 1)
156   {
157    /*
158     * Load one row at a time...
159     */
160
161     if (color_type == PNG_COLOR_TYPE_GRAY ||
162         color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
163       in = malloc(img->xsize);
164     else
165       in = malloc(img->xsize * 3);
166   }
167   else
168   {
169    /*
170     * Interlaced images must be loaded all at once...
171     */
172
173     size_t bufsize;                     /* Size of buffer */
174
175
176     if (color_type == PNG_COLOR_TYPE_GRAY ||
177         color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
178     {
179       bufsize = img->xsize * img->ysize;
180
181       if ((bufsize / img->xsize) != img->ysize)
182       {
183         fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
184                 (unsigned)width, (unsigned)height);
185         fclose(fp);
186         return (1);
187       }
188     }
189     else
190     {
191       bufsize = img->xsize * img->ysize * 3;
192
193       if ((bufsize / (img->xsize * 3)) != img->ysize)
194       {
195         fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
196                 (unsigned)width, (unsigned)height);
197         fclose(fp);
198         return (1);
199       }
200     }
201
202     in = malloc(bufsize);
203   }
204
205   bpp = cupsImageGetDepth(img);
206   out = malloc(img->xsize * bpp);
207
208   if (!in || !out)
209   {
210     fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr);
211
212     if (in)
213       free(in);
214
215     if (out)
216       free(out);
217
218     fclose(fp);
219
220     return (1);
221   }
222
223  /*
224   * Read the image, interlacing as needed...
225   */
226
227   for (pass = 1; pass <= passes; pass ++)
228     for (inptr = in, y = 0; y < img->ysize; y ++)
229     {
230       png_read_row(pp, (png_bytep)inptr, NULL);
231
232       if (pass == passes)
233       {
234        /*
235         * Output this row...
236         */
237
238         if (color_type & PNG_COLOR_MASK_COLOR)
239         {
240           if ((saturation != 100 || hue != 0) && bpp > 1)
241             cupsImageRGBAdjust(inptr, img->xsize, saturation, hue);
242
243           switch (img->colorspace)
244           {
245             case CUPS_IMAGE_WHITE :
246                 cupsImageRGBToWhite(inptr, out, img->xsize);
247                 break;
248             case CUPS_IMAGE_RGB :
249             case CUPS_IMAGE_RGB_CMYK :
250                 cupsImageRGBToRGB(inptr, out, img->xsize);
251                 break;
252             case CUPS_IMAGE_BLACK :
253                 cupsImageRGBToBlack(inptr, out, img->xsize);
254                 break;
255             case CUPS_IMAGE_CMY :
256                 cupsImageRGBToCMY(inptr, out, img->xsize);
257                 break;
258             case CUPS_IMAGE_CMYK :
259                 cupsImageRGBToCMYK(inptr, out, img->xsize);
260                 break;
261           }
262         }
263         else
264         {
265           switch (img->colorspace)
266           {
267             case CUPS_IMAGE_WHITE :
268                 memcpy(out, inptr, img->xsize);
269                 break;
270             case CUPS_IMAGE_RGB :
271             case CUPS_IMAGE_RGB_CMYK :
272                 cupsImageWhiteToRGB(inptr, out, img->xsize);
273                 break;
274             case CUPS_IMAGE_BLACK :
275                 cupsImageWhiteToBlack(inptr, out, img->xsize);
276                 break;
277             case CUPS_IMAGE_CMY :
278                 cupsImageWhiteToCMY(inptr, out, img->xsize);
279                 break;
280             case CUPS_IMAGE_CMYK :
281                 cupsImageWhiteToCMYK(inptr, out, img->xsize);
282                 break;
283           }
284         }
285
286         if (lut)
287           cupsImageLut(out, img->xsize * bpp, lut);
288
289         _cupsImagePutRow(img, 0, y, img->xsize, out);
290       }
291
292       if (passes > 1)
293       {
294         if (color_type & PNG_COLOR_MASK_COLOR)
295           inptr += img->xsize * 3;
296         else
297           inptr += img->xsize;
298       }
299     }
300
301   png_read_end(pp, info);
302   png_destroy_read_struct(&pp, &info, NULL);
303
304   fclose(fp);
305   free(in);
306   free(out);
307
308   return (0);
309 }
310 #endif /* HAVE_LIBPNG && HAVE_LIBZ */
311
312
313 /*
314  * End of "$Id: image-png.c 9771 2011-05-12 05:21:56Z mike $".
315  */