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