Home | History | Annotate | Download | only in libpng-1.2.19
      1 
      2 /* pngwrite.c - general routines to write a PNG file
      3  *
      4  * Last changed in libpng 1.2.15 January 5, 2007
      5  * For conditions of distribution and use, see copyright notice in png.h
      6  * Copyright (c) 1998-2007 Glenn Randers-Pehrson
      7  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
      8  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
      9  */
     10 
     11 /* get internal access to png.h */
     12 #define PNG_INTERNAL
     13 #include "png.h"
     14 #ifdef PNG_WRITE_SUPPORTED
     15 
     16 /* Writes all the PNG information.  This is the suggested way to use the
     17  * library.  If you have a new chunk to add, make a function to write it,
     18  * and put it in the correct location here.  If you want the chunk written
     19  * after the image data, put it in png_write_end().  I strongly encourage
     20  * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
     21  * the chunk, as that will keep the code from breaking if you want to just
     22  * write a plain PNG file.  If you have long comments, I suggest writing
     23  * them in png_write_end(), and compressing them.
     24  */
     25 void PNGAPI
     26 png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
     27 {
     28    png_debug(1, "in png_write_info_before_PLTE\n");
     29    if (png_ptr == NULL || info_ptr == NULL)
     30       return;
     31    if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
     32    {
     33    png_write_sig(png_ptr); /* write PNG signature */
     34 #if defined(PNG_MNG_FEATURES_SUPPORTED)
     35    if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
     36    {
     37       png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
     38       png_ptr->mng_features_permitted=0;
     39    }
     40 #endif
     41    /* write IHDR information. */
     42    png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
     43       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
     44       info_ptr->filter_type,
     45 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
     46       info_ptr->interlace_type);
     47 #else
     48       0);
     49 #endif
     50    /* the rest of these check to see if the valid field has the appropriate
     51       flag set, and if it does, writes the chunk. */
     52 #if defined(PNG_WRITE_gAMA_SUPPORTED)
     53    if (info_ptr->valid & PNG_INFO_gAMA)
     54    {
     55 #  ifdef PNG_FLOATING_POINT_SUPPORTED
     56       png_write_gAMA(png_ptr, info_ptr->gamma);
     57 #else
     58 #ifdef PNG_FIXED_POINT_SUPPORTED
     59       png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
     60 #  endif
     61 #endif
     62    }
     63 #endif
     64 #if defined(PNG_WRITE_sRGB_SUPPORTED)
     65    if (info_ptr->valid & PNG_INFO_sRGB)
     66       png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
     67 #endif
     68 #if defined(PNG_WRITE_iCCP_SUPPORTED)
     69    if (info_ptr->valid & PNG_INFO_iCCP)
     70       png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
     71                      info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
     72 #endif
     73 #if defined(PNG_WRITE_sBIT_SUPPORTED)
     74    if (info_ptr->valid & PNG_INFO_sBIT)
     75       png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
     76 #endif
     77 #if defined(PNG_WRITE_cHRM_SUPPORTED)
     78    if (info_ptr->valid & PNG_INFO_cHRM)
     79    {
     80 #ifdef PNG_FLOATING_POINT_SUPPORTED
     81       png_write_cHRM(png_ptr,
     82          info_ptr->x_white, info_ptr->y_white,
     83          info_ptr->x_red, info_ptr->y_red,
     84          info_ptr->x_green, info_ptr->y_green,
     85          info_ptr->x_blue, info_ptr->y_blue);
     86 #else
     87 #  ifdef PNG_FIXED_POINT_SUPPORTED
     88       png_write_cHRM_fixed(png_ptr,
     89          info_ptr->int_x_white, info_ptr->int_y_white,
     90          info_ptr->int_x_red, info_ptr->int_y_red,
     91          info_ptr->int_x_green, info_ptr->int_y_green,
     92          info_ptr->int_x_blue, info_ptr->int_y_blue);
     93 #  endif
     94 #endif
     95    }
     96 #endif
     97 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
     98    if (info_ptr->unknown_chunks_num)
     99    {
    100        png_unknown_chunk *up;
    101 
    102        png_debug(5, "writing extra chunks\n");
    103 
    104        for (up = info_ptr->unknown_chunks;
    105             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
    106             up++)
    107        {
    108          int keep=png_handle_as_unknown(png_ptr, up->name);
    109          if (keep != PNG_HANDLE_CHUNK_NEVER &&
    110             up->location && !(up->location & PNG_HAVE_PLTE) &&
    111             !(up->location & PNG_HAVE_IDAT) &&
    112             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
    113             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
    114          {
    115             png_write_chunk(png_ptr, up->name, up->data, up->size);
    116          }
    117        }
    118    }
    119 #endif
    120       png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
    121    }
    122 }
    123 
    124 void PNGAPI
    125 png_write_info(png_structp png_ptr, png_infop info_ptr)
    126 {
    127 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
    128    int i;
    129 #endif
    130 
    131    png_debug(1, "in png_write_info\n");
    132 
    133    if (png_ptr == NULL || info_ptr == NULL)
    134       return;
    135 
    136    png_write_info_before_PLTE(png_ptr, info_ptr);
    137 
    138    if (info_ptr->valid & PNG_INFO_PLTE)
    139       png_write_PLTE(png_ptr, info_ptr->palette,
    140          (png_uint_32)info_ptr->num_palette);
    141    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    142       png_error(png_ptr, "Valid palette required for paletted images");
    143 
    144 #if defined(PNG_WRITE_tRNS_SUPPORTED)
    145    if (info_ptr->valid & PNG_INFO_tRNS)
    146       {
    147 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
    148          /* invert the alpha channel (in tRNS) */
    149          if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
    150             info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    151          {
    152             int j;
    153             for (j=0; j<(int)info_ptr->num_trans; j++)
    154                info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
    155          }
    156 #endif
    157       png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
    158          info_ptr->num_trans, info_ptr->color_type);
    159       }
    160 #endif
    161 #if defined(PNG_WRITE_bKGD_SUPPORTED)
    162    if (info_ptr->valid & PNG_INFO_bKGD)
    163       png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
    164 #endif
    165 #if defined(PNG_WRITE_hIST_SUPPORTED)
    166    if (info_ptr->valid & PNG_INFO_hIST)
    167       png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
    168 #endif
    169 #if defined(PNG_WRITE_oFFs_SUPPORTED)
    170    if (info_ptr->valid & PNG_INFO_oFFs)
    171       png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
    172          info_ptr->offset_unit_type);
    173 #endif
    174 #if defined(PNG_WRITE_pCAL_SUPPORTED)
    175    if (info_ptr->valid & PNG_INFO_pCAL)
    176       png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
    177          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
    178          info_ptr->pcal_units, info_ptr->pcal_params);
    179 #endif
    180 #if defined(PNG_WRITE_sCAL_SUPPORTED)
    181    if (info_ptr->valid & PNG_INFO_sCAL)
    182 #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
    183       png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
    184           info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
    185 #else
    186 #ifdef PNG_FIXED_POINT_SUPPORTED
    187       png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
    188           info_ptr->scal_s_width, info_ptr->scal_s_height);
    189 #else
    190       png_warning(png_ptr,
    191           "png_write_sCAL not supported; sCAL chunk not written.");
    192 #endif
    193 #endif
    194 #endif
    195 #if defined(PNG_WRITE_pHYs_SUPPORTED)
    196    if (info_ptr->valid & PNG_INFO_pHYs)
    197       png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
    198          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
    199 #endif
    200 #if defined(PNG_WRITE_tIME_SUPPORTED)
    201    if (info_ptr->valid & PNG_INFO_tIME)
    202    {
    203       png_write_tIME(png_ptr, &(info_ptr->mod_time));
    204       png_ptr->mode |= PNG_WROTE_tIME;
    205    }
    206 #endif
    207 #if defined(PNG_WRITE_sPLT_SUPPORTED)
    208    if (info_ptr->valid & PNG_INFO_sPLT)
    209      for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
    210        png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
    211 #endif
    212 #if defined(PNG_WRITE_TEXT_SUPPORTED)
    213    /* Check to see if we need to write text chunks */
    214    for (i = 0; i < info_ptr->num_text; i++)
    215    {
    216       png_debug2(2, "Writing header text chunk %d, type %d\n", i,
    217          info_ptr->text[i].compression);
    218       /* an internationalized chunk? */
    219       if (info_ptr->text[i].compression > 0)
    220       {
    221 #if defined(PNG_WRITE_iTXt_SUPPORTED)
    222           /* write international chunk */
    223           png_write_iTXt(png_ptr,
    224                          info_ptr->text[i].compression,
    225                          info_ptr->text[i].key,
    226                          info_ptr->text[i].lang,
    227                          info_ptr->text[i].lang_key,
    228                          info_ptr->text[i].text);
    229 #else
    230           png_warning(png_ptr, "Unable to write international text");
    231 #endif
    232           /* Mark this chunk as written */
    233           info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    234       }
    235       /* If we want a compressed text chunk */
    236       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
    237       {
    238 #if defined(PNG_WRITE_zTXt_SUPPORTED)
    239          /* write compressed chunk */
    240          png_write_zTXt(png_ptr, info_ptr->text[i].key,
    241             info_ptr->text[i].text, 0,
    242             info_ptr->text[i].compression);
    243 #else
    244          png_warning(png_ptr, "Unable to write compressed text");
    245 #endif
    246          /* Mark this chunk as written */
    247          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    248       }
    249       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    250       {
    251 #if defined(PNG_WRITE_tEXt_SUPPORTED)
    252          /* write uncompressed chunk */
    253          png_write_tEXt(png_ptr, info_ptr->text[i].key,
    254                          info_ptr->text[i].text,
    255                          0);
    256 #else
    257          png_warning(png_ptr, "Unable to write uncompressed text");
    258 #endif
    259          /* Mark this chunk as written */
    260          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    261       }
    262    }
    263 #endif
    264 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
    265    if (info_ptr->unknown_chunks_num)
    266    {
    267        png_unknown_chunk *up;
    268 
    269        png_debug(5, "writing extra chunks\n");
    270 
    271        for (up = info_ptr->unknown_chunks;
    272             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
    273             up++)
    274        {
    275          int keep=png_handle_as_unknown(png_ptr, up->name);
    276          if (keep != PNG_HANDLE_CHUNK_NEVER &&
    277             up->location && (up->location & PNG_HAVE_PLTE) &&
    278             !(up->location & PNG_HAVE_IDAT) &&
    279             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
    280             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
    281          {
    282             png_write_chunk(png_ptr, up->name, up->data, up->size);
    283          }
    284        }
    285    }
    286 #endif
    287 }
    288 
    289 /* Writes the end of the PNG file.  If you don't want to write comments or
    290  * time information, you can pass NULL for info.  If you already wrote these
    291  * in png_write_info(), do not write them again here.  If you have long
    292  * comments, I suggest writing them here, and compressing them.
    293  */
    294 void PNGAPI
    295 png_write_end(png_structp png_ptr, png_infop info_ptr)
    296 {
    297    png_debug(1, "in png_write_end\n");
    298    if (png_ptr == NULL)
    299       return;
    300    if (!(png_ptr->mode & PNG_HAVE_IDAT))
    301       png_error(png_ptr, "No IDATs written into file");
    302 
    303    /* see if user wants us to write information chunks */
    304    if (info_ptr != NULL)
    305    {
    306 #if defined(PNG_WRITE_TEXT_SUPPORTED)
    307       int i; /* local index variable */
    308 #endif
    309 #if defined(PNG_WRITE_tIME_SUPPORTED)
    310       /* check to see if user has supplied a time chunk */
    311       if ((info_ptr->valid & PNG_INFO_tIME) &&
    312          !(png_ptr->mode & PNG_WROTE_tIME))
    313          png_write_tIME(png_ptr, &(info_ptr->mod_time));
    314 #endif
    315 #if defined(PNG_WRITE_TEXT_SUPPORTED)
    316       /* loop through comment chunks */
    317       for (i = 0; i < info_ptr->num_text; i++)
    318       {
    319          png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
    320             info_ptr->text[i].compression);
    321          /* an internationalized chunk? */
    322          if (info_ptr->text[i].compression > 0)
    323          {
    324 #if defined(PNG_WRITE_iTXt_SUPPORTED)
    325              /* write international chunk */
    326              png_write_iTXt(png_ptr,
    327                          info_ptr->text[i].compression,
    328                          info_ptr->text[i].key,
    329                          info_ptr->text[i].lang,
    330                          info_ptr->text[i].lang_key,
    331                          info_ptr->text[i].text);
    332 #else
    333              png_warning(png_ptr, "Unable to write international text");
    334 #endif
    335              /* Mark this chunk as written */
    336              info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    337          }
    338          else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
    339          {
    340 #if defined(PNG_WRITE_zTXt_SUPPORTED)
    341             /* write compressed chunk */
    342             png_write_zTXt(png_ptr, info_ptr->text[i].key,
    343                info_ptr->text[i].text, 0,
    344                info_ptr->text[i].compression);
    345 #else
    346             png_warning(png_ptr, "Unable to write compressed text");
    347 #endif
    348             /* Mark this chunk as written */
    349             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    350          }
    351          else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    352          {
    353 #if defined(PNG_WRITE_tEXt_SUPPORTED)
    354             /* write uncompressed chunk */
    355             png_write_tEXt(png_ptr, info_ptr->text[i].key,
    356                info_ptr->text[i].text, 0);
    357 #else
    358             png_warning(png_ptr, "Unable to write uncompressed text");
    359 #endif
    360 
    361             /* Mark this chunk as written */
    362             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    363          }
    364       }
    365 #endif
    366 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
    367    if (info_ptr->unknown_chunks_num)
    368    {
    369        png_unknown_chunk *up;
    370 
    371        png_debug(5, "writing extra chunks\n");
    372 
    373        for (up = info_ptr->unknown_chunks;
    374             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
    375             up++)
    376        {
    377          int keep=png_handle_as_unknown(png_ptr, up->name);
    378          if (keep != PNG_HANDLE_CHUNK_NEVER &&
    379             up->location && (up->location & PNG_AFTER_IDAT) &&
    380             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
    381             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
    382          {
    383             png_write_chunk(png_ptr, up->name, up->data, up->size);
    384          }
    385        }
    386    }
    387 #endif
    388    }
    389 
    390    png_ptr->mode |= PNG_AFTER_IDAT;
    391 
    392    /* write end of PNG file */
    393    png_write_IEND(png_ptr);
    394 }
    395 
    396 #if defined(PNG_WRITE_tIME_SUPPORTED)
    397 #if !defined(_WIN32_WCE)
    398 /* "time.h" functions are not supported on WindowsCE */
    399 void PNGAPI
    400 png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
    401 {
    402    png_debug(1, "in png_convert_from_struct_tm\n");
    403    ptime->year = (png_uint_16)(1900 + ttime->tm_year);
    404    ptime->month = (png_byte)(ttime->tm_mon + 1);
    405    ptime->day = (png_byte)ttime->tm_mday;
    406    ptime->hour = (png_byte)ttime->tm_hour;
    407    ptime->minute = (png_byte)ttime->tm_min;
    408    ptime->second = (png_byte)ttime->tm_sec;
    409 }
    410 
    411 void PNGAPI
    412 png_convert_from_time_t(png_timep ptime, time_t ttime)
    413 {
    414    struct tm *tbuf;
    415 
    416    png_debug(1, "in png_convert_from_time_t\n");
    417    tbuf = gmtime(&ttime);
    418    png_convert_from_struct_tm(ptime, tbuf);
    419 }
    420 #endif
    421 #endif
    422 
    423 /* Initialize png_ptr structure, and allocate any memory needed */
    424 png_structp PNGAPI
    425 png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
    426    png_error_ptr error_fn, png_error_ptr warn_fn)
    427 {
    428 #ifdef PNG_USER_MEM_SUPPORTED
    429    return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
    430       warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
    431 }
    432 
    433 /* Alternate initialize png_ptr structure, and allocate any memory needed */
    434 png_structp PNGAPI
    435 png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
    436    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
    437    png_malloc_ptr malloc_fn, png_free_ptr free_fn)
    438 {
    439 #endif /* PNG_USER_MEM_SUPPORTED */
    440    png_structp png_ptr;
    441 #ifdef PNG_SETJMP_SUPPORTED
    442 #ifdef USE_FAR_KEYWORD
    443    jmp_buf jmpbuf;
    444 #endif
    445 #endif
    446    int i;
    447    png_debug(1, "in png_create_write_struct\n");
    448 #ifdef PNG_USER_MEM_SUPPORTED
    449    png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
    450       (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
    451 #else
    452    png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
    453 #endif /* PNG_USER_MEM_SUPPORTED */
    454    if (png_ptr == NULL)
    455       return (NULL);
    456 
    457 #if !defined(PNG_1_0_X)
    458 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
    459 #ifdef PNG_MMX_CODE_SUPPORTED
    460    png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
    461 #endif
    462 #endif
    463 #endif /* PNG_1_0_X */
    464 
    465    /* added at libpng-1.2.6 */
    466 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
    467    png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
    468    png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
    469 #endif
    470 
    471 #ifdef PNG_SETJMP_SUPPORTED
    472 #ifdef USE_FAR_KEYWORD
    473    if (setjmp(jmpbuf))
    474 #else
    475    if (setjmp(png_ptr->jmpbuf))
    476 #endif
    477    {
    478       png_free(png_ptr, png_ptr->zbuf);
    479       png_ptr->zbuf=NULL;
    480       png_destroy_struct(png_ptr);
    481       return (NULL);
    482    }
    483 #ifdef USE_FAR_KEYWORD
    484    png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
    485 #endif
    486 #endif
    487 
    488 #ifdef PNG_USER_MEM_SUPPORTED
    489    png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
    490 #endif /* PNG_USER_MEM_SUPPORTED */
    491    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
    492 
    493    i=0;
    494    do
    495    {
    496      if(user_png_ver[i] != png_libpng_ver[i])
    497         png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
    498    } while (png_libpng_ver[i++]);
    499 
    500    if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
    501    {
    502      /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
    503       * we must recompile any applications that use any older library version.
    504       * For versions after libpng 1.0, we will be compatible, so we need
    505       * only check the first digit.
    506       */
    507      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
    508          (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
    509          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
    510      {
    511 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
    512         char msg[80];
    513         if (user_png_ver)
    514         {
    515           png_snprintf(msg, 80,
    516              "Application was compiled with png.h from libpng-%.20s",
    517              user_png_ver);
    518           png_warning(png_ptr, msg);
    519         }
    520         png_snprintf(msg, 80,
    521            "Application  is  running with png.c from libpng-%.20s",
    522            png_libpng_ver);
    523         png_warning(png_ptr, msg);
    524 #endif
    525 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
    526         png_ptr->flags=0;
    527 #endif
    528         png_error(png_ptr,
    529            "Incompatible libpng version in application and library");
    530      }
    531    }
    532 
    533    /* initialize zbuf - compression buffer */
    534    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
    535    png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
    536       (png_uint_32)png_ptr->zbuf_size);
    537 
    538    png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
    539       png_flush_ptr_NULL);
    540 
    541 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
    542    png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
    543       1, png_doublep_NULL, png_doublep_NULL);
    544 #endif
    545 
    546 #ifdef PNG_SETJMP_SUPPORTED
    547 /* Applications that neglect to set up their own setjmp() and then encounter
    548    a png_error() will longjmp here.  Since the jmpbuf is then meaningless we
    549    abort instead of returning. */
    550 #ifdef USE_FAR_KEYWORD
    551    if (setjmp(jmpbuf))
    552       PNG_ABORT();
    553    png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
    554 #else
    555    if (setjmp(png_ptr->jmpbuf))
    556       PNG_ABORT();
    557 #endif
    558 #endif
    559    return (png_ptr);
    560 }
    561 
    562 /* Initialize png_ptr structure, and allocate any memory needed */
    563 #if defined(PNG_1_0_X) || defined(PNG_1_2_X)
    564 /* Deprecated. */
    565 #undef png_write_init
    566 void PNGAPI
    567 png_write_init(png_structp png_ptr)
    568 {
    569    /* We only come here via pre-1.0.7-compiled applications */
    570    png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
    571 }
    572 
    573 void PNGAPI
    574 png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
    575    png_size_t png_struct_size, png_size_t png_info_size)
    576 {
    577    /* We only come here via pre-1.0.12-compiled applications */
    578    if(png_ptr == NULL) return;
    579 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
    580    if(png_sizeof(png_struct) > png_struct_size ||
    581       png_sizeof(png_info) > png_info_size)
    582    {
    583       char msg[80];
    584       png_ptr->warning_fn=NULL;
    585       if (user_png_ver)
    586       {
    587         png_snprintf(msg, 80,
    588            "Application was compiled with png.h from libpng-%.20s",
    589            user_png_ver);
    590         png_warning(png_ptr, msg);
    591       }
    592       png_snprintf(msg, 80,
    593          "Application  is  running with png.c from libpng-%.20s",
    594          png_libpng_ver);
    595       png_warning(png_ptr, msg);
    596    }
    597 #endif
    598    if(png_sizeof(png_struct) > png_struct_size)
    599      {
    600        png_ptr->error_fn=NULL;
    601 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
    602        png_ptr->flags=0;
    603 #endif
    604        png_error(png_ptr,
    605        "The png struct allocated by the application for writing is too small.");
    606      }
    607    if(png_sizeof(png_info) > png_info_size)
    608      {
    609        png_ptr->error_fn=NULL;
    610 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
    611        png_ptr->flags=0;
    612 #endif
    613        png_error(png_ptr,
    614        "The info struct allocated by the application for writing is too small.");
    615      }
    616    png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
    617 }
    618 #endif /* PNG_1_0_X || PNG_1_2_X */
    619 
    620 
    621 void PNGAPI
    622 png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
    623    png_size_t png_struct_size)
    624 {
    625    png_structp png_ptr=*ptr_ptr;
    626 #ifdef PNG_SETJMP_SUPPORTED
    627    jmp_buf tmp_jmp; /* to save current jump buffer */
    628 #endif
    629 
    630    int i = 0;
    631 
    632    if (png_ptr == NULL)
    633       return;
    634 
    635    do
    636    {
    637      if (user_png_ver[i] != png_libpng_ver[i])
    638      {
    639 #ifdef PNG_LEGACY_SUPPORTED
    640        png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
    641 #else
    642        png_ptr->warning_fn=NULL;
    643        png_warning(png_ptr,
    644      "Application uses deprecated png_write_init() and should be recompiled.");
    645        break;
    646 #endif
    647      }
    648    } while (png_libpng_ver[i++]);
    649 
    650    png_debug(1, "in png_write_init_3\n");
    651 
    652 #ifdef PNG_SETJMP_SUPPORTED
    653    /* save jump buffer and error functions */
    654    png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
    655 #endif
    656 
    657    if (png_sizeof(png_struct) > png_struct_size)
    658      {
    659        png_destroy_struct(png_ptr);
    660        png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
    661        *ptr_ptr = png_ptr;
    662      }
    663 
    664    /* reset all variables to 0 */
    665    png_memset(png_ptr, 0, png_sizeof (png_struct));
    666 
    667    /* added at libpng-1.2.6 */
    668 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
    669    png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
    670    png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
    671 #endif
    672 
    673 #if !defined(PNG_1_0_X)
    674 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
    675 #ifdef PNG_MMX_CODE_SUPPORTED
    676    png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
    677 #endif
    678 #endif
    679 #endif /* PNG_1_0_X */
    680 
    681 #ifdef PNG_SETJMP_SUPPORTED
    682    /* restore jump buffer */
    683    png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
    684 #endif
    685 
    686    png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
    687       png_flush_ptr_NULL);
    688 
    689    /* initialize zbuf - compression buffer */
    690    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
    691    png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
    692       (png_uint_32)png_ptr->zbuf_size);
    693 
    694 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
    695    png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
    696       1, png_doublep_NULL, png_doublep_NULL);
    697 #endif
    698 }
    699 
    700 /* Write a few rows of image data.  If the image is interlaced,
    701  * either you will have to write the 7 sub images, or, if you
    702  * have called png_set_interlace_handling(), you will have to
    703  * "write" the image seven times.
    704  */
    705 void PNGAPI
    706 png_write_rows(png_structp png_ptr, png_bytepp row,
    707    png_uint_32 num_rows)
    708 {
    709    png_uint_32 i; /* row counter */
    710    png_bytepp rp; /* row pointer */
    711 
    712    png_debug(1, "in png_write_rows\n");
    713 
    714    if (png_ptr == NULL)
    715       return;
    716 
    717    /* loop through the rows */
    718    for (i = 0, rp = row; i < num_rows; i++, rp++)
    719    {
    720       png_write_row(png_ptr, *rp);
    721    }
    722 }
    723 
    724 /* Write the image.  You only need to call this function once, even
    725  * if you are writing an interlaced image.
    726  */
    727 void PNGAPI
    728 png_write_image(png_structp png_ptr, png_bytepp image)
    729 {
    730    png_uint_32 i; /* row index */
    731    int pass, num_pass; /* pass variables */
    732    png_bytepp rp; /* points to current row */
    733 
    734    if (png_ptr == NULL)
    735       return;
    736 
    737    png_debug(1, "in png_write_image\n");
    738 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
    739    /* intialize interlace handling.  If image is not interlaced,
    740       this will set pass to 1 */
    741    num_pass = png_set_interlace_handling(png_ptr);
    742 #else
    743    num_pass = 1;
    744 #endif
    745    /* loop through passes */
    746    for (pass = 0; pass < num_pass; pass++)
    747    {
    748       /* loop through image */
    749       for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
    750       {
    751          png_write_row(png_ptr, *rp);
    752       }
    753    }
    754 }
    755 
    756 /* called by user to write a row of image data */
    757 void PNGAPI
    758 png_write_row(png_structp png_ptr, png_bytep row)
    759 {
    760    if (png_ptr == NULL)
    761       return;
    762    png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
    763       png_ptr->row_number, png_ptr->pass);
    764 
    765    /* initialize transformations and other stuff if first time */
    766    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
    767    {
    768    /* make sure we wrote the header info */
    769    if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
    770       png_error(png_ptr,
    771          "png_write_info was never called before png_write_row.");
    772 
    773    /* check for transforms that have been set but were defined out */
    774 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
    775    if (png_ptr->transformations & PNG_INVERT_MONO)
    776       png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
    777 #endif
    778 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
    779    if (png_ptr->transformations & PNG_FILLER)
    780       png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
    781 #endif
    782 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
    783    if (png_ptr->transformations & PNG_PACKSWAP)
    784       png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
    785 #endif
    786 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
    787    if (png_ptr->transformations & PNG_PACK)
    788       png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
    789 #endif
    790 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
    791    if (png_ptr->transformations & PNG_SHIFT)
    792       png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
    793 #endif
    794 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
    795    if (png_ptr->transformations & PNG_BGR)
    796       png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
    797 #endif
    798 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
    799    if (png_ptr->transformations & PNG_SWAP_BYTES)
    800       png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
    801 #endif
    802 
    803       png_write_start_row(png_ptr);
    804    }
    805 
    806 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
    807    /* if interlaced and not interested in row, return */
    808    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
    809    {
    810       switch (png_ptr->pass)
    811       {
    812          case 0:
    813             if (png_ptr->row_number & 0x07)
    814             {
    815                png_write_finish_row(png_ptr);
    816                return;
    817             }
    818             break;
    819          case 1:
    820             if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
    821             {
    822                png_write_finish_row(png_ptr);
    823                return;
    824             }
    825             break;
    826          case 2:
    827             if ((png_ptr->row_number & 0x07) != 4)
    828             {
    829                png_write_finish_row(png_ptr);
    830                return;
    831             }
    832             break;
    833          case 3:
    834             if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
    835             {
    836                png_write_finish_row(png_ptr);
    837                return;
    838             }
    839             break;
    840          case 4:
    841             if ((png_ptr->row_number & 0x03) != 2)
    842             {
    843                png_write_finish_row(png_ptr);
    844                return;
    845             }
    846             break;
    847          case 5:
    848             if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
    849             {
    850                png_write_finish_row(png_ptr);
    851                return;
    852             }
    853             break;
    854          case 6:
    855             if (!(png_ptr->row_number & 0x01))
    856             {
    857                png_write_finish_row(png_ptr);
    858                return;
    859             }
    860             break;
    861       }
    862    }
    863 #endif
    864 
    865    /* set up row info for transformations */
    866    png_ptr->row_info.color_type = png_ptr->color_type;
    867    png_ptr->row_info.width = png_ptr->usr_width;
    868    png_ptr->row_info.channels = png_ptr->usr_channels;
    869    png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
    870    png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
    871       png_ptr->row_info.channels);
    872 
    873    png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
    874       png_ptr->row_info.width);
    875 
    876    png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
    877    png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
    878    png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
    879    png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
    880    png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
    881    png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
    882 
    883    /* Copy user's row into buffer, leaving room for filter byte. */
    884    png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
    885       png_ptr->row_info.rowbytes);
    886 
    887 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
    888    /* handle interlacing */
    889    if (png_ptr->interlaced && png_ptr->pass < 6 &&
    890       (png_ptr->transformations & PNG_INTERLACE))
    891    {
    892       png_do_write_interlace(&(png_ptr->row_info),
    893          png_ptr->row_buf + 1, png_ptr->pass);
    894       /* this should always get caught above, but still ... */
    895       if (!(png_ptr->row_info.width))
    896       {
    897          png_write_finish_row(png_ptr);
    898          return;
    899       }
    900    }
    901 #endif
    902 
    903    /* handle other transformations */
    904    if (png_ptr->transformations)
    905       png_do_write_transformations(png_ptr);
    906 
    907 #if defined(PNG_MNG_FEATURES_SUPPORTED)
    908    /* Write filter_method 64 (intrapixel differencing) only if
    909     * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    910     * 2. Libpng did not write a PNG signature (this filter_method is only
    911     *    used in PNG datastreams that are embedded in MNG datastreams) and
    912     * 3. The application called png_permit_mng_features with a mask that
    913     *    included PNG_FLAG_MNG_FILTER_64 and
    914     * 4. The filter_method is 64 and
    915     * 5. The color_type is RGB or RGBA
    916     */
    917    if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
    918       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
    919    {
    920       /* Intrapixel differencing */
    921       png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
    922    }
    923 #endif
    924 
    925    /* Find a filter if necessary, filter the row and write it out. */
    926    png_write_find_filter(png_ptr, &(png_ptr->row_info));
    927 
    928    if (png_ptr->write_row_fn != NULL)
    929       (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
    930 }
    931 
    932 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
    933 /* Set the automatic flush interval or 0 to turn flushing off */
    934 void PNGAPI
    935 png_set_flush(png_structp png_ptr, int nrows)
    936 {
    937    png_debug(1, "in png_set_flush\n");
    938    if (png_ptr == NULL)
    939       return;
    940    png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
    941 }
    942 
    943 /* flush the current output buffers now */
    944 void PNGAPI
    945 png_write_flush(png_structp png_ptr)
    946 {
    947    int wrote_IDAT;
    948 
    949    png_debug(1, "in png_write_flush\n");
    950    if (png_ptr == NULL)
    951       return;
    952    /* We have already written out all of the data */
    953    if (png_ptr->row_number >= png_ptr->num_rows)
    954      return;
    955 
    956    do
    957    {
    958       int ret;
    959 
    960       /* compress the data */
    961       ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
    962       wrote_IDAT = 0;
    963 
    964       /* check for compression errors */
    965       if (ret != Z_OK)
    966       {
    967          if (png_ptr->zstream.msg != NULL)
    968             png_error(png_ptr, png_ptr->zstream.msg);
    969          else
    970             png_error(png_ptr, "zlib error");
    971       }
    972 
    973       if (!(png_ptr->zstream.avail_out))
    974       {
    975          /* write the IDAT and reset the zlib output buffer */
    976          png_write_IDAT(png_ptr, png_ptr->zbuf,
    977                         png_ptr->zbuf_size);
    978          png_ptr->zstream.next_out = png_ptr->zbuf;
    979          png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
    980          wrote_IDAT = 1;
    981       }
    982    } while(wrote_IDAT == 1);
    983 
    984    /* If there is any data left to be output, write it into a new IDAT */
    985    if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
    986    {
    987       /* write the IDAT and reset the zlib output buffer */
    988       png_write_IDAT(png_ptr, png_ptr->zbuf,
    989                      png_ptr->zbuf_size - png_ptr->zstream.avail_out);
    990       png_ptr->zstream.next_out = png_ptr->zbuf;
    991       png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
    992    }
    993    png_ptr->flush_rows = 0;
    994    png_flush(png_ptr);
    995 }
    996 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
    997 
    998 /* free all memory used by the write */
    999 void PNGAPI
   1000 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
   1001 {
   1002    png_structp png_ptr = NULL;
   1003    png_infop info_ptr = NULL;
   1004 #ifdef PNG_USER_MEM_SUPPORTED
   1005    png_free_ptr free_fn = NULL;
   1006    png_voidp mem_ptr = NULL;
   1007 #endif
   1008 
   1009    png_debug(1, "in png_destroy_write_struct\n");
   1010    if (png_ptr_ptr != NULL)
   1011    {
   1012       png_ptr = *png_ptr_ptr;
   1013 #ifdef PNG_USER_MEM_SUPPORTED
   1014       free_fn = png_ptr->free_fn;
   1015       mem_ptr = png_ptr->mem_ptr;
   1016 #endif
   1017    }
   1018 
   1019    if (info_ptr_ptr != NULL)
   1020       info_ptr = *info_ptr_ptr;
   1021 
   1022    if (info_ptr != NULL)
   1023    {
   1024       png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
   1025 
   1026 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   1027       if (png_ptr->num_chunk_list)
   1028       {
   1029          png_free(png_ptr, png_ptr->chunk_list);
   1030          png_ptr->chunk_list=NULL;
   1031          png_ptr->num_chunk_list=0;
   1032       }
   1033 #endif
   1034 
   1035 #ifdef PNG_USER_MEM_SUPPORTED
   1036       png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
   1037          (png_voidp)mem_ptr);
   1038 #else
   1039       png_destroy_struct((png_voidp)info_ptr);
   1040 #endif
   1041       *info_ptr_ptr = NULL;
   1042    }
   1043 
   1044    if (png_ptr != NULL)
   1045    {
   1046       png_write_destroy(png_ptr);
   1047 #ifdef PNG_USER_MEM_SUPPORTED
   1048       png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
   1049          (png_voidp)mem_ptr);
   1050 #else
   1051       png_destroy_struct((png_voidp)png_ptr);
   1052 #endif
   1053       *png_ptr_ptr = NULL;
   1054    }
   1055 }
   1056 
   1057 
   1058 /* Free any memory used in png_ptr struct (old method) */
   1059 void /* PRIVATE */
   1060 png_write_destroy(png_structp png_ptr)
   1061 {
   1062 #ifdef PNG_SETJMP_SUPPORTED
   1063    jmp_buf tmp_jmp; /* save jump buffer */
   1064 #endif
   1065    png_error_ptr error_fn;
   1066    png_error_ptr warning_fn;
   1067    png_voidp error_ptr;
   1068 #ifdef PNG_USER_MEM_SUPPORTED
   1069    png_free_ptr free_fn;
   1070 #endif
   1071 
   1072    png_debug(1, "in png_write_destroy\n");
   1073    /* free any memory zlib uses */
   1074    deflateEnd(&png_ptr->zstream);
   1075 
   1076    /* free our memory.  png_free checks NULL for us. */
   1077    png_free(png_ptr, png_ptr->zbuf);
   1078    png_free(png_ptr, png_ptr->row_buf);
   1079    png_free(png_ptr, png_ptr->prev_row);
   1080    png_free(png_ptr, png_ptr->sub_row);
   1081    png_free(png_ptr, png_ptr->up_row);
   1082    png_free(png_ptr, png_ptr->avg_row);
   1083    png_free(png_ptr, png_ptr->paeth_row);
   1084 
   1085 #if defined(PNG_TIME_RFC1123_SUPPORTED)
   1086    png_free(png_ptr, png_ptr->time_buffer);
   1087 #endif
   1088 
   1089 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   1090    png_free(png_ptr, png_ptr->prev_filters);
   1091    png_free(png_ptr, png_ptr->filter_weights);
   1092    png_free(png_ptr, png_ptr->inv_filter_weights);
   1093    png_free(png_ptr, png_ptr->filter_costs);
   1094    png_free(png_ptr, png_ptr->inv_filter_costs);
   1095 #endif
   1096 
   1097 #ifdef PNG_SETJMP_SUPPORTED
   1098    /* reset structure */
   1099    png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
   1100 #endif
   1101 
   1102    error_fn = png_ptr->error_fn;
   1103    warning_fn = png_ptr->warning_fn;
   1104    error_ptr = png_ptr->error_ptr;
   1105 #ifdef PNG_USER_MEM_SUPPORTED
   1106    free_fn = png_ptr->free_fn;
   1107 #endif
   1108 
   1109    png_memset(png_ptr, 0, png_sizeof (png_struct));
   1110 
   1111    png_ptr->error_fn = error_fn;
   1112    png_ptr->warning_fn = warning_fn;
   1113    png_ptr->error_ptr = error_ptr;
   1114 #ifdef PNG_USER_MEM_SUPPORTED
   1115    png_ptr->free_fn = free_fn;
   1116 #endif
   1117 
   1118 #ifdef PNG_SETJMP_SUPPORTED
   1119    png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
   1120 #endif
   1121 }
   1122 
   1123 /* Allow the application to select one or more row filters to use. */
   1124 void PNGAPI
   1125 png_set_filter(png_structp png_ptr, int method, int filters)
   1126 {
   1127    png_debug(1, "in png_set_filter\n");
   1128    if (png_ptr == NULL)
   1129       return;
   1130 #if defined(PNG_MNG_FEATURES_SUPPORTED)
   1131    if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
   1132       (method == PNG_INTRAPIXEL_DIFFERENCING))
   1133          method = PNG_FILTER_TYPE_BASE;
   1134 #endif
   1135    if (method == PNG_FILTER_TYPE_BASE)
   1136    {
   1137       switch (filters & (PNG_ALL_FILTERS | 0x07))
   1138       {
   1139 #ifndef PNG_NO_WRITE_FILTER
   1140          case 5:
   1141          case 6:
   1142          case 7: png_warning(png_ptr, "Unknown row filter for method 0");
   1143 #endif /* PNG_NO_WRITE_FILTER */
   1144          case PNG_FILTER_VALUE_NONE:
   1145               png_ptr->do_filter=PNG_FILTER_NONE; break;
   1146 #ifndef PNG_NO_WRITE_FILTER
   1147          case PNG_FILTER_VALUE_SUB:
   1148               png_ptr->do_filter=PNG_FILTER_SUB; break;
   1149          case PNG_FILTER_VALUE_UP:
   1150               png_ptr->do_filter=PNG_FILTER_UP; break;
   1151          case PNG_FILTER_VALUE_AVG:
   1152               png_ptr->do_filter=PNG_FILTER_AVG; break;
   1153          case PNG_FILTER_VALUE_PAETH:
   1154               png_ptr->do_filter=PNG_FILTER_PAETH; break;
   1155          default: png_ptr->do_filter = (png_byte)filters; break;
   1156 #else
   1157          default: png_warning(png_ptr, "Unknown row filter for method 0");
   1158 #endif /* PNG_NO_WRITE_FILTER */
   1159       }
   1160 
   1161       /* If we have allocated the row_buf, this means we have already started
   1162        * with the image and we should have allocated all of the filter buffers
   1163        * that have been selected.  If prev_row isn't already allocated, then
   1164        * it is too late to start using the filters that need it, since we
   1165        * will be missing the data in the previous row.  If an application
   1166        * wants to start and stop using particular filters during compression,
   1167        * it should start out with all of the filters, and then add and
   1168        * remove them after the start of compression.
   1169        */
   1170       if (png_ptr->row_buf != NULL)
   1171       {
   1172 #ifndef PNG_NO_WRITE_FILTER
   1173          if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
   1174          {
   1175             png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
   1176               (png_ptr->rowbytes + 1));
   1177             png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
   1178          }
   1179 
   1180          if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
   1181          {
   1182             if (png_ptr->prev_row == NULL)
   1183             {
   1184                png_warning(png_ptr, "Can't add Up filter after starting");
   1185                png_ptr->do_filter &= ~PNG_FILTER_UP;
   1186             }
   1187             else
   1188             {
   1189                png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
   1190                   (png_ptr->rowbytes + 1));
   1191                png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
   1192             }
   1193          }
   1194 
   1195          if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
   1196          {
   1197             if (png_ptr->prev_row == NULL)
   1198             {
   1199                png_warning(png_ptr, "Can't add Average filter after starting");
   1200                png_ptr->do_filter &= ~PNG_FILTER_AVG;
   1201             }
   1202             else
   1203             {
   1204                png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
   1205                   (png_ptr->rowbytes + 1));
   1206                png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
   1207             }
   1208          }
   1209 
   1210          if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
   1211              png_ptr->paeth_row == NULL)
   1212          {
   1213             if (png_ptr->prev_row == NULL)
   1214             {
   1215                png_warning(png_ptr, "Can't add Paeth filter after starting");
   1216                png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
   1217             }
   1218             else
   1219             {
   1220                png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
   1221                   (png_ptr->rowbytes + 1));
   1222                png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
   1223             }
   1224          }
   1225 
   1226          if (png_ptr->do_filter == PNG_NO_FILTERS)
   1227 #endif /* PNG_NO_WRITE_FILTER */
   1228             png_ptr->do_filter = PNG_FILTER_NONE;
   1229       }
   1230    }
   1231    else
   1232       png_error(png_ptr, "Unknown custom filter method");
   1233 }
   1234 
   1235 /* This allows us to influence the way in which libpng chooses the "best"
   1236  * filter for the current scanline.  While the "minimum-sum-of-absolute-
   1237  * differences metric is relatively fast and effective, there is some
   1238  * question as to whether it can be improved upon by trying to keep the
   1239  * filtered data going to zlib more consistent, hopefully resulting in
   1240  * better compression.
   1241  */
   1242 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
   1243 void PNGAPI
   1244 png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
   1245    int num_weights, png_doublep filter_weights,
   1246    png_doublep filter_costs)
   1247 {
   1248    int i;
   1249 
   1250    png_debug(1, "in png_set_filter_heuristics\n");
   1251    if (png_ptr == NULL)
   1252       return;
   1253    if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
   1254    {
   1255       png_warning(png_ptr, "Unknown filter heuristic method");
   1256       return;
   1257    }
   1258 
   1259    if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
   1260    {
   1261       heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
   1262    }
   1263 
   1264    if (num_weights < 0 || filter_weights == NULL ||
   1265       heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
   1266    {
   1267       num_weights = 0;
   1268    }
   1269 
   1270    png_ptr->num_prev_filters = (png_byte)num_weights;
   1271    png_ptr->heuristic_method = (png_byte)heuristic_method;
   1272 
   1273    if (num_weights > 0)
   1274    {
   1275       if (png_ptr->prev_filters == NULL)
   1276       {
   1277          png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
   1278             (png_uint_32)(png_sizeof(png_byte) * num_weights));
   1279 
   1280          /* To make sure that the weighting starts out fairly */
   1281          for (i = 0; i < num_weights; i++)
   1282          {
   1283             png_ptr->prev_filters[i] = 255;
   1284          }
   1285       }
   1286 
   1287       if (png_ptr->filter_weights == NULL)
   1288       {
   1289          png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
   1290             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
   1291 
   1292          png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
   1293             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
   1294          for (i = 0; i < num_weights; i++)
   1295          {
   1296             png_ptr->inv_filter_weights[i] =
   1297             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
   1298          }
   1299       }
   1300 
   1301       for (i = 0; i < num_weights; i++)
   1302       {
   1303          if (filter_weights[i] < 0.0)
   1304          {
   1305             png_ptr->inv_filter_weights[i] =
   1306             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
   1307          }
   1308          else
   1309          {
   1310             png_ptr->inv_filter_weights[i] =
   1311                (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
   1312             png_ptr->filter_weights[i] =
   1313                (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
   1314          }
   1315       }
   1316    }
   1317 
   1318    /* If, in the future, there are other filter methods, this would
   1319     * need to be based on png_ptr->filter.
   1320     */
   1321    if (png_ptr->filter_costs == NULL)
   1322    {
   1323       png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
   1324          (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
   1325 
   1326       png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
   1327          (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
   1328 
   1329       for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
   1330       {
   1331          png_ptr->inv_filter_costs[i] =
   1332          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
   1333       }
   1334    }
   1335 
   1336    /* Here is where we set the relative costs of the different filters.  We
   1337     * should take the desired compression level into account when setting
   1338     * the costs, so that Paeth, for instance, has a high relative cost at low
   1339     * compression levels, while it has a lower relative cost at higher
   1340     * compression settings.  The filter types are in order of increasing
   1341     * relative cost, so it would be possible to do this with an algorithm.
   1342     */
   1343    for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
   1344    {
   1345       if (filter_costs == NULL || filter_costs[i] < 0.0)
   1346       {
   1347          png_ptr->inv_filter_costs[i] =
   1348          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
   1349       }
   1350       else if (filter_costs[i] >= 1.0)
   1351       {
   1352          png_ptr->inv_filter_costs[i] =
   1353             (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
   1354          png_ptr->filter_costs[i] =
   1355             (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
   1356       }
   1357    }
   1358 }
   1359 #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
   1360 
   1361 void PNGAPI
   1362 png_set_compression_level(png_structp png_ptr, int level)
   1363 {
   1364    png_debug(1, "in png_set_compression_level\n");
   1365    if (png_ptr == NULL)
   1366       return;
   1367    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
   1368    png_ptr->zlib_level = level;
   1369 }
   1370 
   1371 void PNGAPI
   1372 png_set_compression_mem_level(png_structp png_ptr, int mem_level)
   1373 {
   1374    png_debug(1, "in png_set_compression_mem_level\n");
   1375    if (png_ptr == NULL)
   1376       return;
   1377    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
   1378    png_ptr->zlib_mem_level = mem_level;
   1379 }
   1380 
   1381 void PNGAPI
   1382 png_set_compression_strategy(png_structp png_ptr, int strategy)
   1383 {
   1384    png_debug(1, "in png_set_compression_strategy\n");
   1385    if (png_ptr == NULL)
   1386       return;
   1387    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
   1388    png_ptr->zlib_strategy = strategy;
   1389 }
   1390 
   1391 void PNGAPI
   1392 png_set_compression_window_bits(png_structp png_ptr, int window_bits)
   1393 {
   1394    if (png_ptr == NULL)
   1395       return;
   1396    if (window_bits > 15)
   1397       png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
   1398    else if (window_bits < 8)
   1399       png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
   1400 #ifndef WBITS_8_OK
   1401    /* avoid libpng bug with 256-byte windows */
   1402    if (window_bits == 8)
   1403      {
   1404        png_warning(png_ptr, "Compression window is being reset to 512");
   1405        window_bits=9;
   1406      }
   1407 #endif
   1408    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
   1409    png_ptr->zlib_window_bits = window_bits;
   1410 }
   1411 
   1412 void PNGAPI
   1413 png_set_compression_method(png_structp png_ptr, int method)
   1414 {
   1415    png_debug(1, "in png_set_compression_method\n");
   1416    if (png_ptr == NULL)
   1417       return;
   1418    if (method != 8)
   1419       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
   1420    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
   1421    png_ptr->zlib_method = method;
   1422 }
   1423 
   1424 void PNGAPI
   1425 png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
   1426 {
   1427    if (png_ptr == NULL)
   1428       return;
   1429    png_ptr->write_row_fn = write_row_fn;
   1430 }
   1431 
   1432 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
   1433 void PNGAPI
   1434 png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
   1435    write_user_transform_fn)
   1436 {
   1437    png_debug(1, "in png_set_write_user_transform_fn\n");
   1438    if (png_ptr == NULL)
   1439       return;
   1440    png_ptr->transformations |= PNG_USER_TRANSFORM;
   1441    png_ptr->write_user_transform_fn = write_user_transform_fn;
   1442 }
   1443 #endif
   1444 
   1445 
   1446 #if defined(PNG_INFO_IMAGE_SUPPORTED)
   1447 void PNGAPI
   1448 png_write_png(png_structp png_ptr, png_infop info_ptr,
   1449               int transforms, voidp params)
   1450 {
   1451    if (png_ptr == NULL || info_ptr == NULL)
   1452       return;
   1453 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
   1454    /* invert the alpha channel from opacity to transparency */
   1455    if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
   1456        png_set_invert_alpha(png_ptr);
   1457 #endif
   1458 
   1459    /* Write the file header information. */
   1460    png_write_info(png_ptr, info_ptr);
   1461 
   1462    /* ------ these transformations don't touch the info structure ------- */
   1463 
   1464 #if defined(PNG_WRITE_INVERT_SUPPORTED)
   1465    /* invert monochrome pixels */
   1466    if (transforms & PNG_TRANSFORM_INVERT_MONO)
   1467        png_set_invert_mono(png_ptr);
   1468 #endif
   1469 
   1470 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
   1471    /* Shift the pixels up to a legal bit depth and fill in
   1472     * as appropriate to correctly scale the image.
   1473     */
   1474    if ((transforms & PNG_TRANSFORM_SHIFT)
   1475                && (info_ptr->valid & PNG_INFO_sBIT))
   1476        png_set_shift(png_ptr, &info_ptr->sig_bit);
   1477 #endif
   1478 
   1479 #if defined(PNG_WRITE_PACK_SUPPORTED)
   1480    /* pack pixels into bytes */
   1481    if (transforms & PNG_TRANSFORM_PACKING)
   1482        png_set_packing(png_ptr);
   1483 #endif
   1484 
   1485 #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
   1486    /* swap location of alpha bytes from ARGB to RGBA */
   1487    if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
   1488        png_set_swap_alpha(png_ptr);
   1489 #endif
   1490 
   1491 #if defined(PNG_WRITE_FILLER_SUPPORTED)
   1492    /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
   1493     * RGB (4 channels -> 3 channels). The second parameter is not used.
   1494     */
   1495    if (transforms & PNG_TRANSFORM_STRIP_FILLER)
   1496        png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
   1497 #endif
   1498 
   1499 #if defined(PNG_WRITE_BGR_SUPPORTED)
   1500    /* flip BGR pixels to RGB */
   1501    if (transforms & PNG_TRANSFORM_BGR)
   1502        png_set_bgr(png_ptr);
   1503 #endif
   1504 
   1505 #if defined(PNG_WRITE_SWAP_SUPPORTED)
   1506    /* swap bytes of 16-bit files to most significant byte first */
   1507    if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
   1508        png_set_swap(png_ptr);
   1509 #endif
   1510 
   1511 #if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
   1512    /* swap bits of 1, 2, 4 bit packed pixel formats */
   1513    if (transforms & PNG_TRANSFORM_PACKSWAP)
   1514        png_set_packswap(png_ptr);
   1515 #endif
   1516 
   1517    /* ----------------------- end of transformations ------------------- */
   1518 
   1519    /* write the bits */
   1520    if (info_ptr->valid & PNG_INFO_IDAT)
   1521        png_write_image(png_ptr, info_ptr->row_pointers);
   1522 
   1523    /* It is REQUIRED to call this to finish writing the rest of the file */
   1524    png_write_end(png_ptr, info_ptr);
   1525 
   1526    transforms = transforms; /* quiet compiler warnings */
   1527    params = params;
   1528 }
   1529 #endif
   1530 #endif /* PNG_WRITE_SUPPORTED */
   1531