tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pngwrite.c (80181B)


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