"Fossies" - the Fresh Open Source Software Archive 
Member "libgd-2.3.3/src/gd_png.c" (11 Sep 2021, 33437 Bytes) of package /linux/www/libgd-2.3.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdio.h>
6 #include <math.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include "gd.h"
10 #include "gd_errors.h"
11
12 /* JCE: Arrange HAVE_LIBPNG so that it can be set in gd.h */
13 #ifdef HAVE_LIBPNG
14
15 #include "gdhelpers.h"
16 #include "png.h" /* includes zlib.h and setjmp.h */
17
18 #define TRUE 1
19 #define FALSE 0
20
21 /*---------------------------------------------------------------------------
22
23 gd_png.c Copyright 1999 Greg Roelofs and Thomas Boutell
24
25 The routines in this file, gdImagePng*() and gdImageCreateFromPng*(),
26 are drop-in replacements for gdImageGif*() and gdImageCreateFromGif*(),
27 except that these functions are noisier in the case of errors (comment
28 out all fprintf() statements to disable that).
29
30 GD 2.0 supports RGBA truecolor and will read and write truecolor PNGs.
31 GD 2.0 supports 8 bits of color resolution per channel and
32 7 bits of alpha channel resolution. Images with more than 8 bits
33 per channel are reduced to 8 bits. Images with an alpha channel are
34 only able to resolve down to '1/128th opaque' instead of '1/256th',
35 and this conversion is also automatic. I very much doubt you can see it.
36 Both tRNS and true alpha are supported.
37
38 Gamma is ignored, and there is no support for text annotations.
39
40 Last updated: 9 February 2001
41
42 ---------------------------------------------------------------------------*/
43
44 /**
45 * File: PNG IO
46 *
47 * Read and write PNG images.
48 */
49
50 #ifdef PNG_SETJMP_SUPPORTED
51 typedef struct _jmpbuf_wrapper {
52 jmp_buf jmpbuf;
53 }
54 jmpbuf_wrapper;
55
56 static void
57 gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
58 {
59 jmpbuf_wrapper *jmpbuf_ptr;
60
61 /* This function, aside from the extra step of retrieving the "error
62 * pointer" (below) and the fact that it exists within the application
63 * rather than within libpng, is essentially identical to libpng's
64 * default error handler. The second point is critical: since both
65 * setjmp() and longjmp() are called from the same code, they are
66 * guaranteed to have compatible notions of how big a jmp_buf is,
67 * regardless of whether _BSD_SOURCE or anything else has (or has not)
68 * been defined. */
69
70 gd_error_ex(GD_WARNING, "gd-png: fatal libpng error: %s\n", msg);
71
72 jmpbuf_ptr = png_get_error_ptr (png_ptr);
73 if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
74 gd_error_ex(GD_ERROR, "gd-png: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
75 exit (99);
76 }
77
78 longjmp (jmpbuf_ptr->jmpbuf, 1);
79 }
80 #endif
81
82 static void
83 gdPngReadData (png_structp png_ptr, png_bytep data, png_size_t length)
84 {
85 int check;
86 check = gdGetBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr));
87 if (check != (int)length) {
88 png_error(png_ptr, "Read Error: truncated data");
89 }
90 }
91
92 static void
93 gdPngWriteData (png_structp png_ptr, png_bytep data, png_size_t length)
94 {
95 gdPutBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr));
96 }
97
98 static void
99 gdPngFlushData (png_structp png_ptr)
100 {
101 (void)png_ptr;
102 }
103
104 /*
105 Function: gdImageCreateFromPng
106
107 <gdImageCreateFromPng> is called to load images from PNG format
108 files. Invoke <gdImageCreateFromPng> with an already opened
109 pointer to a FILE containing the desired
110 image. <gdImageCreateFromPng> returns a <gdImagePtr> to the new
111 image, or NULL if unable to load the image (most often because the
112 file is corrupt or does not contain a PNG
113 image). <gdImageCreateFromPng> does not close the file. You can
114 inspect the sx and sy members of the image to determine its
115 size. The image must eventually be destroyed using
116 gdImageDestroy().
117
118 If the PNG image being loaded is a truecolor image, the resulting
119 gdImagePtr will refer to a truecolor image. If the PNG image being
120 loaded is a palette or grayscale image, the resulting gdImagePtr
121 will refer to a palette image. gd retains only 8 bits of
122 resolution for each of the red, green and blue channels, and only
123 7 bits of resolution for the alpha channel. The former restriction
124 affects only a handful of very rare 48-bit color and 16-bit
125 grayscale PNG images. The second restriction affects all
126 semitransparent PNG images, but the difference is essentially
127 invisible to the eye. 7 bits of alpha channel resolution is, in
128 practice, quite a lot.
129
130 Variants:
131
132 <gdImageCreateFromPngPtr> creates an image from PNG data (i.e. the
133 contents of a PNG file) already in memory.
134
135 <gdImageCreateFromPngCtx> reads in an image using the functions in
136 a <gdIOCtx> struct.
137
138 <gdImageCreateFromPngSource> is similar to
139 <gdImageCreateFromPngCtx> but uses the old <gdSource> interface.
140 It is *obsolete*.
141
142 Parameters:
143
144 infile - The input FILE pointer.
145
146 Returns:
147
148 A pointer to the new image or NULL if an error occurred.
149
150 Example:
151 (start code)
152
153 gdImagePtr im;
154 ... inside a function ...
155 FILE *in;
156 in = fopen("mypng.png", "rb");
157 im = gdImageCreateFromPng(in);
158 fclose(in);
159 // ... Use the image ...
160 gdImageDestroy(im);
161
162 (end code)
163 */
164 BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * inFile)
165 {
166 gdImagePtr im;
167 gdIOCtx *in = gdNewFileCtx (inFile);
168 if (in == NULL) return NULL;
169 im = gdImageCreateFromPngCtx (in);
170 in->gd_free (in);
171 return im;
172 }
173
174 /*
175 Function: gdImageCreateFromPngPtr
176
177 See <gdImageCreateFromPng>.
178 */
179 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data)
180 {
181 gdImagePtr im;
182 gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
183 if(!in)
184 return 0;
185 im = gdImageCreateFromPngCtx (in);
186 in->gd_free (in);
187 return im;
188 }
189
190
191
192 /* This routine is based in part on the Chapter 13 demo code in
193 * "PNG: The Definitive Guide" (http://www.libpng.org/pub/png/book/).
194 */
195
196 /*
197 Function: gdImageCreateFromPngCtx
198
199 See <gdImageCreateFromPng>.
200 */
201 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile)
202 {
203 png_byte sig[8];
204 #ifdef PNG_SETJMP_SUPPORTED
205 jmpbuf_wrapper jbw;
206 #endif
207 png_structp png_ptr;
208 png_infop info_ptr;
209 png_uint_32 width, height, rowbytes, w, h, res_x, res_y;
210 int bit_depth, color_type, interlace_type, unit_type;
211 int num_palette = 0, num_trans;
212 png_colorp palette;
213 png_color_16p trans_gray_rgb;
214 png_color_16p trans_color_rgb;
215 png_bytep trans;
216 png_bytep image_data = NULL;
217 png_bytepp row_pointers = NULL;
218 gdImagePtr im = NULL;
219 int i, j, *open = NULL;
220 volatile int transparent = -1;
221 volatile int palette_allocated = FALSE;
222
223 /* Make sure the signature can't match by dumb luck -- TBB */
224 /* GRR: isn't sizeof(infile) equal to the size of the pointer? */
225 memset (sig, 0, sizeof (sig));
226
227 /* first do a quick check that the file really is a PNG image; could
228 * have used slightly more general png_sig_cmp() function instead */
229 if (gdGetBuf (sig, 8, infile) < 8) {
230 return NULL;
231 }
232
233 if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */
234 return NULL; /* bad signature */
235 }
236
237 #ifdef PNG_SETJMP_SUPPORTED
238 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL);
239 #else
240 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
241 #endif
242 if (png_ptr == NULL) {
243 gd_error("gd-png error: cannot allocate libpng main struct\n");
244 return NULL;
245 }
246
247 info_ptr = png_create_info_struct (png_ptr);
248 if (info_ptr == NULL) {
249 gd_error("gd-png error: cannot allocate libpng info struct\n");
250 png_destroy_read_struct (&png_ptr, NULL, NULL);
251
252 return NULL;
253 }
254
255 /* we could create a second info struct here (end_info), but it's only
256 * useful if we want to keep pre- and post-IDAT chunk info separated
257 * (mainly for PNG-aware image editors and converters)
258 */
259
260 /* setjmp() must be called in every non-callback function that calls a
261 * PNG-reading libpng function. We must reset it everytime we get a
262 * new allocation that we save in a stack variable.
263 */
264 #ifdef PNG_SETJMP_SUPPORTED
265 if (setjmp(jbw.jmpbuf)) {
266 gd_error("gd-png error: setjmp returns error condition 1\n");
267 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
268
269 return NULL;
270 }
271 #endif
272
273 png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
274
275 png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
276 png_read_info (png_ptr, info_ptr); /* read all PNG info up to image data */
277
278 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
279 if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
280 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
281 im = gdImageCreateTrueColor ((int) width, (int) height);
282 } else {
283 im = gdImageCreate ((int) width, (int) height);
284 }
285 if (im == NULL) {
286 gd_error("gd-png error: cannot allocate gdImage struct\n");
287 goto error;
288 }
289
290 if (bit_depth == 16) {
291 png_set_strip_16 (png_ptr);
292 } else if (bit_depth < 8) {
293 png_set_packing (png_ptr); /* expand to 1 byte per pixel */
294 }
295
296 /* setjmp() must be called in every non-callback function that calls a
297 * PNG-reading libpng function. We must reset it everytime we get a
298 * new allocation that we save in a stack variable.
299 */
300 #ifdef PNG_SETJMP_SUPPORTED
301 if (setjmp(jbw.jmpbuf)) {
302 gd_error("gd-png error: setjmp returns error condition 2\n");
303 goto error;
304 }
305 #endif
306
307 #ifdef PNG_pHYs_SUPPORTED
308 /* check if the resolution is specified */
309 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
310 if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) {
311 switch (unit_type) {
312 case PNG_RESOLUTION_METER:
313 im->res_x = DPM2DPI(res_x);
314 im->res_y = DPM2DPI(res_y);
315 break;
316 }
317 }
318 }
319 #endif
320
321 switch (color_type) {
322 case PNG_COLOR_TYPE_PALETTE:
323 png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
324 #ifdef DEBUG
325 gd_error("gd-png color_type is palette, colors: %d\n", num_palette);
326 #endif /* DEBUG */
327 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
328 /* gd 2.0: we support this rather thoroughly now. Grab the
329 * first fully transparent entry, if any, as the value of
330 * the simple-transparency index, mostly for backwards
331 * binary compatibility. The alpha channel is where it's
332 * really at these days.
333 */
334 int firstZero = 1;
335 png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL);
336 for (i = 0; i < num_trans; ++i) {
337 im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
338 if ((trans[i] == 0) && (firstZero)) {
339 /* 2.0.5: long-forgotten patch from Wez Furlong */
340 transparent = i;
341 firstZero = 0;
342 }
343 }
344 }
345 break;
346
347 case PNG_COLOR_TYPE_GRAY:
348 /* create a fake palette and check for single-shade transparency */
349 if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
350 gd_error("gd-png error: cannot allocate gray palette\n");
351 goto error;
352 }
353 palette_allocated = TRUE;
354 if (bit_depth < 8) {
355 num_palette = 1 << bit_depth;
356 for (i = 0; i < 256; ++i) {
357 j = (255 * i) / (num_palette - 1);
358 palette[i].red = palette[i].green = palette[i].blue = j;
359 }
360 } else {
361 num_palette = 256;
362 for (i = 0; i < 256; ++i) {
363 palette[i].red = palette[i].green = palette[i].blue = i;
364 }
365 }
366 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
367 png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
368 if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
369 transparent = trans_gray_rgb->gray >> 8;
370 } else {
371 transparent = trans_gray_rgb->gray;
372 }
373 /* Note slight error in 16-bit case: up to 256 16-bit shades
374 * may get mapped to a single 8-bit shade, and only one of them
375 * is supposed to be transparent. IOW, both opaque pixels and
376 * transparent pixels will be mapped into the transparent entry.
377 * There is no particularly good way around this in the case
378 * that all 256 8-bit shades are used, but one could write some
379 * custom 16-bit code to handle the case where there are gdFree
380 * palette entries. This error will be extremely rare in
381 * general, though. (Quite possibly there is only one such
382 * image in existence.) */
383 }
384 break;
385
386 case PNG_COLOR_TYPE_GRAY_ALPHA:
387 png_set_gray_to_rgb(png_ptr);
388 // fall through
389 // Keep above comment, gcc recognizes it and silent its warning about fall through case here
390 case PNG_COLOR_TYPE_RGB:
391 case PNG_COLOR_TYPE_RGB_ALPHA:
392 /* gd 2.0: we now support truecolor. See the comment above
393 for a rare situation in which the transparent pixel may not
394 work properly with 16-bit channels. */
395 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
396 png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
397 if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
398 transparent = gdTrueColor (trans_color_rgb->red >> 8,
399 trans_color_rgb->green >> 8,
400 trans_color_rgb->blue >> 8);
401 } else {
402 transparent = gdTrueColor (trans_color_rgb->red,
403 trans_color_rgb->green,
404 trans_color_rgb->blue);
405 }
406 }
407 break;
408 default:
409 gd_error("gd-png color_type is unknown: %d\n", color_type);
410 goto error;
411 }
412
413 png_read_update_info (png_ptr, info_ptr);
414
415 /* allocate space for the PNG image data */
416 rowbytes = png_get_rowbytes (png_ptr, info_ptr);
417 if (overflow2(rowbytes, height))
418 goto error;
419 image_data = (png_bytep) gdMalloc (rowbytes * height);
420 if (!image_data) {
421 gd_error("gd-png error: cannot allocate image data\n");
422 goto error;
423 }
424 if (overflow2(height, sizeof (png_bytep)))
425 goto error;
426
427 row_pointers = (png_bytepp) gdMalloc (height * sizeof (png_bytep));
428 if (!row_pointers) {
429 gd_error("gd-png error: cannot allocate row pointers\n");
430 goto error;
431 }
432
433 /* setjmp() must be called in every non-callback function that calls a
434 * PNG-reading libpng function. We must reset it everytime we get a
435 * new allocation that we save in a stack variable.
436 */
437 #ifdef PNG_SETJMP_SUPPORTED
438 if (setjmp(jbw.jmpbuf)) {
439 gd_error("gd-png error: setjmp returns error condition 3\n");
440 goto error;
441 }
442 #endif
443
444 /* set the individual row_pointers to point at the correct offsets */
445 for (h = 0; h < height; ++h) {
446 row_pointers[h] = image_data + h * rowbytes;
447 }
448
449 png_read_image (png_ptr, row_pointers); /* read whole image... */
450 png_read_end (png_ptr, NULL); /* ...done! */
451
452 if (!im->trueColor) {
453 im->colorsTotal = num_palette;
454 /* load the palette and mark all entries "open" (unused) for now */
455 open = im->open;
456 for (i = 0; i < num_palette; ++i) {
457 im->red[i] = palette[i].red;
458 im->green[i] = palette[i].green;
459 im->blue[i] = palette[i].blue;
460 open[i] = 1;
461 }
462 for (i = num_palette; i < gdMaxColors; ++i) {
463 open[i] = 1;
464 }
465 }
466 /* 2.0.12: Slaven Rezic: palette images are not the only images
467 with a simple transparent color setting */
468 im->transparent = transparent;
469 im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
470
471 /* can't nuke structs until done with palette */
472 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
473 switch (color_type) {
474 case PNG_COLOR_TYPE_RGB:
475 for (h = 0; h < height; h++) {
476 int boffset = 0;
477 for (w = 0; w < width; w++) {
478 register png_byte r = row_pointers[h][boffset++];
479 register png_byte g = row_pointers[h][boffset++];
480 register png_byte b = row_pointers[h][boffset++];
481 im->tpixels[h][w] = gdTrueColor (r, g, b);
482 }
483 }
484 break;
485
486 case PNG_COLOR_TYPE_GRAY_ALPHA:
487 case PNG_COLOR_TYPE_RGB_ALPHA:
488 for (h = 0; h < height; h++) {
489 int boffset = 0;
490 for (w = 0; w < width; w++) {
491 register png_byte r = row_pointers[h][boffset++];
492 register png_byte g = row_pointers[h][boffset++];
493 register png_byte b = row_pointers[h][boffset++];
494
495 /* gd has only 7 bits of alpha channel resolution, and
496 * 127 is transparent, 0 opaque. A moment of convenience,
497 * a lifetime of compatibility.
498 */
499
500 register png_byte a = gdAlphaMax - (row_pointers[h][boffset++] >> 1);
501 im->tpixels[h][w] = gdTrueColorAlpha(r, g, b, a);
502 }
503 }
504 break;
505 default:
506 if (!im->trueColor) {
507 /* Palette image, or something coerced to be one */
508 for (h = 0; h < height; ++h) {
509 for (w = 0; w < width; ++w) {
510 register png_byte idx = row_pointers[h][w];
511 im->pixels[h][w] = idx;
512 open[idx] = 0;
513 }
514 }
515 }
516 }
517 #ifdef DEBUG
518 if (!im->trueColor) {
519 for (i = num_palette; i < gdMaxColors; ++i) {
520 if (!open[i]) {
521 fprintf (stderr,
522 "gd-png warning: image data references out-of-range"
523 " color index (%d)\n", i);
524 }
525 }
526 }
527 #endif
528
529 done:
530 if (palette_allocated) {
531 gdFree (palette);
532 }
533 if (image_data)
534 gdFree(image_data);
535 if (row_pointers)
536 gdFree(row_pointers);
537
538 return im;
539
540 error:
541 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
542 if (im) {
543 gdImageDestroy(im);
544 im = NULL;
545 }
546 goto done;
547 }
548
549
550 /*
551 Function: gdImagePngEx
552
553 <gdImagePngEx> outputs the specified image to the specified file in
554 PNG format. The file must be open for writing. Under MSDOS and all
555 versions of Windows, it is important to use "wb" as opposed to
556 simply "w" as the mode when opening the file, and under Unix there
557 is no penalty for doing so. <gdImagePngEx> does not close the file;
558 your code must do so.
559
560 In addition, <gdImagePngEx> allows the level of compression to be
561 specified. A compression level of 0 means "no compression." A
562 compression level of 1 means "compressed, but as quickly as
563 possible." A compression level of 9 means "compressed as much as
564 possible to produce the smallest possible file." A compression level
565 of -1 will use the default compression level at the time zlib was
566 compiled on your system.
567
568 Variants:
569
570 <gdImagePng> is equivalent to calling <gdImagePngEx> with
571 compression of -1.
572
573 <gdImagePngCtx> and <gdImagePngCtxEx> write via a <gdIOCtx>
574 instead of a file handle.
575
576 <gdImagePngPtr> and <gdImagePngPtrEx> store the image file to
577 memory.
578
579 Parameters:
580
581 im - the image to write
582 outFile - the output FILE* object.
583 level - compression level: 0 -> none, 1-9 -> level, -1 -> default
584
585 Returns:
586
587 Nothing.
588
589 Example:
590 (start code)
591
592 gdImagePtr im;
593 int black, white;
594 FILE *out;
595
596 im = gdImageCreate(100, 100); // Create the image
597 white = gdImageColorAllocate(im, 255, 255, 255); // Alloc background
598 black = gdImageColorAllocate(im, 0, 0, 0); // Allocate drawing color
599 gdImageRectangle(im, 0, 0, 99, 99, black); // Draw rectangle
600 out = fopen("rect.png", "wb"); // Open output file (binary)
601 gdImagePngEx(im, out, 9); // Write PNG, max compression
602 fclose(out); // Close file
603 gdImageDestroy(im); // Destroy image
604
605 (end code)
606 */
607 BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * outFile, int level)
608 {
609 gdIOCtx *out = gdNewFileCtx (outFile);
610 if (out == NULL) return;
611 gdImagePngCtxEx (im, out, level);
612 out->gd_free (out);
613 }
614
615 /*
616 Function: gdImagePng
617
618 Equivalent to calling <gdImagePngEx> with compression of -1.
619
620 Parameters:
621
622 im - the image to save.
623 outFile - the output FILE*.
624
625 Returns:
626
627 Nothing.
628 */
629 BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * outFile)
630 {
631 gdIOCtx *out = gdNewFileCtx (outFile);
632 if (out == NULL) return;
633 gdImagePngCtxEx (im, out, -1);
634 out->gd_free (out);
635 }
636
637 static int _gdImagePngCtxEx(gdImagePtr im, gdIOCtx * outfile, int level);
638
639 /*
640 Function: gdImagePngPtr
641
642 Equivalent to calling <gdImagePngPtrEx> with compression of -1.
643
644 See <gdImagePngEx> for more information.
645
646 Parameters:
647
648 im - the image to save.
649 size - Output: size in bytes of the result.
650
651 Returns:
652
653 A pointer to memory containing the image data or NULL on error.
654
655 */
656 BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size)
657 {
658 void *rv;
659 gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
660 if (out == NULL) return NULL;
661 if (!_gdImagePngCtxEx (im, out, -1)) {
662 rv = gdDPExtractData (out, size);
663 } else {
664 rv = NULL;
665 }
666 out->gd_free (out);
667 return rv;
668 }
669
670 /*
671 Function: gdImagePngPtrEx
672
673 Identical to <gdImagePngEx> except that it returns a pointer to a
674 memory area with the PNG data. This memory must be freed by the
675 caller when it is no longer needed. **The caller must invoke
676 gdFree(), not free()**
677
678 The 'size' parameter receives the total size of the block of
679 memory.
680
681 See <gdImagePngEx> for more information.
682
683 Parameters:
684
685 im - the image to save.
686 size - Output: size in bytes of the result.
687 level - compression level: 0 -> none, 1-9 -> level, -1 -> default
688
689 Returns:
690
691 A pointer to memory containing the image data or NULL on error.
692
693 */
694 BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level)
695 {
696 void *rv;
697 gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
698 if (out == NULL) return NULL;
699 if (!_gdImagePngCtxEx (im, out, level)) {
700 rv = gdDPExtractData (out, size);
701 } else {
702 rv = NULL;
703 }
704 out->gd_free (out);
705 return rv;
706 }
707
708
709
710 /*
711 Function: gdImagePngCtx
712
713 Equivalent to calling <gdImagePngCtxEx> with compression of -1.
714 See <gdImagePngEx> for more information.
715
716 Parameters:
717
718 im - the image to save.
719 outfile - the <gdIOCtx> to write to.
720
721 Returns:
722
723 Nothing.
724
725 */
726 BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
727 {
728 /* 2.0.13: 'return' here was an error, thanks to Kevin Smith */
729 gdImagePngCtxEx (im, outfile, -1);
730 }
731
732
733
734
735 /*
736 Function: gdImagePngCtxEx
737
738 Outputs the given image as PNG data, but using a <gdIOCtx> instead
739 of a file. See <gdIamgePnEx>.
740
741 Parameters:
742
743 im - the image to save.
744 outfile - the <gdIOCtx> to write to.
745 level - compression level: 0 -> none, 1-9 -> level, -1 -> default
746
747 Returns:
748
749 Nothing.
750
751 */
752 BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level)
753 {
754 _gdImagePngCtxEx(im, outfile, level);
755 }
756
757 /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
758 * and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
759 * (http://www.libpng.org/pub/png/book/).
760 */
761 /* returns 0 on success, 1 on failure */
762 static int _gdImagePngCtxEx(gdImagePtr im, gdIOCtx * outfile, int level)
763 {
764 int i, j, bit_depth = 0, interlace_type;
765 int width = im->sx;
766 int height = im->sy;
767 int colors = im->colorsTotal;
768 int *open = im->open;
769 int mapping[gdMaxColors]; /* mapping[gd_index] == png_index */
770 png_byte trans_values[256];
771 png_color_16 trans_rgb_value;
772 png_color palette[gdMaxColors];
773 png_structp png_ptr;
774 png_infop info_ptr;
775 png_bytep *row_pointers = NULL;
776 volatile int transparent = im->transparent;
777 volatile int remap = FALSE;
778 #ifdef PNG_SETJMP_SUPPORTED
779 jmpbuf_wrapper jbw;
780 #endif
781 int ret = 0;
782
783 /* width or height of value 0 is invalid in IHDR;
784 see http://www.w3.org/TR/PNG-Chunks.html */
785 if (width == 0 || height ==0) return 1;
786
787 #ifdef PNG_SETJMP_SUPPORTED
788 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
789 &jbw, gdPngErrorHandler,
790 NULL);
791 #else
792 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
793 #endif
794 if (png_ptr == NULL) {
795 gd_error("gd-png error: cannot allocate libpng main struct\n");
796 return 1;
797 }
798
799 info_ptr = png_create_info_struct (png_ptr);
800 if (info_ptr == NULL) {
801 gd_error("gd-png error: cannot allocate libpng info struct\n");
802 png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
803 return 1;
804 }
805
806 #ifdef PNG_SETJMP_SUPPORTED
807 if (setjmp(jbw.jmpbuf)) {
808 gd_error("gd-png error: setjmp returns error condition\n");
809 png_destroy_write_struct (&png_ptr, &info_ptr);
810
811 if (row_pointers) {
812 for (i = 0; i < height; ++i)
813 gdFree(row_pointers[i]);
814 gdFree(row_pointers);
815 }
816
817 return 1;
818 }
819 #endif
820
821 png_set_write_fn (png_ptr, (void *) outfile, gdPngWriteData,
822 gdPngFlushData);
823
824 /* This is best for palette images, and libpng defaults to it for
825 palette images anyway, so we don't need to do it explicitly.
826 What to ideally do for truecolor images depends, alas, on the image.
827 gd is intentionally imperfect and doesn't spend a lot of time
828 fussing with such things. */
829
830 /* Faster if this is uncommented, but may produce larger truecolor files.
831 Wait for gdImagePngCtxEx. */
832 #if 0
833 png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
834 #endif
835
836 /* 2.0.12: this is finally a parameter */
837 png_set_compression_level (png_ptr, level);
838
839 #ifdef PNG_pHYs_SUPPORTED
840 /* 2.1.0: specify the resolution */
841 png_set_pHYs(png_ptr, info_ptr, DPI2DPM(im->res_x), DPI2DPM(im->res_y),
842 PNG_RESOLUTION_METER);
843 #endif
844
845 /* can set this to a smaller value without compromising compression if all
846 * image data is 16K or less; will save some decoder memory [min == 8] */
847 /* png_set_compression_window_bits(png_ptr, 15); */
848
849 if (!im->trueColor) {
850 if (transparent >= im->colorsTotal ||
851 (transparent >= 0 && open[transparent]))
852 transparent = -1;
853 }
854 if (!im->trueColor) {
855 for (i = 0; i < gdMaxColors; ++i)
856 mapping[i] = -1;
857 }
858 if (!im->trueColor) {
859 /* count actual number of colors used (colorsTotal == high-water mark) */
860 colors = 0;
861 for (i = 0; i < im->colorsTotal; ++i) {
862 if (!open[i]) {
863 mapping[i] = colors;
864 ++colors;
865 }
866 }
867 if (colors == 0) {
868 gd_error("gd-png error: no colors in palette\n");
869 ret = 1;
870 goto bail;
871 }
872 if (colors < im->colorsTotal) {
873 remap = TRUE;
874 }
875 if (colors <= 2)
876 bit_depth = 1;
877 else if (colors <= 4)
878 bit_depth = 2;
879 else if (colors <= 16)
880 bit_depth = 4;
881 else
882 bit_depth = 8;
883 }
884 interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
885
886 if (im->trueColor) {
887 if (im->saveAlphaFlag) {
888 png_set_IHDR (png_ptr, info_ptr, width, height, 8,
889 PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
890 PNG_COMPRESSION_TYPE_DEFAULT,
891 PNG_FILTER_TYPE_DEFAULT);
892 } else {
893 png_set_IHDR (png_ptr, info_ptr, width, height, 8,
894 PNG_COLOR_TYPE_RGB, interlace_type,
895 PNG_COMPRESSION_TYPE_DEFAULT,
896 PNG_FILTER_TYPE_DEFAULT);
897 }
898 } else {
899 png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth,
900 PNG_COLOR_TYPE_PALETTE, interlace_type,
901 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
902 }
903 if (im->trueColor && (!im->saveAlphaFlag) && (transparent >= 0)) {
904 /* 2.0.9: fixed by Thomas Winzig */
905 trans_rgb_value.red = gdTrueColorGetRed (im->transparent);
906 trans_rgb_value.green = gdTrueColorGetGreen (im->transparent);
907 trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent);
908 png_set_tRNS (png_ptr, info_ptr, 0, 0, &trans_rgb_value);
909 }
910 if (!im->trueColor) {
911 /* Oy veh. Remap the PNG palette to put the
912 entries with interesting alpha channel
913 values first. This minimizes the size
914 of the tRNS chunk and thus the size
915 of the PNG file as a whole. */
916 int tc = 0;
917 int i;
918 int j;
919 int k;
920 for (i = 0; (i < im->colorsTotal); i++) {
921 if ((!im->open[i]) && (im->alpha[i] != gdAlphaOpaque)) {
922 tc++;
923 }
924 }
925 if (tc) {
926 #if 0
927 for (i = 0; (i < im->colorsTotal); i++) {
928 trans_values[i] = 255 -
929 ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
930 }
931 png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);
932 #endif
933 if (!remap) {
934 remap = TRUE;
935 }
936 /* (Semi-)transparent indexes come up from the bottom
937 of the list of real colors; opaque
938 indexes come down from the top */
939 j = 0;
940 k = colors - 1;
941 for (i = 0; (i < im->colorsTotal); i++) {
942 if (!im->open[i]) {
943 if (im->alpha[i] != gdAlphaOpaque) {
944 /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
945 trans_values[j] = 255 -
946 ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
947 mapping[i] = j++;
948 } else {
949 mapping[i] = k--;
950 }
951 }
952 }
953 png_set_tRNS (png_ptr, info_ptr, trans_values, tc, NULL);
954 }
955 }
956
957 /* convert palette to libpng layout */
958 if (!im->trueColor) {
959 if (remap)
960 for (i = 0; i < im->colorsTotal; ++i) {
961 if (mapping[i] < 0)
962 continue;
963 palette[mapping[i]].red = im->red[i];
964 palette[mapping[i]].green = im->green[i];
965 palette[mapping[i]].blue = im->blue[i];
966 }
967 else
968 for (i = 0; i < colors; ++i) {
969 palette[i].red = im->red[i];
970 palette[i].green = im->green[i];
971 palette[i].blue = im->blue[i];
972 }
973 png_set_PLTE (png_ptr, info_ptr, palette, colors);
974 }
975
976 /* write out the PNG header info (everything up to first IDAT) */
977 png_write_info (png_ptr, info_ptr);
978
979 /* make sure < 8-bit images are packed into pixels as tightly as possible */
980 png_set_packing (png_ptr);
981
982 /* This code allocates a set of row buffers and copies the gd image data
983 * into them only in the case that remapping is necessary; in gd 1.3 and
984 * later, the im->pixels array is laid out identically to libpng's row
985 * pointers and can be passed to png_write_image() function directly.
986 * The remapping case could be accomplished with less memory for non-
987 * interlaced images, but interlacing causes some serious complications. */
988 if (im->trueColor) {
989 /* performance optimizations by Phong Tran */
990 int channels = im->saveAlphaFlag ? 4 : 3;
991 /* Our little 7-bit alpha channel trick costs us a bit here. */
992 unsigned char *pOutputRow;
993 int **ptpixels = im->tpixels;
994 int *pThisRow;
995 unsigned char a;
996 int thisPixel;
997 png_bytep *prow_pointers;
998 int saveAlphaFlag = im->saveAlphaFlag;
999 if (overflow2(sizeof (png_bytep), height)) {
1000 ret = 1;
1001 goto bail;
1002 }
1003 /* Need to use calloc so we can clean it up sanely in the error handler. */
1004 row_pointers = gdCalloc(height, sizeof (png_bytep));
1005 if (row_pointers == NULL) {
1006 gd_error("gd-png error: unable to allocate row_pointers\n");
1007 ret = 1;
1008 goto bail;
1009 }
1010 prow_pointers = row_pointers;
1011 for (j = 0; j < height; ++j) {
1012 if (overflow2(width, channels) || ((*prow_pointers =
1013 (png_bytep) gdMalloc (width * channels)) == NULL)) {
1014 gd_error("gd-png error: unable to allocate rows\n");
1015 for (i = 0; i < j; ++i)
1016 gdFree (row_pointers[i]);
1017 /* 2.0.29: memory leak TBB */
1018 gdFree(row_pointers);
1019 ret = 1;
1020 goto bail;
1021 }
1022 pOutputRow = *prow_pointers++;
1023 pThisRow = *ptpixels++;
1024 for (i = 0; i < width; ++i) {
1025 thisPixel = *pThisRow++;
1026 *pOutputRow++ = gdTrueColorGetRed (thisPixel);
1027 *pOutputRow++ = gdTrueColorGetGreen (thisPixel);
1028 *pOutputRow++ = gdTrueColorGetBlue (thisPixel);
1029
1030 if (saveAlphaFlag) {
1031 /* convert the 7-bit alpha channel to an 8-bit alpha channel.
1032 We do a little bit-flipping magic, repeating the MSB
1033 as the LSB, to ensure that 0 maps to 0 and
1034 127 maps to 255. We also have to invert to match
1035 PNG's convention in which 255 is opaque. */
1036 a = gdTrueColorGetAlpha (thisPixel);
1037 /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
1038 *pOutputRow++ = 255 - ((a << 1) + (a >> 6));
1039 }
1040 }
1041 }
1042
1043 png_write_image (png_ptr, row_pointers);
1044 png_write_end (png_ptr, info_ptr);
1045
1046 for (j = 0; j < height; ++j)
1047 gdFree (row_pointers[j]);
1048 gdFree (row_pointers);
1049 } else {
1050 if (remap) {
1051 png_bytep *row_pointers;
1052 if (overflow2(sizeof (png_bytep), height)) {
1053 ret = 1;
1054 goto bail;
1055 }
1056 row_pointers = gdMalloc (sizeof (png_bytep) * height);
1057 if (row_pointers == NULL) {
1058 gd_error("gd-png error: unable to allocate row_pointers\n");
1059 ret = 1;
1060 goto bail;
1061 }
1062 for (j = 0; j < height; ++j) {
1063 if ((row_pointers[j] = (png_bytep) gdMalloc (width)) == NULL) {
1064 gd_error("gd-png error: unable to allocate rows\n");
1065 for (i = 0; i < j; ++i)
1066 gdFree (row_pointers[i]);
1067 /* TBB: memory leak */
1068 gdFree (row_pointers);
1069 ret = 1;
1070 goto bail;
1071 }
1072 for (i = 0; i < width; ++i)
1073 row_pointers[j][i] = mapping[im->pixels[j][i]];
1074 }
1075
1076 png_write_image (png_ptr, row_pointers);
1077 png_write_end (png_ptr, info_ptr);
1078
1079 for (j = 0; j < height; ++j)
1080 gdFree (row_pointers[j]);
1081 gdFree (row_pointers);
1082 } else {
1083 png_write_image (png_ptr, im->pixels);
1084 png_write_end (png_ptr, info_ptr);
1085 }
1086 }
1087 /* 1.6.3: maybe we should give that memory BACK! TBB */
1088 bail:
1089 png_destroy_write_struct (&png_ptr, &info_ptr);
1090 return ret;
1091 }
1092
1093 #else /* !HAVE_LIBPNG */
1094
1095 static void _noPngError(void)
1096 {
1097 gd_error("PNG image support has been disabled\n");
1098 }
1099
1100 BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * inFile)
1101 {
1102 ARG_NOT_USED(inFile);
1103 _noPngError();
1104 return NULL;
1105 }
1106
1107 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data)
1108 {
1109 ARG_NOT_USED(size);
1110 ARG_NOT_USED(data);
1111 return NULL;
1112 }
1113
1114 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile)
1115 {
1116 ARG_NOT_USED(infile);
1117 return NULL;
1118 }
1119
1120 BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * outFile, int level)
1121 {
1122 ARG_NOT_USED(im);
1123 ARG_NOT_USED(outFile);
1124 ARG_NOT_USED(level);
1125 _noPngError();
1126 }
1127
1128 BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * outFile)
1129 {
1130 ARG_NOT_USED(im);
1131 ARG_NOT_USED(outFile);
1132 _noPngError();
1133 }
1134
1135 BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size)
1136 {
1137 ARG_NOT_USED(im);
1138 ARG_NOT_USED(size);
1139 return NULL;
1140 }
1141
1142 BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level)
1143 {
1144 ARG_NOT_USED(im);
1145 ARG_NOT_USED(size);
1146 ARG_NOT_USED(level);
1147 return NULL;
1148 }
1149
1150 BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
1151 {
1152 ARG_NOT_USED(im);
1153 ARG_NOT_USED(outfile);
1154 _noPngError();
1155 }
1156
1157 BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level)
1158 {
1159 ARG_NOT_USED(im);
1160 ARG_NOT_USED(outfile);
1161 ARG_NOT_USED(level);
1162 _noPngError();
1163 }
1164
1165 #endif /* HAVE_LIBPNG */