Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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