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