PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - gd/libgd - gd_png.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 315
Code covered: 62.9 % Executed lines: 198
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:08 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.