home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / flash078.zip / flashsource-r0_7_8.zip / libpng / pngwrite.c < prev    next >
C/C++ Source or Header  |  2001-04-27  |  46KB  |  1,367 lines

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