Home | History | Annotate | Download | only in libpng
      1 
      2 /* pngwrite.c - general routines to write a PNG file
      3  *
      4  * Last changed in libpng 1.6.32 [August 24, 2017]
      5  * Copyright (c) 1998-2002,2004,2006-2017 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 #include "pngpriv.h"
     15 #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
     16 #  include <errno.h>
     17 #endif /* SIMPLIFIED_WRITE_STDIO */
     18 
     19 #ifdef PNG_WRITE_SUPPORTED
     20 
     21 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
     22 /* Write out all the unknown chunks for the current given location */
     23 static void
     24 write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
     25     unsigned int where)
     26 {
     27    if (info_ptr->unknown_chunks_num != 0)
     28    {
     29       png_const_unknown_chunkp up;
     30 
     31       png_debug(5, "writing extra chunks");
     32 
     33       for (up = info_ptr->unknown_chunks;
     34            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
     35            ++up)
     36          if ((up->location & where) != 0)
     37       {
     38          /* If per-chunk unknown chunk handling is enabled use it, otherwise
     39           * just write the chunks the application has set.
     40           */
     41 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
     42          int keep = png_handle_as_unknown(png_ptr, up->name);
     43 
     44          /* NOTE: this code is radically different from the read side in the
     45           * matter of handling an ancillary unknown chunk.  In the read side
     46           * the default behavior is to discard it, in the code below the default
     47           * behavior is to write it.  Critical chunks are, however, only
     48           * written if explicitly listed or if the default is set to write all
     49           * unknown chunks.
     50           *
     51           * The default handling is also slightly weird - it is not possible to
     52           * stop the writing of all unsafe-to-copy chunks!
     53           *
     54           * TODO: REVIEW: this would seem to be a bug.
     55           */
     56          if (keep != PNG_HANDLE_CHUNK_NEVER &&
     57              ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||
     58               keep == PNG_HANDLE_CHUNK_ALWAYS ||
     59               (keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&
     60                png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))
     61 #endif
     62          {
     63             /* TODO: review, what is wrong with a zero length unknown chunk? */
     64             if (up->size == 0)
     65                png_warning(png_ptr, "Writing zero-length unknown chunk");
     66 
     67             png_write_chunk(png_ptr, up->name, up->data, up->size);
     68          }
     69       }
     70    }
     71 }
     72 #endif /* WRITE_UNKNOWN_CHUNKS */
     73 
     74 /* Writes all the PNG information.  This is the suggested way to use the
     75  * library.  If you have a new chunk to add, make a function to write it,
     76  * and put it in the correct location here.  If you want the chunk written
     77  * after the image data, put it in png_write_end().  I strongly encourage
     78  * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
     79  * the chunk, as that will keep the code from breaking if you want to just
     80  * write a plain PNG file.  If you have long comments, I suggest writing
     81  * them in png_write_end(), and compressing them.
     82  */
     83 void PNGAPI
     84 png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
     85 {
     86    png_debug(1, "in png_write_info_before_PLTE");
     87 
     88    if (png_ptr == NULL || info_ptr == NULL)
     89       return;
     90 
     91    if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
     92    {
     93       /* Write PNG signature */
     94       png_write_sig(png_ptr);
     95 
     96 #ifdef PNG_MNG_FEATURES_SUPPORTED
     97       if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \
     98           png_ptr->mng_features_permitted != 0)
     99       {
    100          png_warning(png_ptr,
    101              "MNG features are not allowed in a PNG datastream");
    102          png_ptr->mng_features_permitted = 0;
    103       }
    104 #endif
    105 
    106       /* Write IHDR information. */
    107       png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
    108           info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
    109           info_ptr->filter_type,
    110 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
    111           info_ptr->interlace_type
    112 #else
    113           0
    114 #endif
    115          );
    116 
    117       /* The rest of these check to see if the valid field has the appropriate
    118        * flag set, and if it does, writes the chunk.
    119        *
    120        * 1.6.0: COLORSPACE support controls the writing of these chunks too, and
    121        * the chunks will be written if the WRITE routine is there and
    122        * information * is available in the COLORSPACE. (See
    123        * png_colorspace_sync_info in png.c for where the valid flags get set.)
    124        *
    125        * Under certain circumstances the colorspace can be invalidated without
    126        * syncing the info_struct 'valid' flags; this happens if libpng detects
    127        * an error and calls png_error while the color space is being set, yet
    128        * the application continues writing the PNG.  So check the 'invalid'
    129        * flag here too.
    130        */
    131 #ifdef PNG_GAMMA_SUPPORTED
    132 #  ifdef PNG_WRITE_gAMA_SUPPORTED
    133       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
    134           (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
    135           (info_ptr->valid & PNG_INFO_gAMA) != 0)
    136          png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
    137 #  endif
    138 #endif
    139 
    140 #ifdef PNG_COLORSPACE_SUPPORTED
    141       /* Write only one of sRGB or an ICC profile.  If a profile was supplied
    142        * and it matches one of the known sRGB ones issue a warning.
    143        */
    144 #  ifdef PNG_WRITE_iCCP_SUPPORTED
    145          if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
    146              (info_ptr->valid & PNG_INFO_iCCP) != 0)
    147          {
    148 #    ifdef PNG_WRITE_sRGB_SUPPORTED
    149                if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
    150                   png_app_warning(png_ptr,
    151                       "profile matches sRGB but writing iCCP instead");
    152 #     endif
    153 
    154             png_write_iCCP(png_ptr, info_ptr->iccp_name,
    155                 info_ptr->iccp_profile);
    156          }
    157 #     ifdef PNG_WRITE_sRGB_SUPPORTED
    158          else
    159 #     endif
    160 #  endif
    161 
    162 #  ifdef PNG_WRITE_sRGB_SUPPORTED
    163          if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
    164              (info_ptr->valid & PNG_INFO_sRGB) != 0)
    165             png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
    166 #  endif /* WRITE_sRGB */
    167 #endif /* COLORSPACE */
    168 
    169 #ifdef PNG_WRITE_sBIT_SUPPORTED
    170          if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
    171             png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
    172 #endif
    173 
    174 #ifdef PNG_COLORSPACE_SUPPORTED
    175 #  ifdef PNG_WRITE_cHRM_SUPPORTED
    176          if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
    177              (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&
    178              (info_ptr->valid & PNG_INFO_cHRM) != 0)
    179             png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);
    180 #  endif
    181 #endif
    182 
    183 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
    184          write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
    185 #endif
    186 
    187       png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
    188    }
    189 }
    190 
    191 void PNGAPI
    192 png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
    193 {
    194 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
    195    int i;
    196 #endif
    197 
    198    png_debug(1, "in png_write_info");
    199 
    200    if (png_ptr == NULL || info_ptr == NULL)
    201       return;
    202 
    203    png_write_info_before_PLTE(png_ptr, info_ptr);
    204 
    205    if ((info_ptr->valid & PNG_INFO_PLTE) != 0)
    206       png_write_PLTE(png_ptr, info_ptr->palette,
    207           (png_uint_32)info_ptr->num_palette);
    208 
    209    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    210       png_error(png_ptr, "Valid palette required for paletted images");
    211 
    212 #ifdef PNG_WRITE_tRNS_SUPPORTED
    213    if ((info_ptr->valid & PNG_INFO_tRNS) !=0)
    214    {
    215 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
    216       /* Invert the alpha channel (in tRNS) */
    217       if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&
    218           info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    219       {
    220          int j, jend;
    221 
    222          jend = info_ptr->num_trans;
    223          if (jend > PNG_MAX_PALETTE_LENGTH)
    224             jend = PNG_MAX_PALETTE_LENGTH;
    225 
    226          for (j = 0; j<jend; ++j)
    227             info_ptr->trans_alpha[j] =
    228                (png_byte)(255 - info_ptr->trans_alpha[j]);
    229       }
    230 #endif
    231       png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),
    232           info_ptr->num_trans, info_ptr->color_type);
    233    }
    234 #endif
    235 #ifdef PNG_WRITE_bKGD_SUPPORTED
    236    if ((info_ptr->valid & PNG_INFO_bKGD) != 0)
    237       png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
    238 #endif
    239 
    240 #ifdef PNG_WRITE_eXIf_SUPPORTED
    241    if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
    242       png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
    243 #endif
    244 
    245 #ifdef PNG_WRITE_hIST_SUPPORTED
    246    if ((info_ptr->valid & PNG_INFO_hIST) != 0)
    247       png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
    248 #endif
    249 
    250 #ifdef PNG_WRITE_oFFs_SUPPORTED
    251    if ((info_ptr->valid & PNG_INFO_oFFs) != 0)
    252       png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
    253           info_ptr->offset_unit_type);
    254 #endif
    255 
    256 #ifdef PNG_WRITE_pCAL_SUPPORTED
    257    if ((info_ptr->valid & PNG_INFO_pCAL) != 0)
    258       png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
    259           info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
    260           info_ptr->pcal_units, info_ptr->pcal_params);
    261 #endif
    262 
    263 #ifdef PNG_WRITE_sCAL_SUPPORTED
    264    if ((info_ptr->valid & PNG_INFO_sCAL) != 0)
    265       png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
    266           info_ptr->scal_s_width, info_ptr->scal_s_height);
    267 #endif /* sCAL */
    268 
    269 #ifdef PNG_WRITE_pHYs_SUPPORTED
    270    if ((info_ptr->valid & PNG_INFO_pHYs) != 0)
    271       png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
    272           info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
    273 #endif /* pHYs */
    274 
    275 #ifdef PNG_WRITE_tIME_SUPPORTED
    276    if ((info_ptr->valid & PNG_INFO_tIME) != 0)
    277    {
    278       png_write_tIME(png_ptr, &(info_ptr->mod_time));
    279       png_ptr->mode |= PNG_WROTE_tIME;
    280    }
    281 #endif /* tIME */
    282 
    283 #ifdef PNG_WRITE_sPLT_SUPPORTED
    284    if ((info_ptr->valid & PNG_INFO_sPLT) != 0)
    285       for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
    286          png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
    287 #endif /* sPLT */
    288 
    289 #ifdef PNG_WRITE_TEXT_SUPPORTED
    290    /* Check to see if we need to write text chunks */
    291    for (i = 0; i < info_ptr->num_text; i++)
    292    {
    293       png_debug2(2, "Writing header text chunk %d, type %d", i,
    294           info_ptr->text[i].compression);
    295       /* An internationalized chunk? */
    296       if (info_ptr->text[i].compression > 0)
    297       {
    298 #ifdef PNG_WRITE_iTXt_SUPPORTED
    299          /* Write international chunk */
    300          png_write_iTXt(png_ptr,
    301              info_ptr->text[i].compression,
    302              info_ptr->text[i].key,
    303              info_ptr->text[i].lang,
    304              info_ptr->text[i].lang_key,
    305              info_ptr->text[i].text);
    306          /* Mark this chunk as written */
    307          if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    308             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    309          else
    310             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    311 #else
    312          png_warning(png_ptr, "Unable to write international text");
    313 #endif
    314       }
    315 
    316       /* If we want a compressed text chunk */
    317       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
    318       {
    319 #ifdef PNG_WRITE_zTXt_SUPPORTED
    320          /* Write compressed chunk */
    321          png_write_zTXt(png_ptr, info_ptr->text[i].key,
    322              info_ptr->text[i].text, info_ptr->text[i].compression);
    323          /* Mark this chunk as written */
    324          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    325 #else
    326          png_warning(png_ptr, "Unable to write compressed text");
    327 #endif
    328       }
    329 
    330       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    331       {
    332 #ifdef PNG_WRITE_tEXt_SUPPORTED
    333          /* Write uncompressed chunk */
    334          png_write_tEXt(png_ptr, info_ptr->text[i].key,
    335              info_ptr->text[i].text,
    336              0);
    337          /* Mark this chunk as written */
    338          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    339 #else
    340          /* Can't get here */
    341          png_warning(png_ptr, "Unable to write uncompressed text");
    342 #endif
    343       }
    344    }
    345 #endif /* tEXt */
    346 
    347 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
    348    write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);
    349 #endif
    350 }
    351 
    352 /* Writes the end of the PNG file.  If you don't want to write comments or
    353  * time information, you can pass NULL for info.  If you already wrote these
    354  * in png_write_info(), do not write them again here.  If you have long
    355  * comments, I suggest writing them here, and compressing them.
    356  */
    357 void PNGAPI
    358 png_write_end(png_structrp png_ptr, png_inforp info_ptr)
    359 {
    360    png_debug(1, "in png_write_end");
    361 
    362    if (png_ptr == NULL)
    363       return;
    364 
    365    if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
    366       png_error(png_ptr, "No IDATs written into file");
    367 
    368 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
    369    if (png_ptr->num_palette_max > png_ptr->num_palette)
    370       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
    371 #endif
    372 
    373    /* See if user wants us to write information chunks */
    374    if (info_ptr != NULL)
    375    {
    376 #ifdef PNG_WRITE_TEXT_SUPPORTED
    377       int i; /* local index variable */
    378 #endif
    379 #ifdef PNG_WRITE_tIME_SUPPORTED
    380       /* Check to see if user has supplied a time chunk */
    381       if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&
    382           (png_ptr->mode & PNG_WROTE_tIME) == 0)
    383          png_write_tIME(png_ptr, &(info_ptr->mod_time));
    384 
    385 #endif
    386 #ifdef PNG_WRITE_TEXT_SUPPORTED
    387       /* Loop through comment chunks */
    388       for (i = 0; i < info_ptr->num_text; i++)
    389       {
    390          png_debug2(2, "Writing trailer text chunk %d, type %d", i,
    391              info_ptr->text[i].compression);
    392          /* An internationalized chunk? */
    393          if (info_ptr->text[i].compression > 0)
    394          {
    395 #ifdef PNG_WRITE_iTXt_SUPPORTED
    396             /* Write international chunk */
    397             png_write_iTXt(png_ptr,
    398                 info_ptr->text[i].compression,
    399                 info_ptr->text[i].key,
    400                 info_ptr->text[i].lang,
    401                 info_ptr->text[i].lang_key,
    402                 info_ptr->text[i].text);
    403             /* Mark this chunk as written */
    404             if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    405                info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    406             else
    407                info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    408 #else
    409             png_warning(png_ptr, "Unable to write international text");
    410 #endif
    411          }
    412 
    413          else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
    414          {
    415 #ifdef PNG_WRITE_zTXt_SUPPORTED
    416             /* Write compressed chunk */
    417             png_write_zTXt(png_ptr, info_ptr->text[i].key,
    418                 info_ptr->text[i].text, info_ptr->text[i].compression);
    419             /* Mark this chunk as written */
    420             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
    421 #else
    422             png_warning(png_ptr, "Unable to write compressed text");
    423 #endif
    424          }
    425 
    426          else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
    427          {
    428 #ifdef PNG_WRITE_tEXt_SUPPORTED
    429             /* Write uncompressed chunk */
    430             png_write_tEXt(png_ptr, info_ptr->text[i].key,
    431                 info_ptr->text[i].text, 0);
    432             /* Mark this chunk as written */
    433             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
    434 #else
    435             png_warning(png_ptr, "Unable to write uncompressed text");
    436 #endif
    437          }
    438       }
    439 #endif
    440 
    441 #ifdef PNG_WRITE_eXIf_SUPPORTED
    442    if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
    443       png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
    444 #endif
    445 
    446 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
    447       write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
    448 #endif
    449    }
    450 
    451    png_ptr->mode |= PNG_AFTER_IDAT;
    452 
    453    /* Write end of PNG file */
    454    png_write_IEND(png_ptr);
    455 
    456    /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
    457     * and restored again in libpng-1.2.30, may cause some applications that
    458     * do not set png_ptr->output_flush_fn to crash.  If your application
    459     * experiences a problem, please try building libpng with
    460     * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
    461     * png-mng-implement at lists.sf.net .
    462     */
    463 #ifdef PNG_WRITE_FLUSH_SUPPORTED
    464 #  ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
    465    png_flush(png_ptr);
    466 #  endif
    467 #endif
    468 }
    469 
    470 #ifdef PNG_CONVERT_tIME_SUPPORTED
    471 void PNGAPI
    472 png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime)
    473 {
    474    png_debug(1, "in png_convert_from_struct_tm");
    475 
    476    ptime->year = (png_uint_16)(1900 + ttime->tm_year);
    477    ptime->month = (png_byte)(ttime->tm_mon + 1);
    478    ptime->day = (png_byte)ttime->tm_mday;
    479    ptime->hour = (png_byte)ttime->tm_hour;
    480    ptime->minute = (png_byte)ttime->tm_min;
    481    ptime->second = (png_byte)ttime->tm_sec;
    482 }
    483 
    484 void PNGAPI
    485 png_convert_from_time_t(png_timep ptime, time_t ttime)
    486 {
    487    struct tm *tbuf;
    488 
    489    png_debug(1, "in png_convert_from_time_t");
    490 
    491    tbuf = gmtime(&ttime);
    492    png_convert_from_struct_tm(ptime, tbuf);
    493 }
    494 #endif
    495 
    496 /* Initialize png_ptr structure, and allocate any memory needed */
    497 PNG_FUNCTION(png_structp,PNGAPI
    498 png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
    499     png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
    500 {
    501 #ifndef PNG_USER_MEM_SUPPORTED
    502    png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
    503        error_fn, warn_fn, NULL, NULL, NULL);
    504 #else
    505    return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
    506        warn_fn, NULL, NULL, NULL);
    507 }
    508 
    509 /* Alternate initialize png_ptr structure, and allocate any memory needed */
    510 PNG_FUNCTION(png_structp,PNGAPI
    511 png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    512     png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
    513     png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
    514 {
    515    png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
    516        error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
    517 #endif /* USER_MEM */
    518    if (png_ptr != NULL)
    519    {
    520       /* Set the zlib control values to defaults; they can be overridden by the
    521        * application after the struct has been created.
    522        */
    523       png_ptr->zbuffer_size = PNG_ZBUF_SIZE;
    524 
    525       /* The 'zlib_strategy' setting is irrelevant because png_default_claim in
    526        * pngwutil.c defaults it according to whether or not filters will be
    527        * used, and ignores this setting.
    528        */
    529       png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;
    530       png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;
    531       png_ptr->zlib_mem_level = 8;
    532       png_ptr->zlib_window_bits = 15;
    533       png_ptr->zlib_method = 8;
    534 
    535 #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
    536       png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;
    537       png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;
    538       png_ptr->zlib_text_mem_level = 8;
    539       png_ptr->zlib_text_window_bits = 15;
    540       png_ptr->zlib_text_method = 8;
    541 #endif /* WRITE_COMPRESSED_TEXT */
    542 
    543       /* This is a highly dubious configuration option; by default it is off,
    544        * but it may be appropriate for private builds that are testing
    545        * extensions not conformant to the current specification, or of
    546        * applications that must not fail to write at all costs!
    547        */
    548 #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
    549       /* In stable builds only warn if an application error can be completely
    550        * handled.
    551        */
    552       png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
    553 #endif
    554 
    555       /* App warnings are warnings in release (or release candidate) builds but
    556        * are errors during development.
    557        */
    558 #if PNG_RELEASE_BUILD
    559       png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
    560 #endif
    561 
    562       /* TODO: delay this, it can be done in png_init_io() (if the app doesn't
    563        * do it itself) avoiding setting the default function if it is not
    564        * required.
    565        */
    566       png_set_write_fn(png_ptr, NULL, NULL, NULL);
    567    }
    568 
    569    return png_ptr;
    570 }
    571 
    572 
    573 /* Write a few rows of image data.  If the image is interlaced,
    574  * either you will have to write the 7 sub images, or, if you
    575  * have called png_set_interlace_handling(), you will have to
    576  * "write" the image seven times.
    577  */
    578 void PNGAPI
    579 png_write_rows(png_structrp png_ptr, png_bytepp row,
    580     png_uint_32 num_rows)
    581 {
    582    png_uint_32 i; /* row counter */
    583    png_bytepp rp; /* row pointer */
    584 
    585    png_debug(1, "in png_write_rows");
    586 
    587    if (png_ptr == NULL)
    588       return;
    589 
    590    /* Loop through the rows */
    591    for (i = 0, rp = row; i < num_rows; i++, rp++)
    592    {
    593       png_write_row(png_ptr, *rp);
    594    }
    595 }
    596 
    597 /* Write the image.  You only need to call this function once, even
    598  * if you are writing an interlaced image.
    599  */
    600 void PNGAPI
    601 png_write_image(png_structrp png_ptr, png_bytepp image)
    602 {
    603    png_uint_32 i; /* row index */
    604    int pass, num_pass; /* pass variables */
    605    png_bytepp rp; /* points to current row */
    606 
    607    if (png_ptr == NULL)
    608       return;
    609 
    610    png_debug(1, "in png_write_image");
    611 
    612 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
    613    /* Initialize interlace handling.  If image is not interlaced,
    614     * this will set pass to 1
    615     */
    616    num_pass = png_set_interlace_handling(png_ptr);
    617 #else
    618    num_pass = 1;
    619 #endif
    620    /* Loop through passes */
    621    for (pass = 0; pass < num_pass; pass++)
    622    {
    623       /* Loop through image */
    624       for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
    625       {
    626          png_write_row(png_ptr, *rp);
    627       }
    628    }
    629 }
    630 
    631 #ifdef PNG_MNG_FEATURES_SUPPORTED
    632 /* Performs intrapixel differencing  */
    633 static void
    634 png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
    635 {
    636    png_debug(1, "in png_do_write_intrapixel");
    637 
    638    if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
    639    {
    640       int bytes_per_pixel;
    641       png_uint_32 row_width = row_info->width;
    642       if (row_info->bit_depth == 8)
    643       {
    644          png_bytep rp;
    645          png_uint_32 i;
    646 
    647          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
    648             bytes_per_pixel = 3;
    649 
    650          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    651             bytes_per_pixel = 4;
    652 
    653          else
    654             return;
    655 
    656          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
    657          {
    658             *(rp)     = (png_byte)(*rp       - *(rp + 1));
    659             *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1));
    660          }
    661       }
    662 
    663 #ifdef PNG_WRITE_16BIT_SUPPORTED
    664       else if (row_info->bit_depth == 16)
    665       {
    666          png_bytep rp;
    667          png_uint_32 i;
    668 
    669          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
    670             bytes_per_pixel = 6;
    671 
    672          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    673             bytes_per_pixel = 8;
    674 
    675          else
    676             return;
    677 
    678          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
    679          {
    680             png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);
    681             png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
    682             png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
    683             png_uint_32 red  = (png_uint_32)((s0 - s1) & 0xffffL);
    684             png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
    685             *(rp    ) = (png_byte)(red >> 8);
    686             *(rp + 1) = (png_byte)red;
    687             *(rp + 4) = (png_byte)(blue >> 8);
    688             *(rp + 5) = (png_byte)blue;
    689          }
    690       }
    691 #endif /* WRITE_16BIT */
    692    }
    693 }
    694 #endif /* MNG_FEATURES */
    695 
    696 /* Called by user to write a row of image data */
    697 void PNGAPI
    698 png_write_row(png_structrp png_ptr, png_const_bytep row)
    699 {
    700    /* 1.5.6: moved from png_struct to be a local structure: */
    701    png_row_info row_info;
    702 
    703    if (png_ptr == NULL)
    704       return;
    705 
    706    png_debug2(1, "in png_write_row (row %u, pass %d)",
    707        png_ptr->row_number, png_ptr->pass);
    708 
    709    /* Initialize transformations and other stuff if first time */
    710    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
    711    {
    712       /* Make sure we wrote the header info */
    713       if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
    714          png_error(png_ptr,
    715              "png_write_info was never called before png_write_row");
    716 
    717       /* Check for transforms that have been set but were defined out */
    718 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
    719       if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
    720          png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
    721 #endif
    722 
    723 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
    724       if ((png_ptr->transformations & PNG_FILLER) != 0)
    725          png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
    726 #endif
    727 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
    728     defined(PNG_READ_PACKSWAP_SUPPORTED)
    729       if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
    730          png_warning(png_ptr,
    731              "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
    732 #endif
    733 
    734 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
    735       if ((png_ptr->transformations & PNG_PACK) != 0)
    736          png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
    737 #endif
    738 
    739 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
    740       if ((png_ptr->transformations & PNG_SHIFT) != 0)
    741          png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
    742 #endif
    743 
    744 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
    745       if ((png_ptr->transformations & PNG_BGR) != 0)
    746          png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
    747 #endif
    748 
    749 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
    750       if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
    751          png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
    752 #endif
    753 
    754       png_write_start_row(png_ptr);
    755    }
    756 
    757 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
    758    /* If interlaced and not interested in row, return */
    759    if (png_ptr->interlaced != 0 &&
    760        (png_ptr->transformations & PNG_INTERLACE) != 0)
    761    {
    762       switch (png_ptr->pass)
    763       {
    764          case 0:
    765             if ((png_ptr->row_number & 0x07) != 0)
    766             {
    767                png_write_finish_row(png_ptr);
    768                return;
    769             }
    770             break;
    771 
    772          case 1:
    773             if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5)
    774             {
    775                png_write_finish_row(png_ptr);
    776                return;
    777             }
    778             break;
    779 
    780          case 2:
    781             if ((png_ptr->row_number & 0x07) != 4)
    782             {
    783                png_write_finish_row(png_ptr);
    784                return;
    785             }
    786             break;
    787 
    788          case 3:
    789             if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3)
    790             {
    791                png_write_finish_row(png_ptr);
    792                return;
    793             }
    794             break;
    795 
    796          case 4:
    797             if ((png_ptr->row_number & 0x03) != 2)
    798             {
    799                png_write_finish_row(png_ptr);
    800                return;
    801             }
    802             break;
    803 
    804          case 5:
    805             if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2)
    806             {
    807                png_write_finish_row(png_ptr);
    808                return;
    809             }
    810             break;
    811 
    812          case 6:
    813             if ((png_ptr->row_number & 0x01) == 0)
    814             {
    815                png_write_finish_row(png_ptr);
    816                return;
    817             }
    818             break;
    819 
    820          default: /* error: ignore it */
    821             break;
    822       }
    823    }
    824 #endif
    825 
    826    /* Set up row info for transformations */
    827    row_info.color_type = png_ptr->color_type;
    828    row_info.width = png_ptr->usr_width;
    829    row_info.channels = png_ptr->usr_channels;
    830    row_info.bit_depth = png_ptr->usr_bit_depth;
    831    row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);
    832    row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
    833 
    834    png_debug1(3, "row_info->color_type = %d", row_info.color_type);
    835    png_debug1(3, "row_info->width = %u", row_info.width);
    836    png_debug1(3, "row_info->channels = %d", row_info.channels);
    837    png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth);
    838    png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth);
    839    png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes);
    840 
    841    /* Copy user's row into buffer, leaving room for filter byte. */
    842    memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);
    843 
    844 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
    845    /* Handle interlacing */
    846    if (png_ptr->interlaced && png_ptr->pass < 6 &&
    847        (png_ptr->transformations & PNG_INTERLACE) != 0)
    848    {
    849       png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
    850       /* This should always get caught above, but still ... */
    851       if (row_info.width == 0)
    852       {
    853          png_write_finish_row(png_ptr);
    854          return;
    855       }
    856    }
    857 #endif
    858 
    859 #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
    860    /* Handle other transformations */
    861    if (png_ptr->transformations != 0)
    862       png_do_write_transformations(png_ptr, &row_info);
    863 #endif
    864 
    865    /* At this point the row_info pixel depth must match the 'transformed' depth,
    866     * which is also the output depth.
    867     */
    868    if (row_info.pixel_depth != png_ptr->pixel_depth ||
    869        row_info.pixel_depth != png_ptr->transformed_pixel_depth)
    870       png_error(png_ptr, "internal write transform logic error");
    871 
    872 #ifdef PNG_MNG_FEATURES_SUPPORTED
    873    /* Write filter_method 64 (intrapixel differencing) only if
    874     * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    875     * 2. Libpng did not write a PNG signature (this filter_method is only
    876     *    used in PNG datastreams that are embedded in MNG datastreams) and
    877     * 3. The application called png_permit_mng_features with a mask that
    878     *    included PNG_FLAG_MNG_FILTER_64 and
    879     * 4. The filter_method is 64 and
    880     * 5. The color_type is RGB or RGBA
    881     */
    882    if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
    883        (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
    884    {
    885       /* Intrapixel differencing */
    886       png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);
    887    }
    888 #endif
    889 
    890 /* Added at libpng-1.5.10 */
    891 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
    892    /* Check for out-of-range palette index */
    893    if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
    894        png_ptr->num_palette_max >= 0)
    895       png_do_check_palette_indexes(png_ptr, &row_info);
    896 #endif
    897 
    898    /* Find a filter if necessary, filter the row and write it out. */
    899    png_write_find_filter(png_ptr, &row_info);
    900 
    901    if (png_ptr->write_row_fn != NULL)
    902       (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
    903 }
    904 
    905 #ifdef PNG_WRITE_FLUSH_SUPPORTED
    906 /* Set the automatic flush interval or 0 to turn flushing off */
    907 void PNGAPI
    908 png_set_flush(png_structrp png_ptr, int nrows)
    909 {
    910    png_debug(1, "in png_set_flush");
    911 
    912    if (png_ptr == NULL)
    913       return;
    914 
    915    png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);
    916 }
    917 
    918 /* Flush the current output buffers now */
    919 void PNGAPI
    920 png_write_flush(png_structrp png_ptr)
    921 {
    922    png_debug(1, "in png_write_flush");
    923 
    924    if (png_ptr == NULL)
    925       return;
    926 
    927    /* We have already written out all of the data */
    928    if (png_ptr->row_number >= png_ptr->num_rows)
    929       return;
    930 
    931    png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);
    932    png_ptr->flush_rows = 0;
    933    png_flush(png_ptr);
    934 }
    935 #endif /* WRITE_FLUSH */
    936 
    937 /* Free any memory used in png_ptr struct without freeing the struct itself. */
    938 static void
    939 png_write_destroy(png_structrp png_ptr)
    940 {
    941    png_debug(1, "in png_write_destroy");
    942 
    943    /* Free any memory zlib uses */
    944    if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
    945       deflateEnd(&png_ptr->zstream);
    946 
    947    /* Free our memory.  png_free checks NULL for us. */
    948    png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
    949    png_free(png_ptr, png_ptr->row_buf);
    950    png_ptr->row_buf = NULL;
    951 #ifdef PNG_WRITE_FILTER_SUPPORTED
    952    png_free(png_ptr, png_ptr->prev_row);
    953    png_free(png_ptr, png_ptr->try_row);
    954    png_free(png_ptr, png_ptr->tst_row);
    955    png_ptr->prev_row = NULL;
    956    png_ptr->try_row = NULL;
    957    png_ptr->tst_row = NULL;
    958 #endif
    959 
    960 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
    961    png_free(png_ptr, png_ptr->chunk_list);
    962    png_ptr->chunk_list = NULL;
    963 #endif
    964 
    965    /* The error handling and memory handling information is left intact at this
    966     * point: the jmp_buf may still have to be freed.  See png_destroy_png_struct
    967     * for how this happens.
    968     */
    969 }
    970 
    971 /* Free all memory used by the write.
    972  * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for
    973  * *png_ptr_ptr.  Prior to 1.6.0 it would accept such a value and it would free
    974  * the passed in info_structs but it would quietly fail to free any of the data
    975  * inside them.  In 1.6.0 it quietly does nothing (it has to be quiet because it
    976  * has no png_ptr.)
    977  */
    978 void PNGAPI
    979 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
    980 {
    981    png_debug(1, "in png_destroy_write_struct");
    982 
    983    if (png_ptr_ptr != NULL)
    984    {
    985       png_structrp png_ptr = *png_ptr_ptr;
    986 
    987       if (png_ptr != NULL) /* added in libpng 1.6.0 */
    988       {
    989          png_destroy_info_struct(png_ptr, info_ptr_ptr);
    990 
    991          *png_ptr_ptr = NULL;
    992          png_write_destroy(png_ptr);
    993          png_destroy_png_struct(png_ptr);
    994       }
    995    }
    996 }
    997 
    998 /* Allow the application to select one or more row filters to use. */
    999 void PNGAPI
   1000 png_set_filter(png_structrp png_ptr, int method, int filters)
   1001 {
   1002    png_debug(1, "in png_set_filter");
   1003 
   1004    if (png_ptr == NULL)
   1005       return;
   1006 
   1007 #ifdef PNG_MNG_FEATURES_SUPPORTED
   1008    if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
   1009        (method == PNG_INTRAPIXEL_DIFFERENCING))
   1010       method = PNG_FILTER_TYPE_BASE;
   1011 
   1012 #endif
   1013    if (method == PNG_FILTER_TYPE_BASE)
   1014    {
   1015       switch (filters & (PNG_ALL_FILTERS | 0x07))
   1016       {
   1017 #ifdef PNG_WRITE_FILTER_SUPPORTED
   1018          case 5:
   1019          case 6:
   1020          case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
   1021 #endif /* WRITE_FILTER */
   1022             /* FALLTHROUGH */
   1023          case PNG_FILTER_VALUE_NONE:
   1024             png_ptr->do_filter = PNG_FILTER_NONE; break;
   1025 
   1026 #ifdef PNG_WRITE_FILTER_SUPPORTED
   1027          case PNG_FILTER_VALUE_SUB:
   1028             png_ptr->do_filter = PNG_FILTER_SUB; break;
   1029 
   1030          case PNG_FILTER_VALUE_UP:
   1031             png_ptr->do_filter = PNG_FILTER_UP; break;
   1032 
   1033          case PNG_FILTER_VALUE_AVG:
   1034             png_ptr->do_filter = PNG_FILTER_AVG; break;
   1035 
   1036          case PNG_FILTER_VALUE_PAETH:
   1037             png_ptr->do_filter = PNG_FILTER_PAETH; break;
   1038 
   1039          default:
   1040             png_ptr->do_filter = (png_byte)filters; break;
   1041 #else
   1042          default:
   1043             png_app_error(png_ptr, "Unknown row filter for method 0");
   1044 #endif /* WRITE_FILTER */
   1045       }
   1046 
   1047 #ifdef PNG_WRITE_FILTER_SUPPORTED
   1048       /* If we have allocated the row_buf, this means we have already started
   1049        * with the image and we should have allocated all of the filter buffers
   1050        * that have been selected.  If prev_row isn't already allocated, then
   1051        * it is too late to start using the filters that need it, since we
   1052        * will be missing the data in the previous row.  If an application
   1053        * wants to start and stop using particular filters during compression,
   1054        * it should start out with all of the filters, and then remove them
   1055        * or add them back after the start of compression.
   1056        *
   1057        * NOTE: this is a nasty constraint on the code, because it means that the
   1058        * prev_row buffer must be maintained even if there are currently no
   1059        * 'prev_row' requiring filters active.
   1060        */
   1061       if (png_ptr->row_buf != NULL)
   1062       {
   1063          int num_filters;
   1064          png_alloc_size_t buf_size;
   1065 
   1066          /* Repeat the checks in png_write_start_row; 1 pixel high or wide
   1067           * images cannot benefit from certain filters.  If this isn't done here
   1068           * the check below will fire on 1 pixel high images.
   1069           */
   1070          if (png_ptr->height == 1)
   1071             filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
   1072 
   1073          if (png_ptr->width == 1)
   1074             filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
   1075 
   1076          if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0
   1077             && png_ptr->prev_row == NULL)
   1078          {
   1079             /* This is the error case, however it is benign - the previous row
   1080              * is not available so the filter can't be used.  Just warn here.
   1081              */
   1082             png_app_warning(png_ptr,
   1083                 "png_set_filter: UP/AVG/PAETH cannot be added after start");
   1084             filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
   1085          }
   1086 
   1087          num_filters = 0;
   1088 
   1089          if (filters & PNG_FILTER_SUB)
   1090             num_filters++;
   1091 
   1092          if (filters & PNG_FILTER_UP)
   1093             num_filters++;
   1094 
   1095          if (filters & PNG_FILTER_AVG)
   1096             num_filters++;
   1097 
   1098          if (filters & PNG_FILTER_PAETH)
   1099             num_filters++;
   1100 
   1101          /* Allocate needed row buffers if they have not already been
   1102           * allocated.
   1103           */
   1104          buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth,
   1105              png_ptr->width) + 1;
   1106 
   1107          if (png_ptr->try_row == NULL)
   1108             png_ptr->try_row = png_voidcast(png_bytep,
   1109                 png_malloc(png_ptr, buf_size));
   1110 
   1111          if (num_filters > 1)
   1112          {
   1113             if (png_ptr->tst_row == NULL)
   1114                png_ptr->tst_row = png_voidcast(png_bytep,
   1115                    png_malloc(png_ptr, buf_size));
   1116          }
   1117       }
   1118       png_ptr->do_filter = (png_byte)filters;
   1119 #endif
   1120    }
   1121    else
   1122       png_error(png_ptr, "Unknown custom filter method");
   1123 }
   1124 
   1125 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
   1126 /* Provide floating and fixed point APIs */
   1127 #ifdef PNG_FLOATING_POINT_SUPPORTED
   1128 void PNGAPI
   1129 png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,
   1130     int num_weights, png_const_doublep filter_weights,
   1131     png_const_doublep filter_costs)
   1132 {
   1133    PNG_UNUSED(png_ptr)
   1134    PNG_UNUSED(heuristic_method)
   1135    PNG_UNUSED(num_weights)
   1136    PNG_UNUSED(filter_weights)
   1137    PNG_UNUSED(filter_costs)
   1138 }
   1139 #endif /* FLOATING_POINT */
   1140 
   1141 #ifdef PNG_FIXED_POINT_SUPPORTED
   1142 void PNGAPI
   1143 png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,
   1144     int num_weights, png_const_fixed_point_p filter_weights,
   1145     png_const_fixed_point_p filter_costs)
   1146 {
   1147    PNG_UNUSED(png_ptr)
   1148    PNG_UNUSED(heuristic_method)
   1149    PNG_UNUSED(num_weights)
   1150    PNG_UNUSED(filter_weights)
   1151    PNG_UNUSED(filter_costs)
   1152 }
   1153 #endif /* FIXED_POINT */
   1154 #endif /* WRITE_WEIGHTED_FILTER */
   1155 
   1156 #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
   1157 void PNGAPI
   1158 png_set_compression_level(png_structrp png_ptr, int level)
   1159 {
   1160    png_debug(1, "in png_set_compression_level");
   1161 
   1162    if (png_ptr == NULL)
   1163       return;
   1164 
   1165    png_ptr->zlib_level = level;
   1166 }
   1167 
   1168 void PNGAPI
   1169 png_set_compression_mem_level(png_structrp png_ptr, int mem_level)
   1170 {
   1171    png_debug(1, "in png_set_compression_mem_level");
   1172 
   1173    if (png_ptr == NULL)
   1174       return;
   1175 
   1176    png_ptr->zlib_mem_level = mem_level;
   1177 }
   1178 
   1179 void PNGAPI
   1180 png_set_compression_strategy(png_structrp png_ptr, int strategy)
   1181 {
   1182    png_debug(1, "in png_set_compression_strategy");
   1183 
   1184    if (png_ptr == NULL)
   1185       return;
   1186 
   1187    /* The flag setting here prevents the libpng dynamic selection of strategy.
   1188     */
   1189    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
   1190    png_ptr->zlib_strategy = strategy;
   1191 }
   1192 
   1193 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
   1194  * smaller value of window_bits if it can do so safely.
   1195  */
   1196 void PNGAPI
   1197 png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
   1198 {
   1199    if (png_ptr == NULL)
   1200       return;
   1201 
   1202    /* Prior to 1.6.0 this would warn but then set the window_bits value. This
   1203     * meant that negative window bits values could be selected that would cause
   1204     * libpng to write a non-standard PNG file with raw deflate or gzip
   1205     * compressed IDAT or ancillary chunks.  Such files can be read and there is
   1206     * no warning on read, so this seems like a very bad idea.
   1207     */
   1208    if (window_bits > 15)
   1209    {
   1210       png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
   1211       window_bits = 15;
   1212    }
   1213 
   1214    else if (window_bits < 8)
   1215    {
   1216       png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
   1217       window_bits = 8;
   1218    }
   1219 
   1220    png_ptr->zlib_window_bits = window_bits;
   1221 }
   1222 
   1223 void PNGAPI
   1224 png_set_compression_method(png_structrp png_ptr, int method)
   1225 {
   1226    png_debug(1, "in png_set_compression_method");
   1227 
   1228    if (png_ptr == NULL)
   1229       return;
   1230 
   1231    /* This would produce an invalid PNG file if it worked, but it doesn't and
   1232     * deflate will fault it, so it is harmless to just warn here.
   1233     */
   1234    if (method != 8)
   1235       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
   1236 
   1237    png_ptr->zlib_method = method;
   1238 }
   1239 #endif /* WRITE_CUSTOMIZE_COMPRESSION */
   1240 
   1241 /* The following were added to libpng-1.5.4 */
   1242 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
   1243 void PNGAPI
   1244 png_set_text_compression_level(png_structrp png_ptr, int level)
   1245 {
   1246    png_debug(1, "in png_set_text_compression_level");
   1247 
   1248    if (png_ptr == NULL)
   1249       return;
   1250 
   1251    png_ptr->zlib_text_level = level;
   1252 }
   1253 
   1254 void PNGAPI
   1255 png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)
   1256 {
   1257    png_debug(1, "in png_set_text_compression_mem_level");
   1258 
   1259    if (png_ptr == NULL)
   1260       return;
   1261 
   1262    png_ptr->zlib_text_mem_level = mem_level;
   1263 }
   1264 
   1265 void PNGAPI
   1266 png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
   1267 {
   1268    png_debug(1, "in png_set_text_compression_strategy");
   1269 
   1270    if (png_ptr == NULL)
   1271       return;
   1272 
   1273    png_ptr->zlib_text_strategy = strategy;
   1274 }
   1275 
   1276 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
   1277  * smaller value of window_bits if it can do so safely.
   1278  */
   1279 void PNGAPI
   1280 png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
   1281 {
   1282    if (png_ptr == NULL)
   1283       return;
   1284 
   1285    if (window_bits > 15)
   1286    {
   1287       png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
   1288       window_bits = 15;
   1289    }
   1290 
   1291    else if (window_bits < 8)
   1292    {
   1293       png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
   1294       window_bits = 8;
   1295    }
   1296 
   1297    png_ptr->zlib_text_window_bits = window_bits;
   1298 }
   1299 
   1300 void PNGAPI
   1301 png_set_text_compression_method(png_structrp png_ptr, int method)
   1302 {
   1303    png_debug(1, "in png_set_text_compression_method");
   1304 
   1305    if (png_ptr == NULL)
   1306       return;
   1307 
   1308    if (method != 8)
   1309       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
   1310 
   1311    png_ptr->zlib_text_method = method;
   1312 }
   1313 #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
   1314 /* end of API added to libpng-1.5.4 */
   1315 
   1316 void PNGAPI
   1317 png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)
   1318 {
   1319    if (png_ptr == NULL)
   1320       return;
   1321 
   1322    png_ptr->write_row_fn = write_row_fn;
   1323 }
   1324 
   1325 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
   1326 void PNGAPI
   1327 png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
   1328     write_user_transform_fn)
   1329 {
   1330    png_debug(1, "in png_set_write_user_transform_fn");
   1331 
   1332    if (png_ptr == NULL)
   1333       return;
   1334 
   1335    png_ptr->transformations |= PNG_USER_TRANSFORM;
   1336    png_ptr->write_user_transform_fn = write_user_transform_fn;
   1337 }
   1338 #endif
   1339 
   1340 
   1341 #ifdef PNG_INFO_IMAGE_SUPPORTED
   1342 void PNGAPI
   1343 png_write_png(png_structrp png_ptr, png_inforp info_ptr,
   1344     int transforms, voidp params)
   1345 {
   1346    if (png_ptr == NULL || info_ptr == NULL)
   1347       return;
   1348 
   1349    if ((info_ptr->valid & PNG_INFO_IDAT) == 0)
   1350    {
   1351       png_app_error(png_ptr, "no rows for png_write_image to write");
   1352       return;
   1353    }
   1354 
   1355    /* Write the file header information. */
   1356    png_write_info(png_ptr, info_ptr);
   1357 
   1358    /* ------ these transformations don't touch the info structure ------- */
   1359 
   1360    /* Invert monochrome pixels */
   1361    if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
   1362 #ifdef PNG_WRITE_INVERT_SUPPORTED
   1363       png_set_invert_mono(png_ptr);
   1364 #else
   1365       png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
   1366 #endif
   1367 
   1368    /* Shift the pixels up to a legal bit depth and fill in
   1369     * as appropriate to correctly scale the image.
   1370     */
   1371    if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
   1372 #ifdef PNG_WRITE_SHIFT_SUPPORTED
   1373       if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
   1374          png_set_shift(png_ptr, &info_ptr->sig_bit);
   1375 #else
   1376       png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
   1377 #endif
   1378 
   1379    /* Pack pixels into bytes */
   1380    if ((transforms & PNG_TRANSFORM_PACKING) != 0)
   1381 #ifdef PNG_WRITE_PACK_SUPPORTED
   1382       png_set_packing(png_ptr);
   1383 #else
   1384       png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
   1385 #endif
   1386 
   1387    /* Swap location of alpha bytes from ARGB to RGBA */
   1388    if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
   1389 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
   1390       png_set_swap_alpha(png_ptr);
   1391 #else
   1392       png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
   1393 #endif
   1394 
   1395    /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
   1396     * RGB, note that the code expects the input color type to be G or RGB; no
   1397     * alpha channel.
   1398     */
   1399    if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|
   1400        PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)
   1401    {
   1402 #ifdef PNG_WRITE_FILLER_SUPPORTED
   1403       if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)
   1404       {
   1405          if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
   1406             png_app_error(png_ptr,
   1407                 "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");
   1408 
   1409          /* Continue if ignored - this is the pre-1.6.10 behavior */
   1410          png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
   1411       }
   1412 
   1413       else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
   1414          png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
   1415 #else
   1416       png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");
   1417 #endif
   1418    }
   1419 
   1420    /* Flip BGR pixels to RGB */
   1421    if ((transforms & PNG_TRANSFORM_BGR) != 0)
   1422 #ifdef PNG_WRITE_BGR_SUPPORTED
   1423       png_set_bgr(png_ptr);
   1424 #else
   1425       png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
   1426 #endif
   1427 
   1428    /* Swap bytes of 16-bit files to most significant byte first */
   1429    if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
   1430 #ifdef PNG_WRITE_SWAP_SUPPORTED
   1431       png_set_swap(png_ptr);
   1432 #else
   1433       png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
   1434 #endif
   1435 
   1436    /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
   1437    if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
   1438 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
   1439       png_set_packswap(png_ptr);
   1440 #else
   1441       png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
   1442 #endif
   1443 
   1444    /* Invert the alpha channel from opacity to transparency */
   1445    if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
   1446 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
   1447       png_set_invert_alpha(png_ptr);
   1448 #else
   1449       png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
   1450 #endif
   1451 
   1452    /* ----------------------- end of transformations ------------------- */
   1453 
   1454    /* Write the bits */
   1455    png_write_image(png_ptr, info_ptr->row_pointers);
   1456 
   1457    /* It is REQUIRED to call this to finish writing the rest of the file */
   1458    png_write_end(png_ptr, info_ptr);
   1459 
   1460    PNG_UNUSED(params)
   1461 }
   1462 #endif
   1463 
   1464 
   1465 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
   1466 /* Initialize the write structure - general purpose utility. */
   1467 static int
   1468 png_image_write_init(png_imagep image)
   1469 {
   1470    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,
   1471        png_safe_error, png_safe_warning);
   1472 
   1473    if (png_ptr != NULL)
   1474    {
   1475       png_infop info_ptr = png_create_info_struct(png_ptr);
   1476 
   1477       if (info_ptr != NULL)
   1478       {
   1479          png_controlp control = png_voidcast(png_controlp,
   1480              png_malloc_warn(png_ptr, (sizeof *control)));
   1481 
   1482          if (control != NULL)
   1483          {
   1484             memset(control, 0, (sizeof *control));
   1485 
   1486             control->png_ptr = png_ptr;
   1487             control->info_ptr = info_ptr;
   1488             control->for_write = 1;
   1489 
   1490             image->opaque = control;
   1491             return 1;
   1492          }
   1493 
   1494          /* Error clean up */
   1495          png_destroy_info_struct(png_ptr, &info_ptr);
   1496       }
   1497 
   1498       png_destroy_write_struct(&png_ptr, NULL);
   1499    }
   1500 
   1501    return png_image_error(image, "png_image_write_: out of memory");
   1502 }
   1503 
   1504 /* Arguments to png_image_write_main: */
   1505 typedef struct
   1506 {
   1507    /* Arguments: */
   1508    png_imagep      image;
   1509    png_const_voidp buffer;
   1510    png_int_32      row_stride;
   1511    png_const_voidp colormap;
   1512    int             convert_to_8bit;
   1513    /* Local variables: */
   1514    png_const_voidp first_row;
   1515    ptrdiff_t       row_bytes;
   1516    png_voidp       local_row;
   1517    /* Byte count for memory writing */
   1518    png_bytep        memory;
   1519    png_alloc_size_t memory_bytes; /* not used for STDIO */
   1520    png_alloc_size_t output_bytes; /* running total */
   1521 } png_image_write_control;
   1522 
   1523 /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to
   1524  * do any necessary byte swapping.  The component order is defined by the
   1525  * png_image format value.
   1526  */
   1527 static int
   1528 png_write_image_16bit(png_voidp argument)
   1529 {
   1530    png_image_write_control *display = png_voidcast(png_image_write_control*,
   1531        argument);
   1532    png_imagep image = display->image;
   1533    png_structrp png_ptr = image->opaque->png_ptr;
   1534 
   1535    png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
   1536        display->first_row);
   1537    png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
   1538    png_uint_16p row_end;
   1539    const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
   1540        3 : 1;
   1541    int aindex = 0;
   1542    png_uint_32 y = image->height;
   1543 
   1544    if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
   1545    {
   1546 #   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
   1547       if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
   1548       {
   1549          aindex = -1;
   1550          ++input_row; /* To point to the first component */
   1551          ++output_row;
   1552       }
   1553          else
   1554             aindex = (int)channels;
   1555 #     else
   1556          aindex = (int)channels;
   1557 #     endif
   1558    }
   1559 
   1560    else
   1561       png_error(png_ptr, "png_write_image: internal call error");
   1562 
   1563    /* Work out the output row end and count over this, note that the increment
   1564     * above to 'row' means that row_end can actually be beyond the end of the
   1565     * row; this is correct.
   1566     */
   1567    row_end = output_row + image->width * (channels+1);
   1568 
   1569    for (; y > 0; --y)
   1570    {
   1571       png_const_uint_16p in_ptr = input_row;
   1572       png_uint_16p out_ptr = output_row;
   1573 
   1574       while (out_ptr < row_end)
   1575       {
   1576          const png_uint_16 alpha = in_ptr[aindex];
   1577          png_uint_32 reciprocal = 0;
   1578          int c;
   1579 
   1580          out_ptr[aindex] = alpha;
   1581 
   1582          /* Calculate a reciprocal.  The correct calculation is simply
   1583           * component/alpha*65535 << 15. (I.e. 15 bits of precision); this
   1584           * allows correct rounding by adding .5 before the shift.  'reciprocal'
   1585           * is only initialized when required.
   1586           */
   1587          if (alpha > 0 && alpha < 65535)
   1588             reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
   1589 
   1590          c = (int)channels;
   1591          do /* always at least one channel */
   1592          {
   1593             png_uint_16 component = *in_ptr++;
   1594 
   1595             /* The following gives 65535 for an alpha of 0, which is fine,
   1596              * otherwise if 0/0 is represented as some other value there is more
   1597              * likely to be a discontinuity which will probably damage
   1598              * compression when moving from a fully transparent area to a
   1599              * nearly transparent one.  (The assumption here is that opaque
   1600              * areas tend not to be 0 intensity.)
   1601              */
   1602             if (component >= alpha)
   1603                component = 65535;
   1604 
   1605             /* component<alpha, so component/alpha is less than one and
   1606              * component*reciprocal is less than 2^31.
   1607              */
   1608             else if (component > 0 && alpha < 65535)
   1609             {
   1610                png_uint_32 calc = component * reciprocal;
   1611                calc += 16384; /* round to nearest */
   1612                component = (png_uint_16)(calc >> 15);
   1613             }
   1614 
   1615             *out_ptr++ = component;
   1616          }
   1617          while (--c > 0);
   1618 
   1619          /* Skip to next component (skip the intervening alpha channel) */
   1620          ++in_ptr;
   1621          ++out_ptr;
   1622       }
   1623 
   1624       png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
   1625       input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
   1626    }
   1627 
   1628    return 1;
   1629 }
   1630 
   1631 /* Given 16-bit input (1 to 4 channels) write 8-bit output.  If an alpha channel
   1632  * is present it must be removed from the components, the components are then
   1633  * written in sRGB encoding.  No components are added or removed.
   1634  *
   1635  * Calculate an alpha reciprocal to reverse pre-multiplication.  As above the
   1636  * calculation can be done to 15 bits of accuracy; however, the output needs to
   1637  * be scaled in the range 0..255*65535, so include that scaling here.
   1638  */
   1639 #   define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha)
   1640 
   1641 static png_byte
   1642 png_unpremultiply(png_uint_32 component, png_uint_32 alpha,
   1643     png_uint_32 reciprocal/*from the above macro*/)
   1644 {
   1645    /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
   1646     * is represented as some other value there is more likely to be a
   1647     * discontinuity which will probably damage compression when moving from a
   1648     * fully transparent area to a nearly transparent one.  (The assumption here
   1649     * is that opaque areas tend not to be 0 intensity.)
   1650     *
   1651     * There is a rounding problem here; if alpha is less than 128 it will end up
   1652     * as 0 when scaled to 8 bits.  To avoid introducing spurious colors into the
   1653     * output change for this too.
   1654     */
   1655    if (component >= alpha || alpha < 128)
   1656       return 255;
   1657 
   1658    /* component<alpha, so component/alpha is less than one and
   1659     * component*reciprocal is less than 2^31.
   1660     */
   1661    else if (component > 0)
   1662    {
   1663       /* The test is that alpha/257 (rounded) is less than 255, the first value
   1664        * that becomes 255 is 65407.
   1665        * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,
   1666        * be exact!)  [Could also test reciprocal != 0]
   1667        */
   1668       if (alpha < 65407)
   1669       {
   1670          component *= reciprocal;
   1671          component += 64; /* round to nearest */
   1672          component >>= 7;
   1673       }
   1674 
   1675       else
   1676          component *= 255;
   1677 
   1678       /* Convert the component to sRGB. */
   1679       return (png_byte)PNG_sRGB_FROM_LINEAR(component);
   1680    }
   1681 
   1682    else
   1683       return 0;
   1684 }
   1685 
   1686 static int
   1687 png_write_image_8bit(png_voidp argument)
   1688 {
   1689    png_image_write_control *display = png_voidcast(png_image_write_control*,
   1690        argument);
   1691    png_imagep image = display->image;
   1692    png_structrp png_ptr = image->opaque->png_ptr;
   1693 
   1694    png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
   1695        display->first_row);
   1696    png_bytep output_row = png_voidcast(png_bytep, display->local_row);
   1697    png_uint_32 y = image->height;
   1698    const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
   1699        3 : 1;
   1700 
   1701    if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
   1702    {
   1703       png_bytep row_end;
   1704       int aindex;
   1705 
   1706 #   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
   1707       if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
   1708       {
   1709          aindex = -1;
   1710          ++input_row; /* To point to the first component */
   1711          ++output_row;
   1712       }
   1713 
   1714       else
   1715 #   endif
   1716       aindex = (int)channels;
   1717 
   1718       /* Use row_end in place of a loop counter: */
   1719       row_end = output_row + image->width * (channels+1);
   1720 
   1721       for (; y > 0; --y)
   1722       {
   1723          png_const_uint_16p in_ptr = input_row;
   1724          png_bytep out_ptr = output_row;
   1725 
   1726          while (out_ptr < row_end)
   1727          {
   1728             png_uint_16 alpha = in_ptr[aindex];
   1729             png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
   1730             png_uint_32 reciprocal = 0;
   1731             int c;
   1732 
   1733             /* Scale and write the alpha channel. */
   1734             out_ptr[aindex] = alphabyte;
   1735 
   1736             if (alphabyte > 0 && alphabyte < 255)
   1737                reciprocal = UNP_RECIPROCAL(alpha);
   1738 
   1739             c = (int)channels;
   1740             do /* always at least one channel */
   1741                *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
   1742             while (--c > 0);
   1743 
   1744             /* Skip to next component (skip the intervening alpha channel) */
   1745             ++in_ptr;
   1746             ++out_ptr;
   1747          } /* while out_ptr < row_end */
   1748 
   1749          png_write_row(png_ptr, png_voidcast(png_const_bytep,
   1750              display->local_row));
   1751          input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
   1752       } /* while y */
   1753    }
   1754 
   1755    else
   1756    {
   1757       /* No alpha channel, so the row_end really is the end of the row and it
   1758        * is sufficient to loop over the components one by one.
   1759        */
   1760       png_bytep row_end = output_row + image->width * channels;
   1761 
   1762       for (; y > 0; --y)
   1763       {
   1764          png_const_uint_16p in_ptr = input_row;
   1765          png_bytep out_ptr = output_row;
   1766 
   1767          while (out_ptr < row_end)
   1768          {
   1769             png_uint_32 component = *in_ptr++;
   1770 
   1771             component *= 255;
   1772             *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);
   1773          }
   1774 
   1775          png_write_row(png_ptr, output_row);
   1776          input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
   1777       }
   1778    }
   1779 
   1780    return 1;
   1781 }
   1782 
   1783 static void
   1784 png_image_set_PLTE(png_image_write_control *display)
   1785 {
   1786    const png_imagep image = display->image;
   1787    const void *cmap = display->colormap;
   1788    const int entries = image->colormap_entries > 256 ? 256 :
   1789        (int)image->colormap_entries;
   1790 
   1791    /* NOTE: the caller must check for cmap != NULL and entries != 0 */
   1792    const png_uint_32 format = image->format;
   1793    const unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
   1794 
   1795 #   if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
   1796       defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
   1797       const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
   1798           (format & PNG_FORMAT_FLAG_ALPHA) != 0;
   1799 #   else
   1800 #     define afirst 0
   1801 #   endif
   1802 
   1803 #   ifdef PNG_FORMAT_BGR_SUPPORTED
   1804       const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
   1805 #   else
   1806 #     define bgr 0
   1807 #   endif
   1808 
   1809    int i, num_trans;
   1810    png_color palette[256];
   1811    png_byte tRNS[256];
   1812 
   1813    memset(tRNS, 255, (sizeof tRNS));
   1814    memset(palette, 0, (sizeof palette));
   1815 
   1816    for (i=num_trans=0; i<entries; ++i)
   1817    {
   1818       /* This gets automatically converted to sRGB with reversal of the
   1819        * pre-multiplication if the color-map has an alpha channel.
   1820        */
   1821       if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)
   1822       {
   1823          png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);
   1824 
   1825          entry += (unsigned int)i * channels;
   1826 
   1827          if ((channels & 1) != 0) /* no alpha */
   1828          {
   1829             if (channels >= 3) /* RGB */
   1830             {
   1831                palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
   1832                    entry[(2 ^ bgr)]);
   1833                palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
   1834                    entry[1]);
   1835                palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
   1836                    entry[bgr]);
   1837             }
   1838 
   1839             else /* Gray */
   1840                palette[i].blue = palette[i].red = palette[i].green =
   1841                   (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);
   1842          }
   1843 
   1844          else /* alpha */
   1845          {
   1846             png_uint_16 alpha = entry[afirst ? 0 : channels-1];
   1847             png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
   1848             png_uint_32 reciprocal = 0;
   1849 
   1850             /* Calculate a reciprocal, as in the png_write_image_8bit code above
   1851              * this is designed to produce a value scaled to 255*65535 when
   1852              * divided by 128 (i.e. asr 7).
   1853              */
   1854             if (alphabyte > 0 && alphabyte < 255)
   1855                reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;
   1856 
   1857             tRNS[i] = alphabyte;
   1858             if (alphabyte < 255)
   1859                num_trans = i+1;
   1860 
   1861             if (channels >= 3) /* RGB */
   1862             {
   1863                palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
   1864                    alpha, reciprocal);
   1865                palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
   1866                    reciprocal);
   1867                palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
   1868                    reciprocal);
   1869             }
   1870 
   1871             else /* gray */
   1872                palette[i].blue = palette[i].red = palette[i].green =
   1873                    png_unpremultiply(entry[afirst], alpha, reciprocal);
   1874          }
   1875       }
   1876 
   1877       else /* Color-map has sRGB values */
   1878       {
   1879          png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
   1880 
   1881          entry += (unsigned int)i * channels;
   1882 
   1883          switch (channels)
   1884          {
   1885             case 4:
   1886                tRNS[i] = entry[afirst ? 0 : 3];
   1887                if (tRNS[i] < 255)
   1888                   num_trans = i+1;
   1889                /* FALLTHROUGH */
   1890             case 3:
   1891                palette[i].blue = entry[afirst + (2 ^ bgr)];
   1892                palette[i].green = entry[afirst + 1];
   1893                palette[i].red = entry[afirst + bgr];
   1894                break;
   1895 
   1896             case 2:
   1897                tRNS[i] = entry[1 ^ afirst];
   1898                if (tRNS[i] < 255)
   1899                   num_trans = i+1;
   1900                /* FALLTHROUGH */
   1901             case 1:
   1902                palette[i].blue = palette[i].red = palette[i].green =
   1903                   entry[afirst];
   1904                break;
   1905 
   1906             default:
   1907                break;
   1908          }
   1909       }
   1910    }
   1911 
   1912 #   ifdef afirst
   1913 #     undef afirst
   1914 #   endif
   1915 #   ifdef bgr
   1916 #     undef bgr
   1917 #   endif
   1918 
   1919    png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
   1920        entries);
   1921 
   1922    if (num_trans > 0)
   1923       png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
   1924           num_trans, NULL);
   1925 
   1926    image->colormap_entries = (png_uint_32)entries;
   1927 }
   1928 
   1929 static int
   1930 png_image_write_main(png_voidp argument)
   1931 {
   1932    png_image_write_control *display = png_voidcast(png_image_write_control*,
   1933        argument);
   1934    png_imagep image = display->image;
   1935    png_structrp png_ptr = image->opaque->png_ptr;
   1936    png_inforp info_ptr = image->opaque->info_ptr;
   1937    png_uint_32 format = image->format;
   1938 
   1939    /* The following four ints are actually booleans */
   1940    int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
   1941    int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
   1942    int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
   1943    int write_16bit = linear && (display->convert_to_8bit == 0);
   1944 
   1945 #   ifdef PNG_BENIGN_ERRORS_SUPPORTED
   1946       /* Make sure we error out on any bad situation */
   1947       png_set_benign_errors(png_ptr, 0/*error*/);
   1948 #   endif
   1949 
   1950    /* Default the 'row_stride' parameter if required, also check the row stride
   1951     * and total image size to ensure that they are within the system limits.
   1952     */
   1953    {
   1954       const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
   1955 
   1956       if (image->width <= 0x7fffffffU/channels) /* no overflow */
   1957       {
   1958          png_uint_32 check;
   1959          const png_uint_32 png_row_stride = image->width * channels;
   1960 
   1961          if (display->row_stride == 0)
   1962             display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
   1963 
   1964          if (display->row_stride < 0)
   1965             check = (png_uint_32)(-display->row_stride);
   1966 
   1967          else
   1968             check = (png_uint_32)display->row_stride;
   1969 
   1970          if (check >= png_row_stride)
   1971          {
   1972             /* Now check for overflow of the image buffer calculation; this
   1973              * limits the whole image size to 32 bits for API compatibility with
   1974              * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
   1975              */
   1976             if (image->height > 0xffffffffU/png_row_stride)
   1977                png_error(image->opaque->png_ptr, "memory image too large");
   1978          }
   1979 
   1980          else
   1981             png_error(image->opaque->png_ptr, "supplied row stride too small");
   1982       }
   1983 
   1984       else
   1985          png_error(image->opaque->png_ptr, "image row stride too large");
   1986    }
   1987 
   1988    /* Set the required transforms then write the rows in the correct order. */
   1989    if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)
   1990    {
   1991       if (display->colormap != NULL && image->colormap_entries > 0)
   1992       {
   1993          png_uint_32 entries = image->colormap_entries;
   1994 
   1995          png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
   1996              entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),
   1997              PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
   1998              PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
   1999 
   2000          png_image_set_PLTE(display);
   2001       }
   2002 
   2003       else
   2004          png_error(image->opaque->png_ptr,
   2005              "no color-map for color-mapped image");
   2006    }
   2007 
   2008    else
   2009       png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
   2010           write_16bit ? 16 : 8,
   2011           ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +
   2012           ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),
   2013           PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
   2014 
   2015    /* Counter-intuitively the data transformations must be called *after*
   2016     * png_write_info, not before as in the read code, but the 'set' functions
   2017     * must still be called before.  Just set the color space information, never
   2018     * write an interlaced image.
   2019     */
   2020 
   2021    if (write_16bit != 0)
   2022    {
   2023       /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */
   2024       png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);
   2025 
   2026       if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
   2027          png_set_cHRM_fixed(png_ptr, info_ptr,
   2028              /* color      x       y */
   2029              /* white */ 31270, 32900,
   2030              /* red   */ 64000, 33000,
   2031              /* green */ 30000, 60000,
   2032              /* blue  */ 15000,  6000
   2033          );
   2034    }
   2035 
   2036    else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
   2037       png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
   2038 
   2039    /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
   2040     * space must still be gamma encoded.
   2041     */
   2042    else
   2043       png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
   2044 
   2045    /* Write the file header. */
   2046    png_write_info(png_ptr, info_ptr);
   2047 
   2048    /* Now set up the data transformations (*after* the header is written),
   2049     * remove the handled transformations from the 'format' flags for checking.
   2050     *
   2051     * First check for a little endian system if writing 16-bit files.
   2052     */
   2053    if (write_16bit != 0)
   2054    {
   2055       PNG_CONST png_uint_16 le = 0x0001;
   2056 
   2057       if ((*(png_const_bytep) & le) != 0)
   2058          png_set_swap(png_ptr);
   2059    }
   2060 
   2061 #   ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
   2062       if ((format & PNG_FORMAT_FLAG_BGR) != 0)
   2063       {
   2064          if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)
   2065             png_set_bgr(png_ptr);
   2066          format &= ~PNG_FORMAT_FLAG_BGR;
   2067       }
   2068 #   endif
   2069 
   2070 #   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
   2071       if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
   2072       {
   2073          if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)
   2074             png_set_swap_alpha(png_ptr);
   2075          format &= ~PNG_FORMAT_FLAG_AFIRST;
   2076       }
   2077 #   endif
   2078 
   2079    /* If there are 16 or fewer color-map entries we wrote a lower bit depth
   2080     * above, but the application data is still byte packed.
   2081     */
   2082    if (colormap != 0 && image->colormap_entries <= 16)
   2083       png_set_packing(png_ptr);
   2084 
   2085    /* That should have handled all (both) the transforms. */
   2086    if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
   2087          PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)
   2088       png_error(png_ptr, "png_write_image: unsupported transformation");
   2089 
   2090    {
   2091       png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);
   2092       ptrdiff_t row_bytes = display->row_stride;
   2093 
   2094       if (linear != 0)
   2095          row_bytes *= (sizeof (png_uint_16));
   2096 
   2097       if (row_bytes < 0)
   2098          row += (image->height-1) * (-row_bytes);
   2099 
   2100       display->first_row = row;
   2101       display->row_bytes = row_bytes;
   2102    }
   2103 
   2104    /* Apply 'fast' options if the flag is set. */
   2105    if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)
   2106    {
   2107       png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);
   2108       /* NOTE: determined by experiment using pngstest, this reflects some
   2109        * balance between the time to write the image once and the time to read
   2110        * it about 50 times.  The speed-up in pngstest was about 10-20% of the
   2111        * total (user) time on a heavily loaded system.
   2112        */
   2113 #   ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
   2114       png_set_compression_level(png_ptr, 3);
   2115 #   endif
   2116    }
   2117 
   2118    /* Check for the cases that currently require a pre-transform on the row
   2119     * before it is written.  This only applies when the input is 16-bit and
   2120     * either there is an alpha channel or it is converted to 8-bit.
   2121     */
   2122    if ((linear != 0 && alpha != 0 ) ||
   2123        (colormap == 0 && display->convert_to_8bit != 0))
   2124    {
   2125       png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
   2126           png_get_rowbytes(png_ptr, info_ptr)));
   2127       int result;
   2128 
   2129       display->local_row = row;
   2130       if (write_16bit != 0)
   2131          result = png_safe_execute(image, png_write_image_16bit, display);
   2132       else
   2133          result = png_safe_execute(image, png_write_image_8bit, display);
   2134       display->local_row = NULL;
   2135 
   2136       png_free(png_ptr, row);
   2137 
   2138       /* Skip the 'write_end' on error: */
   2139       if (result == 0)
   2140          return 0;
   2141    }
   2142 
   2143    /* Otherwise this is the case where the input is in a format currently
   2144     * supported by the rest of the libpng write code; call it directly.
   2145     */
   2146    else
   2147    {
   2148       png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);
   2149       ptrdiff_t row_bytes = display->row_bytes;
   2150       png_uint_32 y = image->height;
   2151 
   2152       for (; y > 0; --y)
   2153       {
   2154          png_write_row(png_ptr, row);
   2155          row += row_bytes;
   2156       }
   2157    }
   2158 
   2159    png_write_end(png_ptr, info_ptr);
   2160    return 1;
   2161 }
   2162 
   2163 
   2164 static void (PNGCBAPI
   2165 image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data,
   2166     png_size_t size)
   2167 {
   2168    png_image_write_control *display = png_voidcast(png_image_write_control*,
   2169        png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);
   2170    const png_alloc_size_t ob = display->output_bytes;
   2171 
   2172    /* Check for overflow; this should never happen: */
   2173    if (size <= ((png_alloc_size_t)-1) - ob)
   2174    {
   2175       /* I don't think libpng ever does this, but just in case: */
   2176       if (size > 0)
   2177       {
   2178          if (display->memory_bytes >= ob+size) /* writing */
   2179             memcpy(display->memory+ob, data, size);
   2180 
   2181          /* Always update the size: */
   2182          display->output_bytes = ob+size;
   2183       }
   2184    }
   2185 
   2186    else
   2187       png_error(png_ptr, "png_image_write_to_memory: PNG too big");
   2188 }
   2189 
   2190 static void (PNGCBAPI
   2191 image_memory_flush)(png_structp png_ptr)
   2192 {
   2193    PNG_UNUSED(png_ptr)
   2194 }
   2195 
   2196 static int
   2197 png_image_write_memory(png_voidp argument)
   2198 {
   2199    png_image_write_control *display = png_voidcast(png_image_write_control*,
   2200        argument);
   2201 
   2202    /* The rest of the memory-specific init and write_main in an error protected
   2203     * environment.  This case needs to use callbacks for the write operations
   2204     * since libpng has no built in support for writing to memory.
   2205     */
   2206    png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,
   2207        image_memory_write, image_memory_flush);
   2208 
   2209    return png_image_write_main(display);
   2210 }
   2211 
   2212 int PNGAPI
   2213 png_image_write_to_memory(png_imagep image, void *memory,
   2214     png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,
   2215     const void *buffer, png_int_32 row_stride, const void *colormap)
   2216 {
   2217    /* Write the image to the given buffer, or count the bytes if it is NULL */
   2218    if (image != NULL && image->version == PNG_IMAGE_VERSION)
   2219    {
   2220       if (memory_bytes != NULL && buffer != NULL)
   2221       {
   2222          /* This is to give the caller an easier error detection in the NULL
   2223           * case and guard against uninitialized variable problems:
   2224           */
   2225          if (memory == NULL)
   2226             *memory_bytes = 0;
   2227 
   2228          if (png_image_write_init(image) != 0)
   2229          {
   2230             png_image_write_control display;
   2231             int result;
   2232 
   2233             memset(&display, 0, (sizeof display));
   2234             display.image = image;
   2235             display.buffer = buffer;
   2236             display.row_stride = row_stride;
   2237             display.colormap = colormap;
   2238             display.convert_to_8bit = convert_to_8bit;
   2239             display.memory = png_voidcast(png_bytep, memory);
   2240             display.memory_bytes = *memory_bytes;
   2241             display.output_bytes = 0;
   2242 
   2243             result = png_safe_execute(image, png_image_write_memory, &display);
   2244             png_image_free(image);
   2245 
   2246             /* write_memory returns true even if we ran out of buffer. */
   2247             if (result)
   2248             {
   2249                /* On out-of-buffer this function returns '0' but still updates
   2250                 * memory_bytes:
   2251                 */
   2252                if (memory != NULL && display.output_bytes > *memory_bytes)
   2253                   result = 0;
   2254 
   2255                *memory_bytes = display.output_bytes;
   2256             }
   2257 
   2258             return result;
   2259          }
   2260 
   2261          else
   2262             return 0;
   2263       }
   2264 
   2265       else
   2266          return png_image_error(image,
   2267              "png_image_write_to_memory: invalid argument");
   2268    }
   2269 
   2270    else if (image != NULL)
   2271       return png_image_error(image,
   2272           "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION");
   2273 
   2274    else
   2275       return 0;
   2276 }
   2277 
   2278 #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
   2279 int PNGAPI
   2280 png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
   2281     const void *buffer, png_int_32 row_stride, const void *colormap)
   2282 {
   2283    /* Write the image to the given (FILE*). */
   2284    if (image != NULL && image->version == PNG_IMAGE_VERSION)
   2285    {
   2286       if (file != NULL && buffer != NULL)
   2287       {
   2288          if (png_image_write_init(image) != 0)
   2289          {
   2290             png_image_write_control display;
   2291             int result;
   2292 
   2293             /* This is slightly evil, but png_init_io doesn't do anything other
   2294              * than this and we haven't changed the standard IO functions so
   2295              * this saves a 'safe' function.
   2296              */
   2297             image->opaque->png_ptr->io_ptr = file;
   2298 
   2299             memset(&display, 0, (sizeof display));
   2300             display.image = image;
   2301             display.buffer = buffer;
   2302             display.row_stride = row_stride;
   2303             display.colormap = colormap;
   2304             display.convert_to_8bit = convert_to_8bit;
   2305 
   2306             result = png_safe_execute(image, png_image_write_main, &display);
   2307             png_image_free(image);
   2308             return result;
   2309          }
   2310 
   2311          else
   2312             return 0;
   2313       }
   2314 
   2315       else
   2316          return png_image_error(image,
   2317              "png_image_write_to_stdio: invalid argument");
   2318    }
   2319 
   2320    else if (image != NULL)
   2321       return png_image_error(image,
   2322           "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
   2323 
   2324    else
   2325       return 0;
   2326 }
   2327 
   2328 int PNGAPI
   2329 png_image_write_to_file(png_imagep image, const char *file_name,
   2330     int convert_to_8bit, const void *buffer, png_int_32 row_stride,
   2331     const void *colormap)
   2332 {
   2333    /* Write the image to the named file. */
   2334    if (image != NULL && image->version == PNG_IMAGE_VERSION)
   2335    {
   2336       if (file_name != NULL && buffer != NULL)
   2337       {
   2338          FILE *fp = fopen(file_name, "wb");
   2339 
   2340          if (fp != NULL)
   2341          {
   2342             if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
   2343                 row_stride, colormap) != 0)
   2344             {
   2345                int error; /* from fflush/fclose */
   2346 
   2347                /* Make sure the file is flushed correctly. */
   2348                if (fflush(fp) == 0 && ferror(fp) == 0)
   2349                {
   2350                   if (fclose(fp) == 0)
   2351                      return 1;
   2352 
   2353                   error = errno; /* from fclose */
   2354                }
   2355 
   2356                else
   2357                {
   2358                   error = errno; /* from fflush or ferror */
   2359                   (void)fclose(fp);
   2360                }
   2361 
   2362                (void)remove(file_name);
   2363                /* The image has already been cleaned up; this is just used to
   2364                 * set the error (because the original write succeeded).
   2365                 */
   2366                return png_image_error(image, strerror(error));
   2367             }
   2368 
   2369             else
   2370             {
   2371                /* Clean up: just the opened file. */
   2372                (void)fclose(fp);
   2373                (void)remove(file_name);
   2374                return 0;
   2375             }
   2376          }
   2377 
   2378          else
   2379             return png_image_error(image, strerror(errno));
   2380       }
   2381 
   2382       else
   2383          return png_image_error(image,
   2384              "png_image_write_to_file: invalid argument");
   2385    }
   2386 
   2387    else if (image != NULL)
   2388       return png_image_error(image,
   2389           "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
   2390 
   2391    else
   2392       return 0;
   2393 }
   2394 #endif /* SIMPLIFIED_WRITE_STDIO */
   2395 #endif /* SIMPLIFIED_WRITE */
   2396 #endif /* WRITE */
   2397