xref: /PHP-7.2/ext/gd/libgd/gd_png.c (revision 432e16cb)
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "gd_errors.h"
7 
8 /* JCE: Arrange HAVE_LIBPNG so that it can be set in gd.h */
9 #ifdef HAVE_LIBPNG
10 
11 #include "png.h"		/* includes zlib.h and setjmp.h */
12 #include "gdhelpers.h"
13 
14 #define TRUE 1
15 #define FALSE 0
16 
17 /*---------------------------------------------------------------------------
18 
19     gd_png.c                 Copyright 1999 Greg Roelofs and Thomas Boutell
20 
21     The routines in this file, gdImagePng*() and gdImageCreateFromPng*(),
22     are drop-in replacements for gdImageGif*() and gdImageCreateFromGif*(),
23     except that these functions are noisier in the case of errors (comment
24     out all fprintf() statements to disable that).
25 
26     GD 2.0 supports RGBA truecolor and will read and write truecolor PNGs.
27     GD 2.0 supports 8 bits of color resolution per channel and
28     7 bits of alpha channel resolution. Images with more than 8 bits
29     per channel are reduced to 8 bits. Images with an alpha channel are
30     only able to resolve down to '1/128th opaque' instead of '1/256th',
31     and this conversion is also automatic. I very much doubt you can see it.
32     Both tRNS and true alpha are supported.
33 
34     Gamma is ignored, and there is no support for text annotations.
35 
36     Last updated:  9 February 2001
37 
38   ---------------------------------------------------------------------------*/
39 
gdPngGetVersionString()40 const char * gdPngGetVersionString()
41 {
42 	return PNG_LIBPNG_VER_STRING;
43 }
44 
45 #ifdef PNG_SETJMP_SUPPORTED
46 typedef struct _jmpbuf_wrapper
47 {
48 	jmp_buf jmpbuf;
49 } jmpbuf_wrapper;
50 
gdPngErrorHandler(png_structp png_ptr,png_const_charp msg)51 static void gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
52 {
53 	jmpbuf_wrapper *jmpbuf_ptr;
54 
55 	/* This function, aside from the extra step of retrieving the "error
56 	 * pointer" (below) and the fact that it exists within the application
57 	 * rather than within libpng, is essentially identical to libpng's
58 	 * default error handler.  The second point is critical:  since both
59 	 * setjmp() and longjmp() are called from the same code, they are
60 	 * guaranteed to have compatible notions of how big a jmp_buf is,
61 	 * regardless of whether _BSD_SOURCE or anything else has (or has not)
62 	 * been defined.
63 	 */
64 
65 	gd_error_ex(GD_WARNING, "gd-png:  fatal libpng error: %s", msg);
66 
67 	jmpbuf_ptr = png_get_error_ptr (png_ptr);
68 	if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
69 		gd_error_ex(GD_ERROR, "gd-png:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
70 	}
71 
72 	longjmp (jmpbuf_ptr->jmpbuf, 1);
73 }
74 #endif
75 
gdPngReadData(png_structp png_ptr,png_bytep data,png_size_t length)76 static void gdPngReadData (png_structp png_ptr, png_bytep data, png_size_t length)
77 {
78 	int check;
79 	check = gdGetBuf(data, length, (gdIOCtx *) png_get_io_ptr(png_ptr));
80 	if (check != length) {
81 		png_error(png_ptr, "Read Error: truncated data");
82 	}
83 }
84 
gdPngWriteData(png_structp png_ptr,png_bytep data,png_size_t length)85 static void gdPngWriteData (png_structp png_ptr, png_bytep data, png_size_t length)
86 {
87 	gdPutBuf (data, length, (gdIOCtx *) png_get_io_ptr(png_ptr));
88 }
89 
gdPngFlushData(png_structp png_ptr)90 static void gdPngFlushData (png_structp png_ptr)
91 {
92 }
93 
gdImageCreateFromPng(FILE * inFile)94 gdImagePtr gdImageCreateFromPng (FILE * inFile)
95 {
96 	gdImagePtr im;
97 	gdIOCtx *in = gdNewFileCtx(inFile);
98 	im = gdImageCreateFromPngCtx(in);
99 	in->gd_free(in);
100 
101 	return im;
102 }
103 
gdImageCreateFromPngPtr(int size,void * data)104 gdImagePtr gdImageCreateFromPngPtr (int size, void *data)
105 {
106 	gdImagePtr im;
107 	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
108 	im = gdImageCreateFromPngCtx(in);
109 	in->gd_free(in);
110 	return im;
111 }
112 
113 /* This routine is based in part on the Chapter 13 demo code in "PNG: The
114  *  Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html).
115  */
gdImageCreateFromPngCtx(gdIOCtx * infile)116 gdImagePtr gdImageCreateFromPngCtx (gdIOCtx * infile)
117 {
118 	png_byte sig[8];
119 #ifdef PNG_SETJMP_SUPPORTED
120 	jmpbuf_wrapper jbw;
121 #endif
122 	png_structp png_ptr;
123 	png_infop info_ptr;
124 	png_uint_32 width, height, rowbytes, w, h, res_x, res_y;
125 	int bit_depth, color_type, interlace_type, unit_type;
126 	int num_palette, num_trans;
127 	png_colorp palette;
128 	png_color_16p trans_gray_rgb;
129 	png_color_16p trans_color_rgb;
130 	png_bytep trans;
131 	volatile png_bytep image_data = NULL;
132 	volatile png_bytepp row_pointers = NULL;
133 	gdImagePtr im = NULL;
134 	int i, j, *open = NULL;
135 	volatile int transparent = -1;
136 	volatile int palette_allocated = FALSE;
137 
138 
139 	/* Make sure the signature can't match by dumb luck -- TBB */
140 	/* GRR: isn't sizeof(infile) equal to the size of the pointer? */
141 	memset (sig, 0, sizeof(sig));
142 
143 	  /* first do a quick check that the file really is a PNG image; could
144 	   * have used slightly more general png_sig_cmp() function instead
145 	   */
146 	if (gdGetBuf(sig, 8, infile) < 8) {
147 		return NULL;
148 	}
149 
150 	if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */
151 		return NULL;
152 	}
153 
154 #ifdef PNG_SETJMP_SUPPORTED
155 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL);
156 #else
157 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
158 #endif
159 	if (png_ptr == NULL) {
160 		gd_error("gd-png error: cannot allocate libpng main struct");
161 		return NULL;
162 	}
163 
164 	info_ptr = png_create_info_struct(png_ptr);
165 	if (info_ptr == NULL) {
166 		gd_error("gd-png error: cannot allocate libpng info struct");
167 		png_destroy_read_struct (&png_ptr, NULL, NULL);
168 
169 		return NULL;
170 	}
171 
172 	/* we could create a second info struct here (end_info), but it's only
173 	 * useful if we want to keep pre- and post-IDAT chunk info separated
174 	 * (mainly for PNG-aware image editors and converters)
175 	 */
176 
177 	/* setjmp() must be called in every non-callback function that calls a
178 	 * PNG-reading libpng function
179 	 */
180 #ifdef PNG_SETJMP_SUPPORTED
181 	if (setjmp(jbw.jmpbuf)) {
182 		gd_error("gd-png error: setjmp returns error condition");
183 		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
184 
185 		return NULL;
186 	}
187 #endif
188 
189 	png_set_sig_bytes(png_ptr, 8);	/* we already read the 8 signature bytes */
190 
191 	png_set_read_fn(png_ptr, (void *) infile, gdPngReadData);
192 	png_read_info(png_ptr, info_ptr);	/* read all PNG info up to image data */
193 
194 	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
195 	if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
196 		|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
197 		im = gdImageCreateTrueColor((int) width, (int) height);
198 	} else {
199 		im = gdImageCreate((int) width, (int) height);
200 	}
201 	if (im == NULL) {
202 		gd_error("gd-png error: cannot allocate gdImage struct");
203 		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
204 
205 		return NULL;
206 	}
207 
208 	if (bit_depth == 16) {
209 		png_set_strip_16(png_ptr);
210 	} else if (bit_depth < 8) {
211 		png_set_packing (png_ptr); /* expand to 1 byte per pixel */
212 	}
213 
214 	/* setjmp() must be called in every non-callback function that calls a
215 	 * PNG-reading libpng function
216 	 */
217 #ifdef PNG_SETJMP_SUPPORTED
218 	if (setjmp(jbw.jmpbuf)) {
219 		gd_error("gd-png error: setjmp returns error condition");
220 		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
221 		gdFree(image_data);
222 		gdFree(row_pointers);
223 		if (im) {
224 			gdImageDestroy(im);
225 		}
226 		return NULL;
227 	}
228 #endif
229 
230 #ifdef PNG_pHYs_SUPPORTED
231 	/* check if the resolution is specified */
232 	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
233 		if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) {
234 			switch (unit_type) {
235 			case PNG_RESOLUTION_METER:
236 				im->res_x = DPM2DPI(res_x);
237 				im->res_y = DPM2DPI(res_y);
238 				break;
239 			}
240 		}
241 	}
242 #endif
243 
244 	switch (color_type) {
245 		case PNG_COLOR_TYPE_PALETTE:
246 			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
247 #ifdef DEBUG
248 			gd_error("gd-png color_type is palette, colors: %d", num_palette);
249 #endif /* DEBUG */
250 			if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
251 				/* gd 2.0: we support this rather thoroughly now. Grab the
252 				 * first fully transparent entry, if any, as the value of
253 				 * the simple-transparency index, mostly for backwards
254 				 * binary compatibility. The alpha channel is where it's
255 				 * really at these days.
256 				 */
257 				int firstZero = 1;
258 				png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
259 				for (i = 0; i < num_trans; ++i) {
260 					im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
261 					if ((trans[i] == 0) && (firstZero)) {
262 						transparent = i;
263 						firstZero = 0;
264 					}
265 				}
266 			}
267 			break;
268 		case PNG_COLOR_TYPE_GRAY:
269 			/* create a fake palette and check for single-shade transparency */
270 			if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
271 				gd_error("gd-png error: cannot allocate gray palette");
272 				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
273 
274 				return NULL;
275 			}
276 			palette_allocated = TRUE;
277 			if (bit_depth < 8) {
278 				num_palette = 1 << bit_depth;
279 				for (i = 0; i < 256; ++i) {
280 					j = (255 * i) / (num_palette - 1);
281 					palette[i].red = palette[i].green = palette[i].blue = j;
282 				}
283 			} else {
284 				num_palette = 256;
285 				for (i = 0; i < 256; ++i) {
286 					palette[i].red = palette[i].green = palette[i].blue = i;
287 				}
288 			}
289 			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
290 				png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
291 				if (bit_depth == 16) {	/* png_set_strip_16() not yet in effect */
292 					transparent = trans_gray_rgb->gray >> 8;
293 				} else {
294 					transparent = trans_gray_rgb->gray;
295 				}
296 				/* Note slight error in 16-bit case:  up to 256 16-bit shades
297 				 * may get mapped to a single 8-bit shade, and only one of them
298 				 * is supposed to be transparent.  IOW, both opaque pixels and
299 				 * transparent pixels will be mapped into the transparent entry.
300 				 * There is no particularly good way around this in the case
301 				 * that all 256 8-bit shades are used, but one could write some
302 				 * custom 16-bit code to handle the case where there are gdFree
303 				 * palette entries.  This error will be extremely rare in
304 				 * general, though.  (Quite possibly there is only one such
305 				 * image in existence.)
306 				 */
307 			}
308 			break;
309 
310 		case PNG_COLOR_TYPE_GRAY_ALPHA:
311 			png_set_gray_to_rgb(png_ptr);
312 
313 			case PNG_COLOR_TYPE_RGB:
314 			case PNG_COLOR_TYPE_RGB_ALPHA:
315 				/* gd 2.0: we now support truecolor. See the comment above
316 				 * for a rare situation in which the transparent pixel may not
317 				 * work properly with 16-bit channels.
318 				 */
319 				if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
320 					png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
321 					if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
322 						transparent = gdTrueColor(trans_color_rgb->red >> 8,
323 									trans_color_rgb->green >> 8,
324 									trans_color_rgb->blue >> 8);
325 					} else {
326 						transparent = gdTrueColor(trans_color_rgb->red,
327 									trans_color_rgb->green,
328 									trans_color_rgb->blue);
329 					}
330 				}
331 				break;
332 	}
333 
334 	png_read_update_info(png_ptr, info_ptr);
335 
336 	/* allocate space for the PNG image data */
337 	rowbytes = png_get_rowbytes(png_ptr, info_ptr);
338 	image_data = (png_bytep) safe_emalloc(rowbytes, height, 0);
339 
340 	row_pointers = (png_bytepp) safe_emalloc(height, sizeof(png_bytep), 0);
341 
342 	/* set the individual row_pointers to point at the correct offsets */
343 	for (h = 0; h < height; ++h) {
344 		row_pointers[h] = image_data + h * rowbytes;
345 	}
346 
347 	png_read_image(png_ptr, row_pointers);	/* read whole image... */
348 	png_read_end(png_ptr, NULL);		/* ...done! */
349 
350 	if (!im->trueColor) {
351 		im->colorsTotal = num_palette;
352 		/* load the palette and mark all entries "open" (unused) for now */
353 		open = im->open;
354 		for (i = 0; i < num_palette; ++i) {
355 			im->red[i] = palette[i].red;
356 			im->green[i] = palette[i].green;
357 			im->blue[i] = palette[i].blue;
358 			open[i] = 1;
359 		}
360 		for (i = num_palette; i < gdMaxColors; ++i) {
361 			open[i] = 1;
362 		}
363 	}
364 
365 	/* 2.0.12: Slaven Rezic: palette images are not the only images
366 	 * with a simple transparent color setting.
367 	 */
368 	im->transparent = transparent;
369 	im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
370 
371 	/* can't nuke structs until done with palette */
372 	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
373 	switch (color_type) {
374 		case PNG_COLOR_TYPE_RGB:
375 			for (h = 0; h < height; h++) {
376 				int boffset = 0;
377 				for (w = 0; w < width; w++) {
378 					register png_byte r = row_pointers[h][boffset++];
379 					register png_byte g = row_pointers[h][boffset++];
380 					register png_byte b = row_pointers[h][boffset++];
381 					im->tpixels[h][w] = gdTrueColor (r, g, b);
382 				}
383 			}
384 			break;
385 
386 		case PNG_COLOR_TYPE_GRAY_ALPHA:
387 		case PNG_COLOR_TYPE_RGB_ALPHA:
388 			for (h = 0; h < height; h++) {
389 				int boffset = 0;
390 				for (w = 0; w < width; w++) {
391 					register png_byte r = row_pointers[h][boffset++];
392 					register png_byte g = row_pointers[h][boffset++];
393 					register png_byte b = row_pointers[h][boffset++];
394 
395 					/* gd has only 7 bits of alpha channel resolution, and
396 					 * 127 is transparent, 0 opaque. A moment of convenience,
397 					 *  a lifetime of compatibility.
398 					 */
399 
400 					register png_byte a = gdAlphaMax - (row_pointers[h][boffset++] >> 1);
401 					im->tpixels[h][w] = gdTrueColorAlpha(r, g, b, a);
402 				}
403 			}
404 			break;
405 
406 		default:
407 			/* Palette image, or something coerced to be one */
408 			for (h = 0; h < height; ++h) {
409 				for (w = 0; w < width; ++w) {
410 					register png_byte idx = row_pointers[h][w];
411 					im->pixels[h][w] = idx;
412 					open[idx] = 0;
413 				}
414 			}
415 	}
416 #ifdef DEBUG
417 	if (!im->trueColor) {
418 		for (i = num_palette; i < gdMaxColors; ++i) {
419 			if (!open[i]) {
420 				gd_error("gd-png warning: image data references out-of-range color index (%d)", i);
421 			}
422 		}
423 	}
424 #endif
425 
426 	if (palette_allocated) {
427 		gdFree(palette);
428 	}
429 	gdFree(image_data);
430 	gdFree(row_pointers);
431 
432 	return im;
433 }
434 
gdImagePngEx(gdImagePtr im,FILE * outFile,int level,int basefilter)435 void gdImagePngEx (gdImagePtr im, FILE * outFile, int level, int basefilter)
436 {
437 	gdIOCtx *out = gdNewFileCtx(outFile);
438 	gdImagePngCtxEx(im, out, level, basefilter);
439 	out->gd_free(out);
440 }
441 
gdImagePng(gdImagePtr im,FILE * outFile)442 void gdImagePng (gdImagePtr im, FILE * outFile)
443 {
444 	gdIOCtx *out = gdNewFileCtx(outFile);
445   	gdImagePngCtxEx(im, out, -1, -1);
446 	out->gd_free(out);
447 }
448 
gdImagePngPtr(gdImagePtr im,int * size)449 void * gdImagePngPtr (gdImagePtr im, int *size)
450 {
451 	void *rv;
452 	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
453 	gdImagePngCtxEx(im, out, -1, -1);
454 	rv = gdDPExtractData(out, size);
455 	out->gd_free(out);
456 
457 	return rv;
458 }
459 
gdImagePngPtrEx(gdImagePtr im,int * size,int level,int basefilter)460 void * gdImagePngPtrEx (gdImagePtr im, int *size, int level, int basefilter)
461 {
462 	void *rv;
463 	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
464 	gdImagePngCtxEx(im, out, level, basefilter);
465 	rv = gdDPExtractData(out, size);
466 	out->gd_free(out);
467 	return rv;
468 }
469 
gdImagePngCtx(gdImagePtr im,gdIOCtx * outfile)470 void gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
471 {
472 	gdImagePngCtxEx(im, outfile, -1, -1);
473 }
474 
475 /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
476  *  and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
477  *  (http://www.cdrom.com/pub/png/pngbook.html).
478  */
gdImagePngCtxEx(gdImagePtr im,gdIOCtx * outfile,int level,int basefilter)479 void gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level, int basefilter)
480 {
481 	int i, j, bit_depth = 0, interlace_type;
482 	int width = im->sx;
483 	int height = im->sy;
484 	int colors = im->colorsTotal;
485 	int *open = im->open;
486 	int mapping[gdMaxColors];	/* mapping[gd_index] == png_index */
487 	png_byte trans_values[256];
488 	png_color_16 trans_rgb_value;
489 	png_color palette[gdMaxColors];
490 	png_structp png_ptr;
491 	png_infop info_ptr;
492 	volatile int transparent = im->transparent;
493 	volatile int remap = FALSE;
494 #ifdef PNG_SETJMP_SUPPORTED
495 	jmpbuf_wrapper jbw;
496 
497 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL);
498 #else
499 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
500 #endif
501 	if (png_ptr == NULL) {
502 		gd_error("gd-png error: cannot allocate libpng main struct");
503 		return;
504 	}
505 
506 	info_ptr = png_create_info_struct(png_ptr);
507 	if (info_ptr == NULL) {
508 		gd_error("gd-png error: cannot allocate libpng info struct");
509 		png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
510 
511 		return;
512     }
513 
514 #ifdef PNG_SETJMP_SUPPORTED
515 	if (setjmp(jbw.jmpbuf)) {
516 		gd_error("gd-png error: setjmp returns error condition");
517 		png_destroy_write_struct (&png_ptr, &info_ptr);
518 
519 		return;
520 	}
521 #endif
522 
523 	png_set_write_fn(png_ptr, (void *) outfile, gdPngWriteData, gdPngFlushData);
524 
525 	/* This is best for palette images, and libpng defaults to it for
526 	 * palette images anyway, so we don't need to do it explicitly.
527 	 * What to ideally do for truecolor images depends, alas, on the image.
528 	 * gd is intentionally imperfect and doesn't spend a lot of time
529 	 * fussing with such things.
530 	 */
531 
532 	/*  png_set_filter(png_ptr, 0, PNG_FILTER_NONE);  */
533 
534 	/* 2.0.12: this is finally a parameter */
535 	if (level != -1 && (level < 0 || level > 9)) {
536 		gd_error("gd-png error: compression level must be 0 through 9");
537 		return;
538 	}
539 	png_set_compression_level(png_ptr, level);
540 	if (basefilter >= 0) {
541 		png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, basefilter);
542 	}
543 
544 #ifdef PNG_pHYs_SUPPORTED
545 	/* 2.1.0: specify the resolution */
546 	png_set_pHYs(png_ptr, info_ptr, DPI2DPM(im->res_x), DPI2DPM(im->res_y),
547 	             PNG_RESOLUTION_METER);
548 #endif
549 
550 	/* can set this to a smaller value without compromising compression if all
551 	 * image data is 16K or less; will save some decoder memory [min == 8]
552 	 */
553 
554 	/*  png_set_compression_window_bits(png_ptr, 15);  */
555 
556 	if (!im->trueColor) {
557 		if (transparent >= im->colorsTotal || (transparent >= 0 && open[transparent])) {
558 			transparent = -1;
559 		}
560 
561 		for (i = 0; i < gdMaxColors; ++i) {
562 			mapping[i] = -1;
563 		}
564 
565 		/* count actual number of colors used (colorsTotal == high-water mark) */
566 		colors = 0;
567 		for (i = 0; i < im->colorsTotal; ++i) {
568 			if (!open[i]) {
569 				mapping[i] = colors;
570 				++colors;
571 			}
572 		}
573 		if (colors == 0) {
574 			gd_error("gd-png error: no colors in palette");
575 			goto bail;
576 		}
577 		if (colors < im->colorsTotal) {
578 			remap = TRUE;
579 		}
580 		if (colors <= 2) {
581 			bit_depth = 1;
582 		} else if (colors <= 4) {
583 			bit_depth = 2;
584 		} else if (colors <= 16) {
585 			bit_depth = 4;
586 		} else {
587 			bit_depth = 8;
588 		}
589 	}
590 
591 	interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
592 
593 	if (im->trueColor) {
594 		if (im->saveAlphaFlag) {
595 			png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
596 					PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
597 		} else {
598 			png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, interlace_type,
599 					PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
600 		}
601 	} else {
602 		png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type,
603 			PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
604 	}
605 
606 	if (im->trueColor && !im->saveAlphaFlag && (transparent >= 0)) {
607 		/* 2.0.9: fixed by Thomas Winzig */
608 		trans_rgb_value.red = gdTrueColorGetRed (im->transparent);
609 		trans_rgb_value.green = gdTrueColorGetGreen (im->transparent);
610 		trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent);
611 		png_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value);
612 	}
613 
614 	if (!im->trueColor) {
615 		/* Oy veh. Remap the PNG palette to put the entries with interesting alpha channel
616 		 * values first. This minimizes the size of the tRNS chunk and thus the size
617 		 * of the PNG file as a whole.
618 		 */
619 
620 		int tc = 0;
621 		int i;
622 		int j;
623 		int k;
624 
625 		for (i = 0; (i < im->colorsTotal); i++) {
626 			if ((!im->open[i]) && (im->alpha[i] != gdAlphaOpaque)) {
627 				tc++;
628 			}
629 		}
630 		if (tc) {
631 #if 0
632 			for (i = 0; (i < im->colorsTotal); i++) {
633 				trans_values[i] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
634 			}
635 			png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);
636 #endif
637 			if (!remap) {
638 				remap = TRUE;
639 			}
640 
641 			/* (Semi-)transparent indexes come up from the bottom of the list of real colors; opaque
642 			 * indexes come down from the top
643 			 */
644 			j = 0;
645 			k = colors - 1;
646 
647 			for (i = 0; i < im->colorsTotal; i++) {
648 				if (!im->open[i]) {
649 					if (im->alpha[i] != gdAlphaOpaque) {
650 						/* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
651 						trans_values[j] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
652 						mapping[i] = j++;
653 					} else {
654 						mapping[i] = k--;
655 					}
656 				}
657 			}
658 			png_set_tRNS(png_ptr, info_ptr, trans_values, tc, NULL);
659 		}
660 	}
661 
662 	/* convert palette to libpng layout */
663 	if (!im->trueColor) {
664 		if (remap) {
665 			for (i = 0; i < im->colorsTotal; ++i) {
666 				if (mapping[i] < 0) {
667 					continue;
668 				}
669 
670 				palette[mapping[i]].red = im->red[i];
671 				palette[mapping[i]].green = im->green[i];
672 				palette[mapping[i]].blue = im->blue[i];
673 			}
674 		} else {
675 			for (i = 0; i < colors; ++i) {
676 				palette[i].red = im->red[i];
677 				palette[i].green = im->green[i];
678 				palette[i].blue = im->blue[i];
679 			}
680 		}
681 		png_set_PLTE(png_ptr, info_ptr, palette, colors);
682 	}
683 
684 	/* write out the PNG header info (everything up to first IDAT) */
685 	png_write_info(png_ptr, info_ptr);
686 
687 	/* make sure < 8-bit images are packed into pixels as tightly as possible */
688 	png_set_packing(png_ptr);
689 
690 	/* This code allocates a set of row buffers and copies the gd image data
691 	 * into them only in the case that remapping is necessary; in gd 1.3 and
692 	 * later, the im->pixels array is laid out identically to libpng's row
693 	 * pointers and can be passed to png_write_image() function directly.
694 	 * The remapping case could be accomplished with less memory for non-
695 	 * interlaced images, but interlacing causes some serious complications.
696 	 */
697 
698 	if (im->trueColor) {
699 		/* performance optimizations by Phong Tran */
700 		int channels = im->saveAlphaFlag ? 4 : 3;
701 		/* Our little 7-bit alpha channel trick costs us a bit here. */
702 		png_bytep *row_pointers;
703 		unsigned char* pOutputRow;
704 		int **ptpixels = im->tpixels;
705 		int *pThisRow;
706 		unsigned char a;
707 		int thisPixel;
708 		png_bytep *prow_pointers;
709 		int saveAlphaFlag = im->saveAlphaFlag;
710 
711 		row_pointers = safe_emalloc(sizeof(png_bytep), height, 0);
712 		prow_pointers = row_pointers;
713 		for (j = 0; j < height; ++j) {
714 			*prow_pointers = (png_bytep) safe_emalloc(width, channels, 0);
715 			pOutputRow = *prow_pointers++;
716 			pThisRow = *ptpixels++;
717 			for (i = 0; i < width; ++i) {
718 				thisPixel = *pThisRow++;
719 				*pOutputRow++ = gdTrueColorGetRed(thisPixel);
720 				*pOutputRow++ = gdTrueColorGetGreen(thisPixel);
721 				*pOutputRow++ = gdTrueColorGetBlue(thisPixel);
722 				if (saveAlphaFlag) {
723 					/* convert the 7-bit alpha channel to an 8-bit alpha channel.
724 					 * We do a little bit-flipping magic, repeating the MSB
725 					 * as the LSB, to ensure that 0 maps to 0 and
726 					 * 127 maps to 255. We also have to invert to match
727 					 * PNG's convention in which 255 is opaque.
728 					 */
729 					a = gdTrueColorGetAlpha(thisPixel);
730 					/* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
731 					if (a == 127) {
732 						*pOutputRow++ = 0;
733 					} else {
734 						*pOutputRow++ = 255 - ((a << 1) + (a >> 6));
735 					}
736 
737 				}
738 			}
739 		}
740 
741 		png_write_image(png_ptr, row_pointers);
742 		png_write_end(png_ptr, info_ptr);
743 
744 		for (j = 0; j < height; ++j) {
745 			gdFree(row_pointers[j]);
746 		}
747 
748 		gdFree(row_pointers);
749 	} else {
750 		if (remap) {
751 			png_bytep *row_pointers;
752 			row_pointers = safe_emalloc(height, sizeof(png_bytep), 0);
753 			for (j = 0; j < height; ++j) {
754 				row_pointers[j] = (png_bytep) gdMalloc(width);
755 				for (i = 0; i < width; ++i) {
756 					row_pointers[j][i] = mapping[im->pixels[j][i]];
757 				}
758 			}
759 
760 			png_write_image(png_ptr, row_pointers);
761 			png_write_end(png_ptr, info_ptr);
762 
763 			for (j = 0; j < height; ++j) {
764 				gdFree(row_pointers[j]);
765 			}
766 
767 			gdFree(row_pointers);
768 		} else {
769 			png_write_image(png_ptr, im->pixels);
770 			png_write_end(png_ptr, info_ptr);
771 		}
772 	}
773 	/* 1.6.3: maybe we should give that memory BACK! TBB */
774  bail:
775 	png_destroy_write_struct(&png_ptr, &info_ptr);
776 }
777 
778 #endif /* HAVE_LIBPNG */
779