3dphotoshoot

diff libs/libpng/pngwrite.c @ 14:06dc8b9b4f89

added libimago, libjpeg and libpng
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 07 Jun 2015 17:25:49 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/libpng/pngwrite.c	Sun Jun 07 17:25:49 2015 +0300
     1.3 @@ -0,0 +1,1547 @@
     1.4 +
     1.5 +/* pngwrite.c - general routines to write a PNG file
     1.6 + *
     1.7 + * Last changed in libpng 1.2.31 [August 19, 2008]
     1.8 + * For conditions of distribution and use, see copyright notice in png.h
     1.9 + * Copyright (c) 1998-2008 Glenn Randers-Pehrson
    1.10 + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
    1.11 + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
    1.12 + */
    1.13 +
    1.14 +/* get internal access to png.h */
    1.15 +#define PNG_INTERNAL
    1.16 +#include "png.h"
    1.17 +#ifdef PNG_WRITE_SUPPORTED
    1.18 +
    1.19 +/* Writes all the PNG information.  This is the suggested way to use the
    1.20 + * library.  If you have a new chunk to add, make a function to write it,
    1.21 + * and put it in the correct location here.  If you want the chunk written
    1.22 + * after the image data, put it in png_write_end().  I strongly encourage
    1.23 + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
    1.24 + * the chunk, as that will keep the code from breaking if you want to just
    1.25 + * write a plain PNG file.  If you have long comments, I suggest writing
    1.26 + * them in png_write_end(), and compressing them.
    1.27 + */
    1.28 +void PNGAPI
    1.29 +png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
    1.30 +{
    1.31 +   png_debug(1, "in png_write_info_before_PLTE\n");
    1.32 +   if (png_ptr == NULL || info_ptr == NULL)
    1.33 +      return;
    1.34 +   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
    1.35 +   {
    1.36 +   png_write_sig(png_ptr); /* write PNG signature */
    1.37 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
    1.38 +   if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
    1.39 +   {
    1.40 +      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
    1.41 +      png_ptr->mng_features_permitted=0;
    1.42 +   }
    1.43 +#endif
    1.44 +   /* write IHDR information. */
    1.45 +   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
    1.46 +      info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
    1.47 +      info_ptr->filter_type,
    1.48 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
    1.49 +      info_ptr->interlace_type);
    1.50 +#else
    1.51 +      0);
    1.52 +#endif
    1.53 +   /* the rest of these check to see if the valid field has the appropriate
    1.54 +      flag set, and if it does, writes the chunk. */
    1.55 +#if defined(PNG_WRITE_gAMA_SUPPORTED)
    1.56 +   if (info_ptr->valid & PNG_INFO_gAMA)
    1.57 +   {
    1.58 +#  ifdef PNG_FLOATING_POINT_SUPPORTED
    1.59 +      png_write_gAMA(png_ptr, info_ptr->gamma);
    1.60 +#else
    1.61 +#ifdef PNG_FIXED_POINT_SUPPORTED
    1.62 +      png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
    1.63 +#  endif
    1.64 +#endif
    1.65 +   }
    1.66 +#endif
    1.67 +#if defined(PNG_WRITE_sRGB_SUPPORTED)
    1.68 +   if (info_ptr->valid & PNG_INFO_sRGB)
    1.69 +      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
    1.70 +#endif
    1.71 +#if defined(PNG_WRITE_iCCP_SUPPORTED)
    1.72 +   if (info_ptr->valid & PNG_INFO_iCCP)
    1.73 +      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
    1.74 +                     info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
    1.75 +#endif
    1.76 +#if defined(PNG_WRITE_sBIT_SUPPORTED)
    1.77 +   if (info_ptr->valid & PNG_INFO_sBIT)
    1.78 +      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
    1.79 +#endif
    1.80 +#if defined(PNG_WRITE_cHRM_SUPPORTED)
    1.81 +   if (info_ptr->valid & PNG_INFO_cHRM)
    1.82 +   {
    1.83 +#ifdef PNG_FLOATING_POINT_SUPPORTED
    1.84 +      png_write_cHRM(png_ptr,
    1.85 +         info_ptr->x_white, info_ptr->y_white,
    1.86 +         info_ptr->x_red, info_ptr->y_red,
    1.87 +         info_ptr->x_green, info_ptr->y_green,
    1.88 +         info_ptr->x_blue, info_ptr->y_blue);
    1.89 +#else
    1.90 +#  ifdef PNG_FIXED_POINT_SUPPORTED
    1.91 +      png_write_cHRM_fixed(png_ptr,
    1.92 +         info_ptr->int_x_white, info_ptr->int_y_white,
    1.93 +         info_ptr->int_x_red, info_ptr->int_y_red,
    1.94 +         info_ptr->int_x_green, info_ptr->int_y_green,
    1.95 +         info_ptr->int_x_blue, info_ptr->int_y_blue);
    1.96 +#  endif
    1.97 +#endif
    1.98 +   }
    1.99 +#endif
   1.100 +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   1.101 +   if (info_ptr->unknown_chunks_num)
   1.102 +   {
   1.103 +       png_unknown_chunk *up;
   1.104 +
   1.105 +       png_debug(5, "writing extra chunks\n");
   1.106 +
   1.107 +       for (up = info_ptr->unknown_chunks;
   1.108 +            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
   1.109 +            up++)
   1.110 +       {
   1.111 +         int keep=png_handle_as_unknown(png_ptr, up->name);
   1.112 +         if (keep != PNG_HANDLE_CHUNK_NEVER &&
   1.113 +            up->location && !(up->location & PNG_HAVE_PLTE) &&
   1.114 +            !(up->location & PNG_HAVE_IDAT) &&
   1.115 +            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
   1.116 +            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
   1.117 +         {
   1.118 +            if (up->size == 0)
   1.119 +               png_warning(png_ptr, "Writing zero-length unknown chunk");
   1.120 +            png_write_chunk(png_ptr, up->name, up->data, up->size);
   1.121 +         }
   1.122 +       }
   1.123 +   }
   1.124 +#endif
   1.125 +      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
   1.126 +   }
   1.127 +}
   1.128 +
   1.129 +void PNGAPI
   1.130 +png_write_info(png_structp png_ptr, png_infop info_ptr)
   1.131 +{
   1.132 +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
   1.133 +   int i;
   1.134 +#endif
   1.135 +
   1.136 +   png_debug(1, "in png_write_info\n");
   1.137 +
   1.138 +   if (png_ptr == NULL || info_ptr == NULL)
   1.139 +      return;
   1.140 +
   1.141 +   png_write_info_before_PLTE(png_ptr, info_ptr);
   1.142 +
   1.143 +   if (info_ptr->valid & PNG_INFO_PLTE)
   1.144 +      png_write_PLTE(png_ptr, info_ptr->palette,
   1.145 +         (png_uint_32)info_ptr->num_palette);
   1.146 +   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   1.147 +      png_error(png_ptr, "Valid palette required for paletted images");
   1.148 +
   1.149 +#if defined(PNG_WRITE_tRNS_SUPPORTED)
   1.150 +   if (info_ptr->valid & PNG_INFO_tRNS)
   1.151 +      {
   1.152 +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
   1.153 +         /* invert the alpha channel (in tRNS) */
   1.154 +         if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
   1.155 +            info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   1.156 +         {
   1.157 +            int j;
   1.158 +            for (j=0; j<(int)info_ptr->num_trans; j++)
   1.159 +               info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
   1.160 +         }
   1.161 +#endif
   1.162 +      png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
   1.163 +         info_ptr->num_trans, info_ptr->color_type);
   1.164 +      }
   1.165 +#endif
   1.166 +#if defined(PNG_WRITE_bKGD_SUPPORTED)
   1.167 +   if (info_ptr->valid & PNG_INFO_bKGD)
   1.168 +      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
   1.169 +#endif
   1.170 +#if defined(PNG_WRITE_hIST_SUPPORTED)
   1.171 +   if (info_ptr->valid & PNG_INFO_hIST)
   1.172 +      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
   1.173 +#endif
   1.174 +#if defined(PNG_WRITE_oFFs_SUPPORTED)
   1.175 +   if (info_ptr->valid & PNG_INFO_oFFs)
   1.176 +      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
   1.177 +         info_ptr->offset_unit_type);
   1.178 +#endif
   1.179 +#if defined(PNG_WRITE_pCAL_SUPPORTED)
   1.180 +   if (info_ptr->valid & PNG_INFO_pCAL)
   1.181 +      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
   1.182 +         info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
   1.183 +         info_ptr->pcal_units, info_ptr->pcal_params);
   1.184 +#endif
   1.185 +#if defined(PNG_WRITE_sCAL_SUPPORTED)
   1.186 +   if (info_ptr->valid & PNG_INFO_sCAL)
   1.187 +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
   1.188 +      png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
   1.189 +          info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
   1.190 +#else
   1.191 +#ifdef PNG_FIXED_POINT_SUPPORTED
   1.192 +      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
   1.193 +          info_ptr->scal_s_width, info_ptr->scal_s_height);
   1.194 +#else
   1.195 +      png_warning(png_ptr,
   1.196 +          "png_write_sCAL not supported; sCAL chunk not written.");
   1.197 +#endif
   1.198 +#endif
   1.199 +#endif
   1.200 +#if defined(PNG_WRITE_pHYs_SUPPORTED)
   1.201 +   if (info_ptr->valid & PNG_INFO_pHYs)
   1.202 +      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
   1.203 +         info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
   1.204 +#endif
   1.205 +#if defined(PNG_WRITE_tIME_SUPPORTED)
   1.206 +   if (info_ptr->valid & PNG_INFO_tIME)
   1.207 +   {
   1.208 +      png_write_tIME(png_ptr, &(info_ptr->mod_time));
   1.209 +      png_ptr->mode |= PNG_WROTE_tIME;
   1.210 +   }
   1.211 +#endif
   1.212 +#if defined(PNG_WRITE_sPLT_SUPPORTED)
   1.213 +   if (info_ptr->valid & PNG_INFO_sPLT)
   1.214 +     for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
   1.215 +       png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
   1.216 +#endif
   1.217 +#if defined(PNG_WRITE_TEXT_SUPPORTED)
   1.218 +   /* Check to see if we need to write text chunks */
   1.219 +   for (i = 0; i < info_ptr->num_text; i++)
   1.220 +   {
   1.221 +      png_debug2(2, "Writing header text chunk %d, type %d\n", i,
   1.222 +         info_ptr->text[i].compression);
   1.223 +      /* an internationalized chunk? */
   1.224 +      if (info_ptr->text[i].compression > 0)
   1.225 +      {
   1.226 +#if defined(PNG_WRITE_iTXt_SUPPORTED)
   1.227 +          /* write international chunk */
   1.228 +          png_write_iTXt(png_ptr,
   1.229 +                         info_ptr->text[i].compression,
   1.230 +                         info_ptr->text[i].key,
   1.231 +                         info_ptr->text[i].lang,
   1.232 +                         info_ptr->text[i].lang_key,
   1.233 +                         info_ptr->text[i].text);
   1.234 +#else
   1.235 +          png_warning(png_ptr, "Unable to write international text");
   1.236 +#endif
   1.237 +          /* Mark this chunk as written */
   1.238 +          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
   1.239 +      }
   1.240 +      /* If we want a compressed text chunk */
   1.241 +      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
   1.242 +      {
   1.243 +#if defined(PNG_WRITE_zTXt_SUPPORTED)
   1.244 +         /* write compressed chunk */
   1.245 +         png_write_zTXt(png_ptr, info_ptr->text[i].key,
   1.246 +            info_ptr->text[i].text, 0,
   1.247 +            info_ptr->text[i].compression);
   1.248 +#else
   1.249 +         png_warning(png_ptr, "Unable to write compressed text");
   1.250 +#endif
   1.251 +         /* Mark this chunk as written */
   1.252 +         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
   1.253 +      }
   1.254 +      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
   1.255 +      {
   1.256 +#if defined(PNG_WRITE_tEXt_SUPPORTED)
   1.257 +         /* write uncompressed chunk */
   1.258 +         png_write_tEXt(png_ptr, info_ptr->text[i].key,
   1.259 +                         info_ptr->text[i].text,
   1.260 +                         0);
   1.261 +#else
   1.262 +         png_warning(png_ptr, "Unable to write uncompressed text");
   1.263 +#endif
   1.264 +         /* Mark this chunk as written */
   1.265 +         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
   1.266 +      }
   1.267 +   }
   1.268 +#endif
   1.269 +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   1.270 +   if (info_ptr->unknown_chunks_num)
   1.271 +   {
   1.272 +       png_unknown_chunk *up;
   1.273 +
   1.274 +       png_debug(5, "writing extra chunks\n");
   1.275 +
   1.276 +       for (up = info_ptr->unknown_chunks;
   1.277 +            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
   1.278 +            up++)
   1.279 +       {
   1.280 +         int keep=png_handle_as_unknown(png_ptr, up->name);
   1.281 +         if (keep != PNG_HANDLE_CHUNK_NEVER &&
   1.282 +            up->location && (up->location & PNG_HAVE_PLTE) &&
   1.283 +            !(up->location & PNG_HAVE_IDAT) &&
   1.284 +            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
   1.285 +            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
   1.286 +         {
   1.287 +            png_write_chunk(png_ptr, up->name, up->data, up->size);
   1.288 +         }
   1.289 +       }
   1.290 +   }
   1.291 +#endif
   1.292 +}
   1.293 +
   1.294 +/* Writes the end of the PNG file.  If you don't want to write comments or
   1.295 + * time information, you can pass NULL for info.  If you already wrote these
   1.296 + * in png_write_info(), do not write them again here.  If you have long
   1.297 + * comments, I suggest writing them here, and compressing them.
   1.298 + */
   1.299 +void PNGAPI
   1.300 +png_write_end(png_structp png_ptr, png_infop info_ptr)
   1.301 +{
   1.302 +   png_debug(1, "in png_write_end\n");
   1.303 +   if (png_ptr == NULL)
   1.304 +      return;
   1.305 +   if (!(png_ptr->mode & PNG_HAVE_IDAT))
   1.306 +      png_error(png_ptr, "No IDATs written into file");
   1.307 +
   1.308 +   /* see if user wants us to write information chunks */
   1.309 +   if (info_ptr != NULL)
   1.310 +   {
   1.311 +#if defined(PNG_WRITE_TEXT_SUPPORTED)
   1.312 +      int i; /* local index variable */
   1.313 +#endif
   1.314 +#if defined(PNG_WRITE_tIME_SUPPORTED)
   1.315 +      /* check to see if user has supplied a time chunk */
   1.316 +      if ((info_ptr->valid & PNG_INFO_tIME) &&
   1.317 +         !(png_ptr->mode & PNG_WROTE_tIME))
   1.318 +         png_write_tIME(png_ptr, &(info_ptr->mod_time));
   1.319 +#endif
   1.320 +#if defined(PNG_WRITE_TEXT_SUPPORTED)
   1.321 +      /* loop through comment chunks */
   1.322 +      for (i = 0; i < info_ptr->num_text; i++)
   1.323 +      {
   1.324 +         png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
   1.325 +            info_ptr->text[i].compression);
   1.326 +         /* an internationalized chunk? */
   1.327 +         if (info_ptr->text[i].compression > 0)
   1.328 +         {
   1.329 +#if defined(PNG_WRITE_iTXt_SUPPORTED)
   1.330 +             /* write international chunk */
   1.331 +             png_write_iTXt(png_ptr,
   1.332 +                         info_ptr->text[i].compression,
   1.333 +                         info_ptr->text[i].key,
   1.334 +                         info_ptr->text[i].lang,
   1.335 +                         info_ptr->text[i].lang_key,
   1.336 +                         info_ptr->text[i].text);
   1.337 +#else
   1.338 +             png_warning(png_ptr, "Unable to write international text");
   1.339 +#endif
   1.340 +             /* Mark this chunk as written */
   1.341 +             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
   1.342 +         }
   1.343 +         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
   1.344 +         {
   1.345 +#if defined(PNG_WRITE_zTXt_SUPPORTED)
   1.346 +            /* write compressed chunk */
   1.347 +            png_write_zTXt(png_ptr, info_ptr->text[i].key,
   1.348 +               info_ptr->text[i].text, 0,
   1.349 +               info_ptr->text[i].compression);
   1.350 +#else
   1.351 +            png_warning(png_ptr, "Unable to write compressed text");
   1.352 +#endif
   1.353 +            /* Mark this chunk as written */
   1.354 +            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
   1.355 +         }
   1.356 +         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
   1.357 +         {
   1.358 +#if defined(PNG_WRITE_tEXt_SUPPORTED)
   1.359 +            /* write uncompressed chunk */
   1.360 +            png_write_tEXt(png_ptr, info_ptr->text[i].key,
   1.361 +               info_ptr->text[i].text, 0);
   1.362 +#else
   1.363 +            png_warning(png_ptr, "Unable to write uncompressed text");
   1.364 +#endif
   1.365 +
   1.366 +            /* Mark this chunk as written */
   1.367 +            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
   1.368 +         }
   1.369 +      }
   1.370 +#endif
   1.371 +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   1.372 +   if (info_ptr->unknown_chunks_num)
   1.373 +   {
   1.374 +       png_unknown_chunk *up;
   1.375 +
   1.376 +       png_debug(5, "writing extra chunks\n");
   1.377 +
   1.378 +       for (up = info_ptr->unknown_chunks;
   1.379 +            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
   1.380 +            up++)
   1.381 +       {
   1.382 +         int keep=png_handle_as_unknown(png_ptr, up->name);
   1.383 +         if (keep != PNG_HANDLE_CHUNK_NEVER &&
   1.384 +            up->location && (up->location & PNG_AFTER_IDAT) &&
   1.385 +            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
   1.386 +            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
   1.387 +         {
   1.388 +            png_write_chunk(png_ptr, up->name, up->data, up->size);
   1.389 +         }
   1.390 +       }
   1.391 +   }
   1.392 +#endif
   1.393 +   }
   1.394 +
   1.395 +   png_ptr->mode |= PNG_AFTER_IDAT;
   1.396 +
   1.397 +   /* write end of PNG file */
   1.398 +   png_write_IEND(png_ptr);
   1.399 +   /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
   1.400 +    * and restored again in libpng-1.2.30, may cause some applications that
   1.401 +    * do not set png_ptr->output_flush_fn to crash.  If your application
   1.402 +    * experiences a problem, please try building libpng with
   1.403 +    * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
   1.404 +    * png-mng-implement at lists.sf.net .  This kludge will be removed
   1.405 +    * from libpng-1.4.0.
   1.406 +    */
   1.407 +#if defined(PNG_WRITE_FLUSH_SUPPORTED) && \
   1.408 +    defined(PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED)
   1.409 +   png_flush(png_ptr);
   1.410 +#endif
   1.411 +}
   1.412 +
   1.413 +#if defined(PNG_WRITE_tIME_SUPPORTED)
   1.414 +#if !defined(_WIN32_WCE)
   1.415 +/* "time.h" functions are not supported on WindowsCE */
   1.416 +void PNGAPI
   1.417 +png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
   1.418 +{
   1.419 +   png_debug(1, "in png_convert_from_struct_tm\n");
   1.420 +   ptime->year = (png_uint_16)(1900 + ttime->tm_year);
   1.421 +   ptime->month = (png_byte)(ttime->tm_mon + 1);
   1.422 +   ptime->day = (png_byte)ttime->tm_mday;
   1.423 +   ptime->hour = (png_byte)ttime->tm_hour;
   1.424 +   ptime->minute = (png_byte)ttime->tm_min;
   1.425 +   ptime->second = (png_byte)ttime->tm_sec;
   1.426 +}
   1.427 +
   1.428 +void PNGAPI
   1.429 +png_convert_from_time_t(png_timep ptime, time_t ttime)
   1.430 +{
   1.431 +   struct tm *tbuf;
   1.432 +
   1.433 +   png_debug(1, "in png_convert_from_time_t\n");
   1.434 +   tbuf = gmtime(&ttime);
   1.435 +   png_convert_from_struct_tm(ptime, tbuf);
   1.436 +}
   1.437 +#endif
   1.438 +#endif
   1.439 +
   1.440 +/* Initialize png_ptr structure, and allocate any memory needed */
   1.441 +png_structp PNGAPI
   1.442 +png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
   1.443 +   png_error_ptr error_fn, png_error_ptr warn_fn)
   1.444 +{
   1.445 +#ifdef PNG_USER_MEM_SUPPORTED
   1.446 +   return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
   1.447 +      warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
   1.448 +}
   1.449 +
   1.450 +/* Alternate initialize png_ptr structure, and allocate any memory needed */
   1.451 +png_structp PNGAPI
   1.452 +png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
   1.453 +   png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
   1.454 +   png_malloc_ptr malloc_fn, png_free_ptr free_fn)
   1.455 +{
   1.456 +#endif /* PNG_USER_MEM_SUPPORTED */
   1.457 +#ifdef PNG_SETJMP_SUPPORTED
   1.458 +    volatile
   1.459 +#endif
   1.460 +    png_structp png_ptr;
   1.461 +#ifdef PNG_SETJMP_SUPPORTED
   1.462 +#ifdef USE_FAR_KEYWORD
   1.463 +   jmp_buf jmpbuf;
   1.464 +#endif
   1.465 +#endif
   1.466 +   int i;
   1.467 +   png_debug(1, "in png_create_write_struct\n");
   1.468 +#ifdef PNG_USER_MEM_SUPPORTED
   1.469 +   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
   1.470 +      (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
   1.471 +#else
   1.472 +   png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
   1.473 +#endif /* PNG_USER_MEM_SUPPORTED */
   1.474 +   if (png_ptr == NULL)
   1.475 +      return (NULL);
   1.476 +
   1.477 +   /* added at libpng-1.2.6 */
   1.478 +#ifdef PNG_SET_USER_LIMITS_SUPPORTED
   1.479 +   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
   1.480 +   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
   1.481 +#endif
   1.482 +
   1.483 +#ifdef PNG_SETJMP_SUPPORTED
   1.484 +#ifdef USE_FAR_KEYWORD
   1.485 +   if (setjmp(jmpbuf))
   1.486 +#else
   1.487 +   if (setjmp(png_ptr->jmpbuf))
   1.488 +#endif
   1.489 +   {
   1.490 +      png_free(png_ptr, png_ptr->zbuf);
   1.491 +       png_ptr->zbuf=NULL;
   1.492 +      png_destroy_struct(png_ptr);
   1.493 +      return (NULL);
   1.494 +   }
   1.495 +#ifdef USE_FAR_KEYWORD
   1.496 +   png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf));
   1.497 +#endif
   1.498 +#endif
   1.499 +
   1.500 +#ifdef PNG_USER_MEM_SUPPORTED
   1.501 +   png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
   1.502 +#endif /* PNG_USER_MEM_SUPPORTED */
   1.503 +   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
   1.504 +
   1.505 +   if (user_png_ver)
   1.506 +   {
   1.507 +     i=0;
   1.508 +     do
   1.509 +     {
   1.510 +       if (user_png_ver[i] != png_libpng_ver[i])
   1.511 +          png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
   1.512 +     } while (png_libpng_ver[i++]);
   1.513 +   }
   1.514 +
   1.515 +   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
   1.516 +   {
   1.517 +     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
   1.518 +      * we must recompile any applications that use any older library version.
   1.519 +      * For versions after libpng 1.0, we will be compatible, so we need
   1.520 +      * only check the first digit.
   1.521 +      */
   1.522 +     if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
   1.523 +         (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
   1.524 +         (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
   1.525 +     {
   1.526 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
   1.527 +        char msg[80];
   1.528 +        if (user_png_ver)
   1.529 +        {
   1.530 +          png_snprintf(msg, 80,
   1.531 +             "Application was compiled with png.h from libpng-%.20s",
   1.532 +             user_png_ver);
   1.533 +          png_warning(png_ptr, msg);
   1.534 +        }
   1.535 +        png_snprintf(msg, 80,
   1.536 +           "Application  is  running with png.c from libpng-%.20s",
   1.537 +           png_libpng_ver);
   1.538 +        png_warning(png_ptr, msg);
   1.539 +#endif
   1.540 +#ifdef PNG_ERROR_NUMBERS_SUPPORTED
   1.541 +        png_ptr->flags=0;
   1.542 +#endif
   1.543 +        png_error(png_ptr,
   1.544 +           "Incompatible libpng version in application and library");
   1.545 +     }
   1.546 +   }
   1.547 +
   1.548 +   /* initialize zbuf - compression buffer */
   1.549 +   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
   1.550 +   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
   1.551 +      (png_uint_32)png_ptr->zbuf_size);
   1.552 +
   1.553 +   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
   1.554 +      png_flush_ptr_NULL);
   1.555 +
   1.556 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   1.557 +   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
   1.558 +      1, png_doublep_NULL, png_doublep_NULL);
   1.559 +#endif
   1.560 +
   1.561 +#ifdef PNG_SETJMP_SUPPORTED
   1.562 +/* Applications that neglect to set up their own setjmp() and then encounter
   1.563 +   a png_error() will longjmp here.  Since the jmpbuf is then meaningless we
   1.564 +   abort instead of returning. */
   1.565 +#ifdef USE_FAR_KEYWORD
   1.566 +   if (setjmp(jmpbuf))
   1.567 +      PNG_ABORT();
   1.568 +   png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf));
   1.569 +#else
   1.570 +   if (setjmp(png_ptr->jmpbuf))
   1.571 +      PNG_ABORT();
   1.572 +#endif
   1.573 +#endif
   1.574 +   return (png_ptr);
   1.575 +}
   1.576 +
   1.577 +/* Initialize png_ptr structure, and allocate any memory needed */
   1.578 +#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
   1.579 +/* Deprecated. */
   1.580 +#undef png_write_init
   1.581 +void PNGAPI
   1.582 +png_write_init(png_structp png_ptr)
   1.583 +{
   1.584 +   /* We only come here via pre-1.0.7-compiled applications */
   1.585 +   png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
   1.586 +}
   1.587 +
   1.588 +void PNGAPI
   1.589 +png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
   1.590 +   png_size_t png_struct_size, png_size_t png_info_size)
   1.591 +{
   1.592 +   /* We only come here via pre-1.0.12-compiled applications */
   1.593 +   if (png_ptr == NULL) return;
   1.594 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
   1.595 +   if (png_sizeof(png_struct) > png_struct_size ||
   1.596 +      png_sizeof(png_info) > png_info_size)
   1.597 +   {
   1.598 +      char msg[80];
   1.599 +      png_ptr->warning_fn=NULL;
   1.600 +      if (user_png_ver)
   1.601 +      {
   1.602 +        png_snprintf(msg, 80,
   1.603 +           "Application was compiled with png.h from libpng-%.20s",
   1.604 +           user_png_ver);
   1.605 +        png_warning(png_ptr, msg);
   1.606 +      }
   1.607 +      png_snprintf(msg, 80,
   1.608 +         "Application  is  running with png.c from libpng-%.20s",
   1.609 +         png_libpng_ver);
   1.610 +      png_warning(png_ptr, msg);
   1.611 +   }
   1.612 +#endif
   1.613 +   if (png_sizeof(png_struct) > png_struct_size)
   1.614 +     {
   1.615 +       png_ptr->error_fn=NULL;
   1.616 +#ifdef PNG_ERROR_NUMBERS_SUPPORTED
   1.617 +       png_ptr->flags=0;
   1.618 +#endif
   1.619 +       png_error(png_ptr,
   1.620 +       "The png struct allocated by the application for writing is too small.");
   1.621 +     }
   1.622 +   if (png_sizeof(png_info) > png_info_size)
   1.623 +     {
   1.624 +       png_ptr->error_fn=NULL;
   1.625 +#ifdef PNG_ERROR_NUMBERS_SUPPORTED
   1.626 +       png_ptr->flags=0;
   1.627 +#endif
   1.628 +       png_error(png_ptr,
   1.629 +       "The info struct allocated by the application for writing is too small.");
   1.630 +     }
   1.631 +   png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
   1.632 +}
   1.633 +#endif /* PNG_1_0_X || PNG_1_2_X */
   1.634 +
   1.635 +
   1.636 +void PNGAPI
   1.637 +png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
   1.638 +   png_size_t png_struct_size)
   1.639 +{
   1.640 +   png_structp png_ptr=*ptr_ptr;
   1.641 +#ifdef PNG_SETJMP_SUPPORTED
   1.642 +   jmp_buf tmp_jmp; /* to save current jump buffer */
   1.643 +#endif
   1.644 +
   1.645 +   int i = 0;
   1.646 +
   1.647 +   if (png_ptr == NULL)
   1.648 +      return;
   1.649 +
   1.650 +   do
   1.651 +   {
   1.652 +     if (user_png_ver[i] != png_libpng_ver[i])
   1.653 +     {
   1.654 +#ifdef PNG_LEGACY_SUPPORTED
   1.655 +       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
   1.656 +#else
   1.657 +       png_ptr->warning_fn=NULL;
   1.658 +       png_warning(png_ptr,
   1.659 + "Application uses deprecated png_write_init() and should be recompiled.");
   1.660 +       break;
   1.661 +#endif
   1.662 +     }
   1.663 +   } while (png_libpng_ver[i++]);
   1.664 +
   1.665 +   png_debug(1, "in png_write_init_3\n");
   1.666 +
   1.667 +#ifdef PNG_SETJMP_SUPPORTED
   1.668 +   /* save jump buffer and error functions */
   1.669 +   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
   1.670 +#endif
   1.671 +
   1.672 +   if (png_sizeof(png_struct) > png_struct_size)
   1.673 +     {
   1.674 +       png_destroy_struct(png_ptr);
   1.675 +       png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
   1.676 +       *ptr_ptr = png_ptr;
   1.677 +     }
   1.678 +
   1.679 +   /* reset all variables to 0 */
   1.680 +   png_memset(png_ptr, 0, png_sizeof(png_struct));
   1.681 +
   1.682 +   /* added at libpng-1.2.6 */
   1.683 +#ifdef PNG_SET_USER_LIMITS_SUPPORTED
   1.684 +   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
   1.685 +   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
   1.686 +#endif
   1.687 +
   1.688 +#ifdef PNG_SETJMP_SUPPORTED
   1.689 +   /* restore jump buffer */
   1.690 +   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
   1.691 +#endif
   1.692 +
   1.693 +   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
   1.694 +      png_flush_ptr_NULL);
   1.695 +
   1.696 +   /* initialize zbuf - compression buffer */
   1.697 +   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
   1.698 +   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
   1.699 +      (png_uint_32)png_ptr->zbuf_size);
   1.700 +
   1.701 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   1.702 +   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
   1.703 +      1, png_doublep_NULL, png_doublep_NULL);
   1.704 +#endif
   1.705 +}
   1.706 +
   1.707 +/* Write a few rows of image data.  If the image is interlaced,
   1.708 + * either you will have to write the 7 sub images, or, if you
   1.709 + * have called png_set_interlace_handling(), you will have to
   1.710 + * "write" the image seven times.
   1.711 + */
   1.712 +void PNGAPI
   1.713 +png_write_rows(png_structp png_ptr, png_bytepp row,
   1.714 +   png_uint_32 num_rows)
   1.715 +{
   1.716 +   png_uint_32 i; /* row counter */
   1.717 +   png_bytepp rp; /* row pointer */
   1.718 +
   1.719 +   png_debug(1, "in png_write_rows\n");
   1.720 +
   1.721 +   if (png_ptr == NULL)
   1.722 +      return;
   1.723 +
   1.724 +   /* loop through the rows */
   1.725 +   for (i = 0, rp = row; i < num_rows; i++, rp++)
   1.726 +   {
   1.727 +      png_write_row(png_ptr, *rp);
   1.728 +   }
   1.729 +}
   1.730 +
   1.731 +/* Write the image.  You only need to call this function once, even
   1.732 + * if you are writing an interlaced image.
   1.733 + */
   1.734 +void PNGAPI
   1.735 +png_write_image(png_structp png_ptr, png_bytepp image)
   1.736 +{
   1.737 +   png_uint_32 i; /* row index */
   1.738 +   int pass, num_pass; /* pass variables */
   1.739 +   png_bytepp rp; /* points to current row */
   1.740 +
   1.741 +   if (png_ptr == NULL)
   1.742 +      return;
   1.743 +
   1.744 +   png_debug(1, "in png_write_image\n");
   1.745 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
   1.746 +   /* intialize interlace handling.  If image is not interlaced,
   1.747 +      this will set pass to 1 */
   1.748 +   num_pass = png_set_interlace_handling(png_ptr);
   1.749 +#else
   1.750 +   num_pass = 1;
   1.751 +#endif
   1.752 +   /* loop through passes */
   1.753 +   for (pass = 0; pass < num_pass; pass++)
   1.754 +   {
   1.755 +      /* loop through image */
   1.756 +      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
   1.757 +      {
   1.758 +         png_write_row(png_ptr, *rp);
   1.759 +      }
   1.760 +   }
   1.761 +}
   1.762 +
   1.763 +/* called by user to write a row of image data */
   1.764 +void PNGAPI
   1.765 +png_write_row(png_structp png_ptr, png_bytep row)
   1.766 +{
   1.767 +   if (png_ptr == NULL)
   1.768 +      return;
   1.769 +   png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
   1.770 +      png_ptr->row_number, png_ptr->pass);
   1.771 +
   1.772 +   /* initialize transformations and other stuff if first time */
   1.773 +   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
   1.774 +   {
   1.775 +   /* make sure we wrote the header info */
   1.776 +   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
   1.777 +      png_error(png_ptr,
   1.778 +         "png_write_info was never called before png_write_row.");
   1.779 +
   1.780 +   /* check for transforms that have been set but were defined out */
   1.781 +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
   1.782 +   if (png_ptr->transformations & PNG_INVERT_MONO)
   1.783 +      png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
   1.784 +#endif
   1.785 +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
   1.786 +   if (png_ptr->transformations & PNG_FILLER)
   1.787 +      png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
   1.788 +#endif
   1.789 +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
   1.790 +   if (png_ptr->transformations & PNG_PACKSWAP)
   1.791 +      png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
   1.792 +#endif
   1.793 +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
   1.794 +   if (png_ptr->transformations & PNG_PACK)
   1.795 +      png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
   1.796 +#endif
   1.797 +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
   1.798 +   if (png_ptr->transformations & PNG_SHIFT)
   1.799 +      png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
   1.800 +#endif
   1.801 +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
   1.802 +   if (png_ptr->transformations & PNG_BGR)
   1.803 +      png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
   1.804 +#endif
   1.805 +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
   1.806 +   if (png_ptr->transformations & PNG_SWAP_BYTES)
   1.807 +      png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
   1.808 +#endif
   1.809 +
   1.810 +      png_write_start_row(png_ptr);
   1.811 +   }
   1.812 +
   1.813 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
   1.814 +   /* if interlaced and not interested in row, return */
   1.815 +   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   1.816 +   {
   1.817 +      switch (png_ptr->pass)
   1.818 +      {
   1.819 +         case 0:
   1.820 +            if (png_ptr->row_number & 0x07)
   1.821 +            {
   1.822 +               png_write_finish_row(png_ptr);
   1.823 +               return;
   1.824 +            }
   1.825 +            break;
   1.826 +         case 1:
   1.827 +            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
   1.828 +            {
   1.829 +               png_write_finish_row(png_ptr);
   1.830 +               return;
   1.831 +            }
   1.832 +            break;
   1.833 +         case 2:
   1.834 +            if ((png_ptr->row_number & 0x07) != 4)
   1.835 +            {
   1.836 +               png_write_finish_row(png_ptr);
   1.837 +               return;
   1.838 +            }
   1.839 +            break;
   1.840 +         case 3:
   1.841 +            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
   1.842 +            {
   1.843 +               png_write_finish_row(png_ptr);
   1.844 +               return;
   1.845 +            }
   1.846 +            break;
   1.847 +         case 4:
   1.848 +            if ((png_ptr->row_number & 0x03) != 2)
   1.849 +            {
   1.850 +               png_write_finish_row(png_ptr);
   1.851 +               return;
   1.852 +            }
   1.853 +            break;
   1.854 +         case 5:
   1.855 +            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
   1.856 +            {
   1.857 +               png_write_finish_row(png_ptr);
   1.858 +               return;
   1.859 +            }
   1.860 +            break;
   1.861 +         case 6:
   1.862 +            if (!(png_ptr->row_number & 0x01))
   1.863 +            {
   1.864 +               png_write_finish_row(png_ptr);
   1.865 +               return;
   1.866 +            }
   1.867 +            break;
   1.868 +      }
   1.869 +   }
   1.870 +#endif
   1.871 +
   1.872 +   /* set up row info for transformations */
   1.873 +   png_ptr->row_info.color_type = png_ptr->color_type;
   1.874 +   png_ptr->row_info.width = png_ptr->usr_width;
   1.875 +   png_ptr->row_info.channels = png_ptr->usr_channels;
   1.876 +   png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
   1.877 +   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
   1.878 +      png_ptr->row_info.channels);
   1.879 +
   1.880 +   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
   1.881 +      png_ptr->row_info.width);
   1.882 +
   1.883 +   png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
   1.884 +   png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
   1.885 +   png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
   1.886 +   png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
   1.887 +   png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
   1.888 +   png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
   1.889 +
   1.890 +   /* Copy user's row into buffer, leaving room for filter byte. */
   1.891 +   png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
   1.892 +      png_ptr->row_info.rowbytes);
   1.893 +
   1.894 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
   1.895 +   /* handle interlacing */
   1.896 +   if (png_ptr->interlaced && png_ptr->pass < 6 &&
   1.897 +      (png_ptr->transformations & PNG_INTERLACE))
   1.898 +   {
   1.899 +      png_do_write_interlace(&(png_ptr->row_info),
   1.900 +         png_ptr->row_buf + 1, png_ptr->pass);
   1.901 +      /* this should always get caught above, but still ... */
   1.902 +      if (!(png_ptr->row_info.width))
   1.903 +      {
   1.904 +         png_write_finish_row(png_ptr);
   1.905 +         return;
   1.906 +      }
   1.907 +   }
   1.908 +#endif
   1.909 +
   1.910 +   /* handle other transformations */
   1.911 +   if (png_ptr->transformations)
   1.912 +      png_do_write_transformations(png_ptr);
   1.913 +
   1.914 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
   1.915 +   /* Write filter_method 64 (intrapixel differencing) only if
   1.916 +    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
   1.917 +    * 2. Libpng did not write a PNG signature (this filter_method is only
   1.918 +    *    used in PNG datastreams that are embedded in MNG datastreams) and
   1.919 +    * 3. The application called png_permit_mng_features with a mask that
   1.920 +    *    included PNG_FLAG_MNG_FILTER_64 and
   1.921 +    * 4. The filter_method is 64 and
   1.922 +    * 5. The color_type is RGB or RGBA
   1.923 +    */
   1.924 +   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
   1.925 +      (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
   1.926 +   {
   1.927 +      /* Intrapixel differencing */
   1.928 +      png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
   1.929 +   }
   1.930 +#endif
   1.931 +
   1.932 +   /* Find a filter if necessary, filter the row and write it out. */
   1.933 +   png_write_find_filter(png_ptr, &(png_ptr->row_info));
   1.934 +
   1.935 +   if (png_ptr->write_row_fn != NULL)
   1.936 +      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
   1.937 +}
   1.938 +
   1.939 +#if defined(PNG_WRITE_FLUSH_SUPPORTED)
   1.940 +/* Set the automatic flush interval or 0 to turn flushing off */
   1.941 +void PNGAPI
   1.942 +png_set_flush(png_structp png_ptr, int nrows)
   1.943 +{
   1.944 +   png_debug(1, "in png_set_flush\n");
   1.945 +   if (png_ptr == NULL)
   1.946 +      return;
   1.947 +   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
   1.948 +}
   1.949 +
   1.950 +/* flush the current output buffers now */
   1.951 +void PNGAPI
   1.952 +png_write_flush(png_structp png_ptr)
   1.953 +{
   1.954 +   int wrote_IDAT;
   1.955 +
   1.956 +   png_debug(1, "in png_write_flush\n");
   1.957 +   if (png_ptr == NULL)
   1.958 +      return;
   1.959 +   /* We have already written out all of the data */
   1.960 +   if (png_ptr->row_number >= png_ptr->num_rows)
   1.961 +     return;
   1.962 +
   1.963 +   do
   1.964 +   {
   1.965 +      int ret;
   1.966 +
   1.967 +      /* compress the data */
   1.968 +      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
   1.969 +      wrote_IDAT = 0;
   1.970 +
   1.971 +      /* check for compression errors */
   1.972 +      if (ret != Z_OK)
   1.973 +      {
   1.974 +         if (png_ptr->zstream.msg != NULL)
   1.975 +            png_error(png_ptr, png_ptr->zstream.msg);
   1.976 +         else
   1.977 +            png_error(png_ptr, "zlib error");
   1.978 +      }
   1.979 +
   1.980 +      if (!(png_ptr->zstream.avail_out))
   1.981 +      {
   1.982 +         /* write the IDAT and reset the zlib output buffer */
   1.983 +         png_write_IDAT(png_ptr, png_ptr->zbuf,
   1.984 +                        png_ptr->zbuf_size);
   1.985 +         png_ptr->zstream.next_out = png_ptr->zbuf;
   1.986 +         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.987 +         wrote_IDAT = 1;
   1.988 +      }
   1.989 +   } while(wrote_IDAT == 1);
   1.990 +
   1.991 +   /* If there is any data left to be output, write it into a new IDAT */
   1.992 +   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
   1.993 +   {
   1.994 +      /* write the IDAT and reset the zlib output buffer */
   1.995 +      png_write_IDAT(png_ptr, png_ptr->zbuf,
   1.996 +                     png_ptr->zbuf_size - png_ptr->zstream.avail_out);
   1.997 +      png_ptr->zstream.next_out = png_ptr->zbuf;
   1.998 +      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.999 +   }
  1.1000 +   png_ptr->flush_rows = 0;
  1.1001 +   png_flush(png_ptr);
  1.1002 +}
  1.1003 +#endif /* PNG_WRITE_FLUSH_SUPPORTED */
  1.1004 +
  1.1005 +/* free all memory used by the write */
  1.1006 +void PNGAPI
  1.1007 +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
  1.1008 +{
  1.1009 +   png_structp png_ptr = NULL;
  1.1010 +   png_infop info_ptr = NULL;
  1.1011 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1012 +   png_free_ptr free_fn = NULL;
  1.1013 +   png_voidp mem_ptr = NULL;
  1.1014 +#endif
  1.1015 +
  1.1016 +   png_debug(1, "in png_destroy_write_struct\n");
  1.1017 +   if (png_ptr_ptr != NULL)
  1.1018 +   {
  1.1019 +      png_ptr = *png_ptr_ptr;
  1.1020 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1021 +      free_fn = png_ptr->free_fn;
  1.1022 +      mem_ptr = png_ptr->mem_ptr;
  1.1023 +#endif
  1.1024 +   }
  1.1025 +
  1.1026 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1027 +   if (png_ptr != NULL)
  1.1028 +   {
  1.1029 +      free_fn = png_ptr->free_fn;
  1.1030 +      mem_ptr = png_ptr->mem_ptr;
  1.1031 +   }
  1.1032 +#endif
  1.1033 +
  1.1034 +   if (info_ptr_ptr != NULL)
  1.1035 +      info_ptr = *info_ptr_ptr;
  1.1036 +
  1.1037 +   if (info_ptr != NULL)
  1.1038 +   {
  1.1039 +      if (png_ptr != NULL)
  1.1040 +      {
  1.1041 +        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
  1.1042 +
  1.1043 +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
  1.1044 +        if (png_ptr->num_chunk_list)
  1.1045 +        {
  1.1046 +           png_free(png_ptr, png_ptr->chunk_list);
  1.1047 +           png_ptr->chunk_list=NULL;
  1.1048 +           png_ptr->num_chunk_list = 0;
  1.1049 +        }
  1.1050 +#endif
  1.1051 +      }
  1.1052 +
  1.1053 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1054 +      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
  1.1055 +         (png_voidp)mem_ptr);
  1.1056 +#else
  1.1057 +      png_destroy_struct((png_voidp)info_ptr);
  1.1058 +#endif
  1.1059 +      *info_ptr_ptr = NULL;
  1.1060 +   }
  1.1061 +
  1.1062 +   if (png_ptr != NULL)
  1.1063 +   {
  1.1064 +      png_write_destroy(png_ptr);
  1.1065 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1066 +      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
  1.1067 +         (png_voidp)mem_ptr);
  1.1068 +#else
  1.1069 +      png_destroy_struct((png_voidp)png_ptr);
  1.1070 +#endif
  1.1071 +      *png_ptr_ptr = NULL;
  1.1072 +   }
  1.1073 +}
  1.1074 +
  1.1075 +
  1.1076 +/* Free any memory used in png_ptr struct (old method) */
  1.1077 +void /* PRIVATE */
  1.1078 +png_write_destroy(png_structp png_ptr)
  1.1079 +{
  1.1080 +#ifdef PNG_SETJMP_SUPPORTED
  1.1081 +   jmp_buf tmp_jmp; /* save jump buffer */
  1.1082 +#endif
  1.1083 +   png_error_ptr error_fn;
  1.1084 +   png_error_ptr warning_fn;
  1.1085 +   png_voidp error_ptr;
  1.1086 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1087 +   png_free_ptr free_fn;
  1.1088 +#endif
  1.1089 +
  1.1090 +   png_debug(1, "in png_write_destroy\n");
  1.1091 +   /* free any memory zlib uses */
  1.1092 +   deflateEnd(&png_ptr->zstream);
  1.1093 +
  1.1094 +   /* free our memory.  png_free checks NULL for us. */
  1.1095 +   png_free(png_ptr, png_ptr->zbuf);
  1.1096 +   png_free(png_ptr, png_ptr->row_buf);
  1.1097 +#ifndef PNG_NO_WRITE_FILTER
  1.1098 +   png_free(png_ptr, png_ptr->prev_row);
  1.1099 +   png_free(png_ptr, png_ptr->sub_row);
  1.1100 +   png_free(png_ptr, png_ptr->up_row);
  1.1101 +   png_free(png_ptr, png_ptr->avg_row);
  1.1102 +   png_free(png_ptr, png_ptr->paeth_row);
  1.1103 +#endif
  1.1104 +
  1.1105 +#if defined(PNG_TIME_RFC1123_SUPPORTED)
  1.1106 +   png_free(png_ptr, png_ptr->time_buffer);
  1.1107 +#endif
  1.1108 +
  1.1109 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.1110 +   png_free(png_ptr, png_ptr->prev_filters);
  1.1111 +   png_free(png_ptr, png_ptr->filter_weights);
  1.1112 +   png_free(png_ptr, png_ptr->inv_filter_weights);
  1.1113 +   png_free(png_ptr, png_ptr->filter_costs);
  1.1114 +   png_free(png_ptr, png_ptr->inv_filter_costs);
  1.1115 +#endif
  1.1116 +
  1.1117 +#ifdef PNG_SETJMP_SUPPORTED
  1.1118 +   /* reset structure */
  1.1119 +   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
  1.1120 +#endif
  1.1121 +
  1.1122 +   error_fn = png_ptr->error_fn;
  1.1123 +   warning_fn = png_ptr->warning_fn;
  1.1124 +   error_ptr = png_ptr->error_ptr;
  1.1125 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1126 +   free_fn = png_ptr->free_fn;
  1.1127 +#endif
  1.1128 +
  1.1129 +   png_memset(png_ptr, 0, png_sizeof(png_struct));
  1.1130 +
  1.1131 +   png_ptr->error_fn = error_fn;
  1.1132 +   png_ptr->warning_fn = warning_fn;
  1.1133 +   png_ptr->error_ptr = error_ptr;
  1.1134 +#ifdef PNG_USER_MEM_SUPPORTED
  1.1135 +   png_ptr->free_fn = free_fn;
  1.1136 +#endif
  1.1137 +
  1.1138 +#ifdef PNG_SETJMP_SUPPORTED
  1.1139 +   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
  1.1140 +#endif
  1.1141 +}
  1.1142 +
  1.1143 +/* Allow the application to select one or more row filters to use. */
  1.1144 +void PNGAPI
  1.1145 +png_set_filter(png_structp png_ptr, int method, int filters)
  1.1146 +{
  1.1147 +   png_debug(1, "in png_set_filter\n");
  1.1148 +   if (png_ptr == NULL)
  1.1149 +      return;
  1.1150 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
  1.1151 +   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
  1.1152 +      (method == PNG_INTRAPIXEL_DIFFERENCING))
  1.1153 +         method = PNG_FILTER_TYPE_BASE;
  1.1154 +#endif
  1.1155 +   if (method == PNG_FILTER_TYPE_BASE)
  1.1156 +   {
  1.1157 +      switch (filters & (PNG_ALL_FILTERS | 0x07))
  1.1158 +      {
  1.1159 +#ifndef PNG_NO_WRITE_FILTER
  1.1160 +         case 5:
  1.1161 +         case 6:
  1.1162 +         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
  1.1163 +#endif /* PNG_NO_WRITE_FILTER */
  1.1164 +         case PNG_FILTER_VALUE_NONE:
  1.1165 +              png_ptr->do_filter=PNG_FILTER_NONE; break;
  1.1166 +#ifndef PNG_NO_WRITE_FILTER
  1.1167 +         case PNG_FILTER_VALUE_SUB:
  1.1168 +              png_ptr->do_filter=PNG_FILTER_SUB; break;
  1.1169 +         case PNG_FILTER_VALUE_UP:
  1.1170 +              png_ptr->do_filter=PNG_FILTER_UP; break;
  1.1171 +         case PNG_FILTER_VALUE_AVG:
  1.1172 +              png_ptr->do_filter=PNG_FILTER_AVG; break;
  1.1173 +         case PNG_FILTER_VALUE_PAETH:
  1.1174 +              png_ptr->do_filter=PNG_FILTER_PAETH; break;
  1.1175 +         default: png_ptr->do_filter = (png_byte)filters; break;
  1.1176 +#else
  1.1177 +         default: png_warning(png_ptr, "Unknown row filter for method 0");
  1.1178 +#endif /* PNG_NO_WRITE_FILTER */
  1.1179 +      }
  1.1180 +
  1.1181 +      /* If we have allocated the row_buf, this means we have already started
  1.1182 +       * with the image and we should have allocated all of the filter buffers
  1.1183 +       * that have been selected.  If prev_row isn't already allocated, then
  1.1184 +       * it is too late to start using the filters that need it, since we
  1.1185 +       * will be missing the data in the previous row.  If an application
  1.1186 +       * wants to start and stop using particular filters during compression,
  1.1187 +       * it should start out with all of the filters, and then add and
  1.1188 +       * remove them after the start of compression.
  1.1189 +       */
  1.1190 +      if (png_ptr->row_buf != NULL)
  1.1191 +      {
  1.1192 +#ifndef PNG_NO_WRITE_FILTER
  1.1193 +         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
  1.1194 +         {
  1.1195 +            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
  1.1196 +              (png_ptr->rowbytes + 1));
  1.1197 +            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
  1.1198 +         }
  1.1199 +
  1.1200 +         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
  1.1201 +         {
  1.1202 +            if (png_ptr->prev_row == NULL)
  1.1203 +            {
  1.1204 +               png_warning(png_ptr, "Can't add Up filter after starting");
  1.1205 +               png_ptr->do_filter &= ~PNG_FILTER_UP;
  1.1206 +            }
  1.1207 +            else
  1.1208 +            {
  1.1209 +               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
  1.1210 +                  (png_ptr->rowbytes + 1));
  1.1211 +               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
  1.1212 +            }
  1.1213 +         }
  1.1214 +
  1.1215 +         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
  1.1216 +         {
  1.1217 +            if (png_ptr->prev_row == NULL)
  1.1218 +            {
  1.1219 +               png_warning(png_ptr, "Can't add Average filter after starting");
  1.1220 +               png_ptr->do_filter &= ~PNG_FILTER_AVG;
  1.1221 +            }
  1.1222 +            else
  1.1223 +            {
  1.1224 +               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
  1.1225 +                  (png_ptr->rowbytes + 1));
  1.1226 +               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
  1.1227 +            }
  1.1228 +         }
  1.1229 +
  1.1230 +         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
  1.1231 +             png_ptr->paeth_row == NULL)
  1.1232 +         {
  1.1233 +            if (png_ptr->prev_row == NULL)
  1.1234 +            {
  1.1235 +               png_warning(png_ptr, "Can't add Paeth filter after starting");
  1.1236 +               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
  1.1237 +            }
  1.1238 +            else
  1.1239 +            {
  1.1240 +               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
  1.1241 +                  (png_ptr->rowbytes + 1));
  1.1242 +               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
  1.1243 +            }
  1.1244 +         }
  1.1245 +
  1.1246 +         if (png_ptr->do_filter == PNG_NO_FILTERS)
  1.1247 +#endif /* PNG_NO_WRITE_FILTER */
  1.1248 +            png_ptr->do_filter = PNG_FILTER_NONE;
  1.1249 +      }
  1.1250 +   }
  1.1251 +   else
  1.1252 +      png_error(png_ptr, "Unknown custom filter method");
  1.1253 +}
  1.1254 +
  1.1255 +/* This allows us to influence the way in which libpng chooses the "best"
  1.1256 + * filter for the current scanline.  While the "minimum-sum-of-absolute-
  1.1257 + * differences metric is relatively fast and effective, there is some
  1.1258 + * question as to whether it can be improved upon by trying to keep the
  1.1259 + * filtered data going to zlib more consistent, hopefully resulting in
  1.1260 + * better compression.
  1.1261 + */
  1.1262 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
  1.1263 +void PNGAPI
  1.1264 +png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
  1.1265 +   int num_weights, png_doublep filter_weights,
  1.1266 +   png_doublep filter_costs)
  1.1267 +{
  1.1268 +   int i;
  1.1269 +
  1.1270 +   png_debug(1, "in png_set_filter_heuristics\n");
  1.1271 +   if (png_ptr == NULL)
  1.1272 +      return;
  1.1273 +   if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
  1.1274 +   {
  1.1275 +      png_warning(png_ptr, "Unknown filter heuristic method");
  1.1276 +      return;
  1.1277 +   }
  1.1278 +
  1.1279 +   if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
  1.1280 +   {
  1.1281 +      heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
  1.1282 +   }
  1.1283 +
  1.1284 +   if (num_weights < 0 || filter_weights == NULL ||
  1.1285 +      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
  1.1286 +   {
  1.1287 +      num_weights = 0;
  1.1288 +   }
  1.1289 +
  1.1290 +   png_ptr->num_prev_filters = (png_byte)num_weights;
  1.1291 +   png_ptr->heuristic_method = (png_byte)heuristic_method;
  1.1292 +
  1.1293 +   if (num_weights > 0)
  1.1294 +   {
  1.1295 +      if (png_ptr->prev_filters == NULL)
  1.1296 +      {
  1.1297 +         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
  1.1298 +            (png_uint_32)(png_sizeof(png_byte) * num_weights));
  1.1299 +
  1.1300 +         /* To make sure that the weighting starts out fairly */
  1.1301 +         for (i = 0; i < num_weights; i++)
  1.1302 +         {
  1.1303 +            png_ptr->prev_filters[i] = 255;
  1.1304 +         }
  1.1305 +      }
  1.1306 +
  1.1307 +      if (png_ptr->filter_weights == NULL)
  1.1308 +      {
  1.1309 +         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
  1.1310 +            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
  1.1311 +
  1.1312 +         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
  1.1313 +            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
  1.1314 +         for (i = 0; i < num_weights; i++)
  1.1315 +         {
  1.1316 +            png_ptr->inv_filter_weights[i] =
  1.1317 +            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
  1.1318 +         }
  1.1319 +      }
  1.1320 +
  1.1321 +      for (i = 0; i < num_weights; i++)
  1.1322 +      {
  1.1323 +         if (filter_weights[i] < 0.0)
  1.1324 +         {
  1.1325 +            png_ptr->inv_filter_weights[i] =
  1.1326 +            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
  1.1327 +         }
  1.1328 +         else
  1.1329 +         {
  1.1330 +            png_ptr->inv_filter_weights[i] =
  1.1331 +               (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
  1.1332 +            png_ptr->filter_weights[i] =
  1.1333 +               (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
  1.1334 +         }
  1.1335 +      }
  1.1336 +   }
  1.1337 +
  1.1338 +   /* If, in the future, there are other filter methods, this would
  1.1339 +    * need to be based on png_ptr->filter.
  1.1340 +    */
  1.1341 +   if (png_ptr->filter_costs == NULL)
  1.1342 +   {
  1.1343 +      png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
  1.1344 +         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
  1.1345 +
  1.1346 +      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
  1.1347 +         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
  1.1348 +
  1.1349 +      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
  1.1350 +      {
  1.1351 +         png_ptr->inv_filter_costs[i] =
  1.1352 +         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
  1.1353 +      }
  1.1354 +   }
  1.1355 +
  1.1356 +   /* Here is where we set the relative costs of the different filters.  We
  1.1357 +    * should take the desired compression level into account when setting
  1.1358 +    * the costs, so that Paeth, for instance, has a high relative cost at low
  1.1359 +    * compression levels, while it has a lower relative cost at higher
  1.1360 +    * compression settings.  The filter types are in order of increasing
  1.1361 +    * relative cost, so it would be possible to do this with an algorithm.
  1.1362 +    */
  1.1363 +   for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
  1.1364 +   {
  1.1365 +      if (filter_costs == NULL || filter_costs[i] < 0.0)
  1.1366 +      {
  1.1367 +         png_ptr->inv_filter_costs[i] =
  1.1368 +         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
  1.1369 +      }
  1.1370 +      else if (filter_costs[i] >= 1.0)
  1.1371 +      {
  1.1372 +         png_ptr->inv_filter_costs[i] =
  1.1373 +            (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
  1.1374 +         png_ptr->filter_costs[i] =
  1.1375 +            (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
  1.1376 +      }
  1.1377 +   }
  1.1378 +}
  1.1379 +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
  1.1380 +
  1.1381 +void PNGAPI
  1.1382 +png_set_compression_level(png_structp png_ptr, int level)
  1.1383 +{
  1.1384 +   png_debug(1, "in png_set_compression_level\n");
  1.1385 +   if (png_ptr == NULL)
  1.1386 +      return;
  1.1387 +   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
  1.1388 +   png_ptr->zlib_level = level;
  1.1389 +}
  1.1390 +
  1.1391 +void PNGAPI
  1.1392 +png_set_compression_mem_level(png_structp png_ptr, int mem_level)
  1.1393 +{
  1.1394 +   png_debug(1, "in png_set_compression_mem_level\n");
  1.1395 +   if (png_ptr == NULL)
  1.1396 +      return;
  1.1397 +   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
  1.1398 +   png_ptr->zlib_mem_level = mem_level;
  1.1399 +}
  1.1400 +
  1.1401 +void PNGAPI
  1.1402 +png_set_compression_strategy(png_structp png_ptr, int strategy)
  1.1403 +{
  1.1404 +   png_debug(1, "in png_set_compression_strategy\n");
  1.1405 +   if (png_ptr == NULL)
  1.1406 +      return;
  1.1407 +   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
  1.1408 +   png_ptr->zlib_strategy = strategy;
  1.1409 +}
  1.1410 +
  1.1411 +void PNGAPI
  1.1412 +png_set_compression_window_bits(png_structp png_ptr, int window_bits)
  1.1413 +{
  1.1414 +   if (png_ptr == NULL)
  1.1415 +      return;
  1.1416 +   if (window_bits > 15)
  1.1417 +      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
  1.1418 +   else if (window_bits < 8)
  1.1419 +      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
  1.1420 +#ifndef WBITS_8_OK
  1.1421 +   /* avoid libpng bug with 256-byte windows */
  1.1422 +   if (window_bits == 8)
  1.1423 +     {
  1.1424 +       png_warning(png_ptr, "Compression window is being reset to 512");
  1.1425 +       window_bits=9;
  1.1426 +     }
  1.1427 +#endif
  1.1428 +   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
  1.1429 +   png_ptr->zlib_window_bits = window_bits;
  1.1430 +}
  1.1431 +
  1.1432 +void PNGAPI
  1.1433 +png_set_compression_method(png_structp png_ptr, int method)
  1.1434 +{
  1.1435 +   png_debug(1, "in png_set_compression_method\n");
  1.1436 +   if (png_ptr == NULL)
  1.1437 +      return;
  1.1438 +   if (method != 8)
  1.1439 +      png_warning(png_ptr, "Only compression method 8 is supported by PNG");
  1.1440 +   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
  1.1441 +   png_ptr->zlib_method = method;
  1.1442 +}
  1.1443 +
  1.1444 +void PNGAPI
  1.1445 +png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
  1.1446 +{
  1.1447 +   if (png_ptr == NULL)
  1.1448 +      return;
  1.1449 +   png_ptr->write_row_fn = write_row_fn;
  1.1450 +}
  1.1451 +
  1.1452 +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
  1.1453 +void PNGAPI
  1.1454 +png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
  1.1455 +   write_user_transform_fn)
  1.1456 +{
  1.1457 +   png_debug(1, "in png_set_write_user_transform_fn\n");
  1.1458 +   if (png_ptr == NULL)
  1.1459 +      return;
  1.1460 +   png_ptr->transformations |= PNG_USER_TRANSFORM;
  1.1461 +   png_ptr->write_user_transform_fn = write_user_transform_fn;
  1.1462 +}
  1.1463 +#endif
  1.1464 +
  1.1465 +
  1.1466 +#if defined(PNG_INFO_IMAGE_SUPPORTED)
  1.1467 +void PNGAPI
  1.1468 +png_write_png(png_structp png_ptr, png_infop info_ptr,
  1.1469 +              int transforms, voidp params)
  1.1470 +{
  1.1471 +   if (png_ptr == NULL || info_ptr == NULL)
  1.1472 +      return;
  1.1473 +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
  1.1474 +   /* invert the alpha channel from opacity to transparency */
  1.1475 +   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
  1.1476 +       png_set_invert_alpha(png_ptr);
  1.1477 +#endif
  1.1478 +
  1.1479 +   /* Write the file header information. */
  1.1480 +   png_write_info(png_ptr, info_ptr);
  1.1481 +
  1.1482 +   /* ------ these transformations don't touch the info structure ------- */
  1.1483 +
  1.1484 +#if defined(PNG_WRITE_INVERT_SUPPORTED)
  1.1485 +   /* invert monochrome pixels */
  1.1486 +   if (transforms & PNG_TRANSFORM_INVERT_MONO)
  1.1487 +       png_set_invert_mono(png_ptr);
  1.1488 +#endif
  1.1489 +
  1.1490 +#if defined(PNG_WRITE_SHIFT_SUPPORTED)
  1.1491 +   /* Shift the pixels up to a legal bit depth and fill in
  1.1492 +    * as appropriate to correctly scale the image.
  1.1493 +    */
  1.1494 +   if ((transforms & PNG_TRANSFORM_SHIFT)
  1.1495 +               && (info_ptr->valid & PNG_INFO_sBIT))
  1.1496 +       png_set_shift(png_ptr, &info_ptr->sig_bit);
  1.1497 +#endif
  1.1498 +
  1.1499 +#if defined(PNG_WRITE_PACK_SUPPORTED)
  1.1500 +   /* pack pixels into bytes */
  1.1501 +   if (transforms & PNG_TRANSFORM_PACKING)
  1.1502 +       png_set_packing(png_ptr);
  1.1503 +#endif
  1.1504 +
  1.1505 +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
  1.1506 +   /* swap location of alpha bytes from ARGB to RGBA */
  1.1507 +   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
  1.1508 +       png_set_swap_alpha(png_ptr);
  1.1509 +#endif
  1.1510 +
  1.1511 +#if defined(PNG_WRITE_FILLER_SUPPORTED)
  1.1512 +   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
  1.1513 +    * RGB (4 channels -> 3 channels). The second parameter is not used.
  1.1514 +    */
  1.1515 +   if (transforms & PNG_TRANSFORM_STRIP_FILLER)
  1.1516 +       png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
  1.1517 +#endif
  1.1518 +
  1.1519 +#if defined(PNG_WRITE_BGR_SUPPORTED)
  1.1520 +   /* flip BGR pixels to RGB */
  1.1521 +   if (transforms & PNG_TRANSFORM_BGR)
  1.1522 +       png_set_bgr(png_ptr);
  1.1523 +#endif
  1.1524 +
  1.1525 +#if defined(PNG_WRITE_SWAP_SUPPORTED)
  1.1526 +   /* swap bytes of 16-bit files to most significant byte first */
  1.1527 +   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
  1.1528 +       png_set_swap(png_ptr);
  1.1529 +#endif
  1.1530 +
  1.1531 +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
  1.1532 +   /* swap bits of 1, 2, 4 bit packed pixel formats */
  1.1533 +   if (transforms & PNG_TRANSFORM_PACKSWAP)
  1.1534 +       png_set_packswap(png_ptr);
  1.1535 +#endif
  1.1536 +
  1.1537 +   /* ----------------------- end of transformations ------------------- */
  1.1538 +
  1.1539 +   /* write the bits */
  1.1540 +   if (info_ptr->valid & PNG_INFO_IDAT)
  1.1541 +       png_write_image(png_ptr, info_ptr->row_pointers);
  1.1542 +
  1.1543 +   /* It is REQUIRED to call this to finish writing the rest of the file */
  1.1544 +   png_write_end(png_ptr, info_ptr);
  1.1545 +
  1.1546 +   transforms = transforms; /* quiet compiler warnings */
  1.1547 +   params = params;
  1.1548 +}
  1.1549 +#endif
  1.1550 +#endif /* PNG_WRITE_SUPPORTED */