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