"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 */