vrshoot

diff libs/libpng/pngwutil.c @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/libpng/pngwutil.c	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,2827 @@
     1.4 +
     1.5 +/* pngwutil.c - utilities to write a PNG file
     1.6 + *
     1.7 + * Last changed in libpng 1.2.30 [August 15, 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 +#define PNG_INTERNAL
    1.15 +#include "png.h"
    1.16 +#ifdef PNG_WRITE_SUPPORTED
    1.17 +
    1.18 +/* Place a 32-bit number into a buffer in PNG byte order.  We work
    1.19 + * with unsigned numbers for convenience, although one supported
    1.20 + * ancillary chunk uses signed (two's complement) numbers.
    1.21 + */
    1.22 +void PNGAPI
    1.23 +png_save_uint_32(png_bytep buf, png_uint_32 i)
    1.24 +{
    1.25 +   buf[0] = (png_byte)((i >> 24) & 0xff);
    1.26 +   buf[1] = (png_byte)((i >> 16) & 0xff);
    1.27 +   buf[2] = (png_byte)((i >> 8) & 0xff);
    1.28 +   buf[3] = (png_byte)(i & 0xff);
    1.29 +}
    1.30 +
    1.31 +/* The png_save_int_32 function assumes integers are stored in two's
    1.32 + * complement format.  If this isn't the case, then this routine needs to
    1.33 + * be modified to write data in two's complement format.
    1.34 + */
    1.35 +void PNGAPI
    1.36 +png_save_int_32(png_bytep buf, png_int_32 i)
    1.37 +{
    1.38 +   buf[0] = (png_byte)((i >> 24) & 0xff);
    1.39 +   buf[1] = (png_byte)((i >> 16) & 0xff);
    1.40 +   buf[2] = (png_byte)((i >> 8) & 0xff);
    1.41 +   buf[3] = (png_byte)(i & 0xff);
    1.42 +}
    1.43 +
    1.44 +/* Place a 16-bit number into a buffer in PNG byte order.
    1.45 + * The parameter is declared unsigned int, not png_uint_16,
    1.46 + * just to avoid potential problems on pre-ANSI C compilers.
    1.47 + */
    1.48 +void PNGAPI
    1.49 +png_save_uint_16(png_bytep buf, unsigned int i)
    1.50 +{
    1.51 +   buf[0] = (png_byte)((i >> 8) & 0xff);
    1.52 +   buf[1] = (png_byte)(i & 0xff);
    1.53 +}
    1.54 +
    1.55 +/* Simple function to write the signature.  If we have already written
    1.56 + * the magic bytes of the signature, or more likely, the PNG stream is
    1.57 + * being embedded into another stream and doesn't need its own signature,
    1.58 + * we should call png_set_sig_bytes() to tell libpng how many of the
    1.59 + * bytes have already been written.
    1.60 + */
    1.61 +void /* PRIVATE */
    1.62 +png_write_sig(png_structp png_ptr)
    1.63 +{
    1.64 +   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
    1.65 +
    1.66 +   /* write the rest of the 8 byte signature */
    1.67 +   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
    1.68 +      (png_size_t)(8 - png_ptr->sig_bytes));
    1.69 +   if (png_ptr->sig_bytes < 3)
    1.70 +      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
    1.71 +}
    1.72 +
    1.73 +/* Write a PNG chunk all at once.  The type is an array of ASCII characters
    1.74 + * representing the chunk name.  The array must be at least 4 bytes in
    1.75 + * length, and does not need to be null terminated.  To be safe, pass the
    1.76 + * pre-defined chunk names here, and if you need a new one, define it
    1.77 + * where the others are defined.  The length is the length of the data.
    1.78 + * All the data must be present.  If that is not possible, use the
    1.79 + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
    1.80 + * functions instead.
    1.81 + */
    1.82 +void PNGAPI
    1.83 +png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
    1.84 +   png_bytep data, png_size_t length)
    1.85 +{
    1.86 +   if (png_ptr == NULL) return;
    1.87 +   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
    1.88 +   png_write_chunk_data(png_ptr, data, (png_size_t)length);
    1.89 +   png_write_chunk_end(png_ptr);
    1.90 +}
    1.91 +
    1.92 +/* Write the start of a PNG chunk.  The type is the chunk type.
    1.93 + * The total_length is the sum of the lengths of all the data you will be
    1.94 + * passing in png_write_chunk_data().
    1.95 + */
    1.96 +void PNGAPI
    1.97 +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
    1.98 +   png_uint_32 length)
    1.99 +{
   1.100 +   png_byte buf[8];
   1.101 +
   1.102 +   png_debug2(0, "Writing %s chunk, length = %lu\n", chunk_name,
   1.103 +      (unsigned long)length);
   1.104 +   if (png_ptr == NULL) return;
   1.105 +
   1.106 +   /* write the length and the chunk name */
   1.107 +   png_save_uint_32(buf, length);
   1.108 +   png_memcpy(buf + 4, chunk_name, 4);
   1.109 +   png_write_data(png_ptr, buf, (png_size_t)8);
   1.110 +   /* put the chunk name into png_ptr->chunk_name */
   1.111 +   png_memcpy(png_ptr->chunk_name, chunk_name, 4);
   1.112 +   /* reset the crc and run it over the chunk name */
   1.113 +   png_reset_crc(png_ptr);
   1.114 +   png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
   1.115 +}
   1.116 +
   1.117 +/* Write the data of a PNG chunk started with png_write_chunk_start().
   1.118 + * Note that multiple calls to this function are allowed, and that the
   1.119 + * sum of the lengths from these calls *must* add up to the total_length
   1.120 + * given to png_write_chunk_start().
   1.121 + */
   1.122 +void PNGAPI
   1.123 +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
   1.124 +{
   1.125 +   /* write the data, and run the CRC over it */
   1.126 +   if (png_ptr == NULL) return;
   1.127 +   if (data != NULL && length > 0)
   1.128 +   {
   1.129 +      png_write_data(png_ptr, data, length);
   1.130 +      /* update the CRC after writing the data,
   1.131 +       * in case that the user I/O routine alters it.
   1.132 +       */
   1.133 +      png_calculate_crc(png_ptr, data, length);
   1.134 +   }
   1.135 +}
   1.136 +
   1.137 +/* Finish a chunk started with png_write_chunk_start(). */
   1.138 +void PNGAPI
   1.139 +png_write_chunk_end(png_structp png_ptr)
   1.140 +{
   1.141 +   png_byte buf[4];
   1.142 +
   1.143 +   if (png_ptr == NULL) return;
   1.144 +
   1.145 +   /* write the crc in a single operation */
   1.146 +   png_save_uint_32(buf, png_ptr->crc);
   1.147 +
   1.148 +   png_write_data(png_ptr, buf, (png_size_t)4);
   1.149 +}
   1.150 +
   1.151 +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
   1.152 +/*
   1.153 + * This pair of functions encapsulates the operation of (a) compressing a
   1.154 + * text string, and (b) issuing it later as a series of chunk data writes.
   1.155 + * The compression_state structure is shared context for these functions
   1.156 + * set up by the caller in order to make the whole mess thread-safe.
   1.157 + */
   1.158 +
   1.159 +typedef struct
   1.160 +{
   1.161 +    char *input;   /* the uncompressed input data */
   1.162 +    int input_len;   /* its length */
   1.163 +    int num_output_ptr; /* number of output pointers used */
   1.164 +    int max_output_ptr; /* size of output_ptr */
   1.165 +    png_charpp output_ptr; /* array of pointers to output */
   1.166 +} compression_state;
   1.167 +
   1.168 +/* compress given text into storage in the png_ptr structure */
   1.169 +static int /* PRIVATE */
   1.170 +png_text_compress(png_structp png_ptr,
   1.171 +        png_charp text, png_size_t text_len, int compression,
   1.172 +        compression_state *comp)
   1.173 +{
   1.174 +   int ret;
   1.175 +
   1.176 +   comp->num_output_ptr = 0;
   1.177 +   comp->max_output_ptr = 0;
   1.178 +   comp->output_ptr = NULL;
   1.179 +   comp->input = NULL;
   1.180 +   comp->input_len = 0;
   1.181 +
   1.182 +   /* we may just want to pass the text right through */
   1.183 +   if (compression == PNG_TEXT_COMPRESSION_NONE)
   1.184 +   {
   1.185 +       comp->input = text;
   1.186 +       comp->input_len = text_len;
   1.187 +       return((int)text_len);
   1.188 +   }
   1.189 +
   1.190 +   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   1.191 +   {
   1.192 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
   1.193 +      char msg[50];
   1.194 +      png_snprintf(msg, 50, "Unknown compression type %d", compression);
   1.195 +      png_warning(png_ptr, msg);
   1.196 +#else
   1.197 +      png_warning(png_ptr, "Unknown compression type");
   1.198 +#endif
   1.199 +   }
   1.200 +
   1.201 +   /* We can't write the chunk until we find out how much data we have,
   1.202 +    * which means we need to run the compressor first and save the
   1.203 +    * output.  This shouldn't be a problem, as the vast majority of
   1.204 +    * comments should be reasonable, but we will set up an array of
   1.205 +    * malloc'd pointers to be sure.
   1.206 +    *
   1.207 +    * If we knew the application was well behaved, we could simplify this
   1.208 +    * greatly by assuming we can always malloc an output buffer large
   1.209 +    * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
   1.210 +    * and malloc this directly.  The only time this would be a bad idea is
   1.211 +    * if we can't malloc more than 64K and we have 64K of random input
   1.212 +    * data, or if the input string is incredibly large (although this
   1.213 +    * wouldn't cause a failure, just a slowdown due to swapping).
   1.214 +    */
   1.215 +
   1.216 +   /* set up the compression buffers */
   1.217 +   png_ptr->zstream.avail_in = (uInt)text_len;
   1.218 +   png_ptr->zstream.next_in = (Bytef *)text;
   1.219 +   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.220 +   png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
   1.221 +
   1.222 +   /* this is the same compression loop as in png_write_row() */
   1.223 +   do
   1.224 +   {
   1.225 +      /* compress the data */
   1.226 +      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
   1.227 +      if (ret != Z_OK)
   1.228 +      {
   1.229 +         /* error */
   1.230 +         if (png_ptr->zstream.msg != NULL)
   1.231 +            png_error(png_ptr, png_ptr->zstream.msg);
   1.232 +         else
   1.233 +            png_error(png_ptr, "zlib error");
   1.234 +      }
   1.235 +      /* check to see if we need more room */
   1.236 +      if (!(png_ptr->zstream.avail_out))
   1.237 +      {
   1.238 +         /* make sure the output array has room */
   1.239 +         if (comp->num_output_ptr >= comp->max_output_ptr)
   1.240 +         {
   1.241 +            int old_max;
   1.242 +
   1.243 +            old_max = comp->max_output_ptr;
   1.244 +            comp->max_output_ptr = comp->num_output_ptr + 4;
   1.245 +            if (comp->output_ptr != NULL)
   1.246 +            {
   1.247 +               png_charpp old_ptr;
   1.248 +
   1.249 +               old_ptr = comp->output_ptr;
   1.250 +               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
   1.251 +                  (png_uint_32)
   1.252 +                  (comp->max_output_ptr * png_sizeof(png_charpp)));
   1.253 +               png_memcpy(comp->output_ptr, old_ptr, old_max
   1.254 +                  * png_sizeof(png_charp));
   1.255 +               png_free(png_ptr, old_ptr);
   1.256 +            }
   1.257 +            else
   1.258 +               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
   1.259 +                  (png_uint_32)
   1.260 +                  (comp->max_output_ptr * png_sizeof(png_charp)));
   1.261 +         }
   1.262 +
   1.263 +         /* save the data */
   1.264 +         comp->output_ptr[comp->num_output_ptr] =
   1.265 +            (png_charp)png_malloc(png_ptr,
   1.266 +            (png_uint_32)png_ptr->zbuf_size);
   1.267 +         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
   1.268 +            png_ptr->zbuf_size);
   1.269 +         comp->num_output_ptr++;
   1.270 +
   1.271 +         /* and reset the buffer */
   1.272 +         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.273 +         png_ptr->zstream.next_out = png_ptr->zbuf;
   1.274 +      }
   1.275 +   /* continue until we don't have any more to compress */
   1.276 +   } while (png_ptr->zstream.avail_in);
   1.277 +
   1.278 +   /* finish the compression */
   1.279 +   do
   1.280 +   {
   1.281 +      /* tell zlib we are finished */
   1.282 +      ret = deflate(&png_ptr->zstream, Z_FINISH);
   1.283 +
   1.284 +      if (ret == Z_OK)
   1.285 +      {
   1.286 +         /* check to see if we need more room */
   1.287 +         if (!(png_ptr->zstream.avail_out))
   1.288 +         {
   1.289 +            /* check to make sure our output array has room */
   1.290 +            if (comp->num_output_ptr >= comp->max_output_ptr)
   1.291 +            {
   1.292 +               int old_max;
   1.293 +
   1.294 +               old_max = comp->max_output_ptr;
   1.295 +               comp->max_output_ptr = comp->num_output_ptr + 4;
   1.296 +               if (comp->output_ptr != NULL)
   1.297 +               {
   1.298 +                  png_charpp old_ptr;
   1.299 +
   1.300 +                  old_ptr = comp->output_ptr;
   1.301 +                  /* This could be optimized to realloc() */
   1.302 +                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
   1.303 +                     (png_uint_32)(comp->max_output_ptr *
   1.304 +                     png_sizeof(png_charp)));
   1.305 +                  png_memcpy(comp->output_ptr, old_ptr,
   1.306 +                     old_max * png_sizeof(png_charp));
   1.307 +                  png_free(png_ptr, old_ptr);
   1.308 +               }
   1.309 +               else
   1.310 +                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
   1.311 +                     (png_uint_32)(comp->max_output_ptr *
   1.312 +                     png_sizeof(png_charp)));
   1.313 +            }
   1.314 +
   1.315 +            /* save off the data */
   1.316 +            comp->output_ptr[comp->num_output_ptr] =
   1.317 +               (png_charp)png_malloc(png_ptr,
   1.318 +               (png_uint_32)png_ptr->zbuf_size);
   1.319 +            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
   1.320 +               png_ptr->zbuf_size);
   1.321 +            comp->num_output_ptr++;
   1.322 +
   1.323 +            /* and reset the buffer pointers */
   1.324 +            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.325 +            png_ptr->zstream.next_out = png_ptr->zbuf;
   1.326 +         }
   1.327 +      }
   1.328 +      else if (ret != Z_STREAM_END)
   1.329 +      {
   1.330 +         /* we got an error */
   1.331 +         if (png_ptr->zstream.msg != NULL)
   1.332 +            png_error(png_ptr, png_ptr->zstream.msg);
   1.333 +         else
   1.334 +            png_error(png_ptr, "zlib error");
   1.335 +      }
   1.336 +   } while (ret != Z_STREAM_END);
   1.337 +
   1.338 +   /* text length is number of buffers plus last buffer */
   1.339 +   text_len = png_ptr->zbuf_size * comp->num_output_ptr;
   1.340 +   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
   1.341 +      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
   1.342 +
   1.343 +   return((int)text_len);
   1.344 +}
   1.345 +
   1.346 +/* ship the compressed text out via chunk writes */
   1.347 +static void /* PRIVATE */
   1.348 +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
   1.349 +{
   1.350 +   int i;
   1.351 +
   1.352 +   /* handle the no-compression case */
   1.353 +   if (comp->input)
   1.354 +   {
   1.355 +       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
   1.356 +                            (png_size_t)comp->input_len);
   1.357 +       return;
   1.358 +   }
   1.359 +
   1.360 +   /* write saved output buffers, if any */
   1.361 +   for (i = 0; i < comp->num_output_ptr; i++)
   1.362 +   {
   1.363 +      png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i],
   1.364 +         (png_size_t)png_ptr->zbuf_size);
   1.365 +      png_free(png_ptr, comp->output_ptr[i]);
   1.366 +       comp->output_ptr[i]=NULL;
   1.367 +   }
   1.368 +   if (comp->max_output_ptr != 0)
   1.369 +      png_free(png_ptr, comp->output_ptr);
   1.370 +       comp->output_ptr=NULL;
   1.371 +   /* write anything left in zbuf */
   1.372 +   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
   1.373 +      png_write_chunk_data(png_ptr, png_ptr->zbuf,
   1.374 +         (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
   1.375 +
   1.376 +   /* reset zlib for another zTXt/iTXt or image data */
   1.377 +   deflateReset(&png_ptr->zstream);
   1.378 +   png_ptr->zstream.data_type = Z_BINARY;
   1.379 +}
   1.380 +#endif
   1.381 +
   1.382 +/* Write the IHDR chunk, and update the png_struct with the necessary
   1.383 + * information.  Note that the rest of this code depends upon this
   1.384 + * information being correct.
   1.385 + */
   1.386 +void /* PRIVATE */
   1.387 +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
   1.388 +   int bit_depth, int color_type, int compression_type, int filter_type,
   1.389 +   int interlace_type)
   1.390 +{
   1.391 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.392 +   PNG_IHDR;
   1.393 +#endif
   1.394 +   int ret;
   1.395 +
   1.396 +   png_byte buf[13]; /* buffer to store the IHDR info */
   1.397 +
   1.398 +   png_debug(1, "in png_write_IHDR\n");
   1.399 +   /* Check that we have valid input data from the application info */
   1.400 +   switch (color_type)
   1.401 +   {
   1.402 +      case PNG_COLOR_TYPE_GRAY:
   1.403 +         switch (bit_depth)
   1.404 +         {
   1.405 +            case 1:
   1.406 +            case 2:
   1.407 +            case 4:
   1.408 +            case 8:
   1.409 +            case 16: png_ptr->channels = 1; break;
   1.410 +            default: png_error(png_ptr, "Invalid bit depth for grayscale image");
   1.411 +         }
   1.412 +         break;
   1.413 +      case PNG_COLOR_TYPE_RGB:
   1.414 +         if (bit_depth != 8 && bit_depth != 16)
   1.415 +            png_error(png_ptr, "Invalid bit depth for RGB image");
   1.416 +         png_ptr->channels = 3;
   1.417 +         break;
   1.418 +      case PNG_COLOR_TYPE_PALETTE:
   1.419 +         switch (bit_depth)
   1.420 +         {
   1.421 +            case 1:
   1.422 +            case 2:
   1.423 +            case 4:
   1.424 +            case 8: png_ptr->channels = 1; break;
   1.425 +            default: png_error(png_ptr, "Invalid bit depth for paletted image");
   1.426 +         }
   1.427 +         break;
   1.428 +      case PNG_COLOR_TYPE_GRAY_ALPHA:
   1.429 +         if (bit_depth != 8 && bit_depth != 16)
   1.430 +            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
   1.431 +         png_ptr->channels = 2;
   1.432 +         break;
   1.433 +      case PNG_COLOR_TYPE_RGB_ALPHA:
   1.434 +         if (bit_depth != 8 && bit_depth != 16)
   1.435 +            png_error(png_ptr, "Invalid bit depth for RGBA image");
   1.436 +         png_ptr->channels = 4;
   1.437 +         break;
   1.438 +      default:
   1.439 +         png_error(png_ptr, "Invalid image color type specified");
   1.440 +   }
   1.441 +
   1.442 +   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
   1.443 +   {
   1.444 +      png_warning(png_ptr, "Invalid compression type specified");
   1.445 +      compression_type = PNG_COMPRESSION_TYPE_BASE;
   1.446 +   }
   1.447 +
   1.448 +   /* Write filter_method 64 (intrapixel differencing) only if
   1.449 +    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
   1.450 +    * 2. Libpng did not write a PNG signature (this filter_method is only
   1.451 +    *    used in PNG datastreams that are embedded in MNG datastreams) and
   1.452 +    * 3. The application called png_permit_mng_features with a mask that
   1.453 +    *    included PNG_FLAG_MNG_FILTER_64 and
   1.454 +    * 4. The filter_method is 64 and
   1.455 +    * 5. The color_type is RGB or RGBA
   1.456 +    */
   1.457 +   if (
   1.458 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
   1.459 +      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
   1.460 +      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
   1.461 +      (color_type == PNG_COLOR_TYPE_RGB ||
   1.462 +       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
   1.463 +      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
   1.464 +#endif
   1.465 +      filter_type != PNG_FILTER_TYPE_BASE)
   1.466 +   {
   1.467 +      png_warning(png_ptr, "Invalid filter type specified");
   1.468 +      filter_type = PNG_FILTER_TYPE_BASE;
   1.469 +   }
   1.470 +
   1.471 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED
   1.472 +   if (interlace_type != PNG_INTERLACE_NONE &&
   1.473 +      interlace_type != PNG_INTERLACE_ADAM7)
   1.474 +   {
   1.475 +      png_warning(png_ptr, "Invalid interlace type specified");
   1.476 +      interlace_type = PNG_INTERLACE_ADAM7;
   1.477 +   }
   1.478 +#else
   1.479 +   interlace_type=PNG_INTERLACE_NONE;
   1.480 +#endif
   1.481 +
   1.482 +   /* save off the relevent information */
   1.483 +   png_ptr->bit_depth = (png_byte)bit_depth;
   1.484 +   png_ptr->color_type = (png_byte)color_type;
   1.485 +   png_ptr->interlaced = (png_byte)interlace_type;
   1.486 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
   1.487 +   png_ptr->filter_type = (png_byte)filter_type;
   1.488 +#endif
   1.489 +   png_ptr->compression_type = (png_byte)compression_type;
   1.490 +   png_ptr->width = width;
   1.491 +   png_ptr->height = height;
   1.492 +
   1.493 +   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
   1.494 +   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
   1.495 +   /* set the usr info, so any transformations can modify it */
   1.496 +   png_ptr->usr_width = png_ptr->width;
   1.497 +   png_ptr->usr_bit_depth = png_ptr->bit_depth;
   1.498 +   png_ptr->usr_channels = png_ptr->channels;
   1.499 +
   1.500 +   /* pack the header information into the buffer */
   1.501 +   png_save_uint_32(buf, width);
   1.502 +   png_save_uint_32(buf + 4, height);
   1.503 +   buf[8] = (png_byte)bit_depth;
   1.504 +   buf[9] = (png_byte)color_type;
   1.505 +   buf[10] = (png_byte)compression_type;
   1.506 +   buf[11] = (png_byte)filter_type;
   1.507 +   buf[12] = (png_byte)interlace_type;
   1.508 +
   1.509 +   /* write the chunk */
   1.510 +   png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
   1.511 +
   1.512 +   /* initialize zlib with PNG info */
   1.513 +   png_ptr->zstream.zalloc = png_zalloc;
   1.514 +   png_ptr->zstream.zfree = png_zfree;
   1.515 +   png_ptr->zstream.opaque = (voidpf)png_ptr;
   1.516 +   if (!(png_ptr->do_filter))
   1.517 +   {
   1.518 +      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
   1.519 +         png_ptr->bit_depth < 8)
   1.520 +         png_ptr->do_filter = PNG_FILTER_NONE;
   1.521 +      else
   1.522 +         png_ptr->do_filter = PNG_ALL_FILTERS;
   1.523 +   }
   1.524 +   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
   1.525 +   {
   1.526 +      if (png_ptr->do_filter != PNG_FILTER_NONE)
   1.527 +         png_ptr->zlib_strategy = Z_FILTERED;
   1.528 +      else
   1.529 +         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   1.530 +   }
   1.531 +   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
   1.532 +      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
   1.533 +   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
   1.534 +      png_ptr->zlib_mem_level = 8;
   1.535 +   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
   1.536 +      png_ptr->zlib_window_bits = 15;
   1.537 +   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
   1.538 +      png_ptr->zlib_method = 8;
   1.539 +   ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
   1.540 +         png_ptr->zlib_method, png_ptr->zlib_window_bits,
   1.541 +         png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
   1.542 +   if (ret != Z_OK)
   1.543 +   {
   1.544 +      if (ret == Z_VERSION_ERROR) png_error(png_ptr,
   1.545 +          "zlib failed to initialize compressor -- version error");
   1.546 +      if (ret == Z_STREAM_ERROR) png_error(png_ptr,
   1.547 +           "zlib failed to initialize compressor -- stream error");
   1.548 +      if (ret == Z_MEM_ERROR) png_error(png_ptr,
   1.549 +           "zlib failed to initialize compressor -- mem error");
   1.550 +      png_error(png_ptr, "zlib failed to initialize compressor");
   1.551 +   }
   1.552 +   png_ptr->zstream.next_out = png_ptr->zbuf;
   1.553 +   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   1.554 +   /* libpng is not interested in zstream.data_type */
   1.555 +   /* set it to a predefined value, to avoid its evaluation inside zlib */
   1.556 +   png_ptr->zstream.data_type = Z_BINARY;
   1.557 +
   1.558 +   png_ptr->mode = PNG_HAVE_IHDR;
   1.559 +}
   1.560 +
   1.561 +/* write the palette.  We are careful not to trust png_color to be in the
   1.562 + * correct order for PNG, so people can redefine it to any convenient
   1.563 + * structure.
   1.564 + */
   1.565 +void /* PRIVATE */
   1.566 +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
   1.567 +{
   1.568 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.569 +   PNG_PLTE;
   1.570 +#endif
   1.571 +   png_uint_32 i;
   1.572 +   png_colorp pal_ptr;
   1.573 +   png_byte buf[3];
   1.574 +
   1.575 +   png_debug(1, "in png_write_PLTE\n");
   1.576 +   if ((
   1.577 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
   1.578 +        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
   1.579 +#endif
   1.580 +        num_pal == 0) || num_pal > 256)
   1.581 +   {
   1.582 +     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   1.583 +     {
   1.584 +        png_error(png_ptr, "Invalid number of colors in palette");
   1.585 +     }
   1.586 +     else
   1.587 +     {
   1.588 +        png_warning(png_ptr, "Invalid number of colors in palette");
   1.589 +        return;
   1.590 +     }
   1.591 +   }
   1.592 +
   1.593 +   if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
   1.594 +   {
   1.595 +      png_warning(png_ptr,
   1.596 +        "Ignoring request to write a PLTE chunk in grayscale PNG");
   1.597 +      return;
   1.598 +   }
   1.599 +
   1.600 +   png_ptr->num_palette = (png_uint_16)num_pal;
   1.601 +   png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
   1.602 +
   1.603 +   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE,
   1.604 +     (png_uint_32)(num_pal * 3));
   1.605 +#ifndef PNG_NO_POINTER_INDEXING
   1.606 +   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
   1.607 +   {
   1.608 +      buf[0] = pal_ptr->red;
   1.609 +      buf[1] = pal_ptr->green;
   1.610 +      buf[2] = pal_ptr->blue;
   1.611 +      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
   1.612 +   }
   1.613 +#else
   1.614 +   /* This is a little slower but some buggy compilers need to do this instead */
   1.615 +   pal_ptr=palette;
   1.616 +   for (i = 0; i < num_pal; i++)
   1.617 +   {
   1.618 +      buf[0] = pal_ptr[i].red;
   1.619 +      buf[1] = pal_ptr[i].green;
   1.620 +      buf[2] = pal_ptr[i].blue;
   1.621 +      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
   1.622 +   }
   1.623 +#endif
   1.624 +   png_write_chunk_end(png_ptr);
   1.625 +   png_ptr->mode |= PNG_HAVE_PLTE;
   1.626 +}
   1.627 +
   1.628 +/* write an IDAT chunk */
   1.629 +void /* PRIVATE */
   1.630 +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
   1.631 +{
   1.632 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.633 +   PNG_IDAT;
   1.634 +#endif
   1.635 +   png_debug(1, "in png_write_IDAT\n");
   1.636 +
   1.637 +   /* Optimize the CMF field in the zlib stream. */
   1.638 +   /* This hack of the zlib stream is compliant to the stream specification. */
   1.639 +   if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
   1.640 +       png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
   1.641 +   {
   1.642 +      unsigned int z_cmf = data[0];  /* zlib compression method and flags */
   1.643 +      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
   1.644 +      {
   1.645 +         /* Avoid memory underflows and multiplication overflows. */
   1.646 +         /* The conditions below are practically always satisfied;
   1.647 +            however, they still must be checked. */
   1.648 +         if (length >= 2 &&
   1.649 +             png_ptr->height < 16384 && png_ptr->width < 16384)
   1.650 +         {
   1.651 +            png_uint_32 uncompressed_idat_size = png_ptr->height *
   1.652 +               ((png_ptr->width *
   1.653 +               png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
   1.654 +            unsigned int z_cinfo = z_cmf >> 4;
   1.655 +            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
   1.656 +            while (uncompressed_idat_size <= half_z_window_size &&
   1.657 +                   half_z_window_size >= 256)
   1.658 +            {
   1.659 +               z_cinfo--;
   1.660 +               half_z_window_size >>= 1;
   1.661 +            }
   1.662 +            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
   1.663 +            if (data[0] != (png_byte)z_cmf)
   1.664 +            {
   1.665 +               data[0] = (png_byte)z_cmf;
   1.666 +               data[1] &= 0xe0;
   1.667 +               data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
   1.668 +            }
   1.669 +         }
   1.670 +      }
   1.671 +      else
   1.672 +         png_error(png_ptr,
   1.673 +            "Invalid zlib compression method or flags in IDAT");
   1.674 +   }
   1.675 +
   1.676 +   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
   1.677 +   png_ptr->mode |= PNG_HAVE_IDAT;
   1.678 +}
   1.679 +
   1.680 +/* write an IEND chunk */
   1.681 +void /* PRIVATE */
   1.682 +png_write_IEND(png_structp png_ptr)
   1.683 +{
   1.684 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.685 +   PNG_IEND;
   1.686 +#endif
   1.687 +   png_debug(1, "in png_write_IEND\n");
   1.688 +   png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
   1.689 +     (png_size_t)0);
   1.690 +   png_ptr->mode |= PNG_HAVE_IEND;
   1.691 +}
   1.692 +
   1.693 +#if defined(PNG_WRITE_gAMA_SUPPORTED)
   1.694 +/* write a gAMA chunk */
   1.695 +#ifdef PNG_FLOATING_POINT_SUPPORTED
   1.696 +void /* PRIVATE */
   1.697 +png_write_gAMA(png_structp png_ptr, double file_gamma)
   1.698 +{
   1.699 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.700 +   PNG_gAMA;
   1.701 +#endif
   1.702 +   png_uint_32 igamma;
   1.703 +   png_byte buf[4];
   1.704 +
   1.705 +   png_debug(1, "in png_write_gAMA\n");
   1.706 +   /* file_gamma is saved in 1/100,000ths */
   1.707 +   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
   1.708 +   png_save_uint_32(buf, igamma);
   1.709 +   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
   1.710 +}
   1.711 +#endif
   1.712 +#ifdef PNG_FIXED_POINT_SUPPORTED
   1.713 +void /* PRIVATE */
   1.714 +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
   1.715 +{
   1.716 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.717 +   PNG_gAMA;
   1.718 +#endif
   1.719 +   png_byte buf[4];
   1.720 +
   1.721 +   png_debug(1, "in png_write_gAMA\n");
   1.722 +   /* file_gamma is saved in 1/100,000ths */
   1.723 +   png_save_uint_32(buf, (png_uint_32)file_gamma);
   1.724 +   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
   1.725 +}
   1.726 +#endif
   1.727 +#endif
   1.728 +
   1.729 +#if defined(PNG_WRITE_sRGB_SUPPORTED)
   1.730 +/* write a sRGB chunk */
   1.731 +void /* PRIVATE */
   1.732 +png_write_sRGB(png_structp png_ptr, int srgb_intent)
   1.733 +{
   1.734 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.735 +   PNG_sRGB;
   1.736 +#endif
   1.737 +   png_byte buf[1];
   1.738 +
   1.739 +   png_debug(1, "in png_write_sRGB\n");
   1.740 +   if (srgb_intent >= PNG_sRGB_INTENT_LAST)
   1.741 +         png_warning(png_ptr,
   1.742 +            "Invalid sRGB rendering intent specified");
   1.743 +   buf[0]=(png_byte)srgb_intent;
   1.744 +   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
   1.745 +}
   1.746 +#endif
   1.747 +
   1.748 +#if defined(PNG_WRITE_iCCP_SUPPORTED)
   1.749 +/* write an iCCP chunk */
   1.750 +void /* PRIVATE */
   1.751 +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
   1.752 +   png_charp profile, int profile_len)
   1.753 +{
   1.754 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.755 +   PNG_iCCP;
   1.756 +#endif
   1.757 +   png_size_t name_len;
   1.758 +   png_charp new_name;
   1.759 +   compression_state comp;
   1.760 +   int embedded_profile_len = 0;
   1.761 +
   1.762 +   png_debug(1, "in png_write_iCCP\n");
   1.763 +
   1.764 +   comp.num_output_ptr = 0;
   1.765 +   comp.max_output_ptr = 0;
   1.766 +   comp.output_ptr = NULL;
   1.767 +   comp.input = NULL;
   1.768 +   comp.input_len = 0;
   1.769 +
   1.770 +   if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
   1.771 +      &new_name)) == 0)
   1.772 +   {
   1.773 +      png_warning(png_ptr, "Empty keyword in iCCP chunk");
   1.774 +      return;
   1.775 +   }
   1.776 +
   1.777 +   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
   1.778 +      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
   1.779 +
   1.780 +   if (profile == NULL)
   1.781 +      profile_len = 0;
   1.782 +
   1.783 +   if (profile_len > 3)
   1.784 +      embedded_profile_len =
   1.785 +          ((*( (png_bytep)profile    ))<<24) |
   1.786 +          ((*( (png_bytep)profile + 1))<<16) |
   1.787 +          ((*( (png_bytep)profile + 2))<< 8) |
   1.788 +          ((*( (png_bytep)profile + 3))    );
   1.789 +
   1.790 +   if (profile_len < embedded_profile_len)
   1.791 +   {
   1.792 +      png_warning(png_ptr,
   1.793 +        "Embedded profile length too large in iCCP chunk");
   1.794 +      return;
   1.795 +   }
   1.796 +
   1.797 +   if (profile_len > embedded_profile_len)
   1.798 +   {
   1.799 +      png_warning(png_ptr,
   1.800 +        "Truncating profile to actual length in iCCP chunk");
   1.801 +      profile_len = embedded_profile_len;
   1.802 +   }
   1.803 +
   1.804 +   if (profile_len)
   1.805 +      profile_len = png_text_compress(png_ptr, profile,
   1.806 +        (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
   1.807 +
   1.808 +   /* make sure we include the NULL after the name and the compression type */
   1.809 +   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
   1.810 +          (png_uint_32)(name_len + profile_len + 2));
   1.811 +   new_name[name_len + 1] = 0x00;
   1.812 +   png_write_chunk_data(png_ptr, (png_bytep)new_name,
   1.813 +     (png_size_t)(name_len + 2));
   1.814 +
   1.815 +   if (profile_len)
   1.816 +      png_write_compressed_data_out(png_ptr, &comp);
   1.817 +
   1.818 +   png_write_chunk_end(png_ptr);
   1.819 +   png_free(png_ptr, new_name);
   1.820 +}
   1.821 +#endif
   1.822 +
   1.823 +#if defined(PNG_WRITE_sPLT_SUPPORTED)
   1.824 +/* write a sPLT chunk */
   1.825 +void /* PRIVATE */
   1.826 +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
   1.827 +{
   1.828 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.829 +   PNG_sPLT;
   1.830 +#endif
   1.831 +   png_size_t name_len;
   1.832 +   png_charp new_name;
   1.833 +   png_byte entrybuf[10];
   1.834 +   int entry_size = (spalette->depth == 8 ? 6 : 10);
   1.835 +   int palette_size = entry_size * spalette->nentries;
   1.836 +   png_sPLT_entryp ep;
   1.837 +#ifdef PNG_NO_POINTER_INDEXING
   1.838 +   int i;
   1.839 +#endif
   1.840 +
   1.841 +   png_debug(1, "in png_write_sPLT\n");
   1.842 +   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
   1.843 +      spalette->name, &new_name))==0)
   1.844 +   {
   1.845 +      png_warning(png_ptr, "Empty keyword in sPLT chunk");
   1.846 +      return;
   1.847 +   }
   1.848 +
   1.849 +   /* make sure we include the NULL after the name */
   1.850 +   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
   1.851 +     (png_uint_32)(name_len + 2 + palette_size));
   1.852 +   png_write_chunk_data(png_ptr, (png_bytep)new_name,
   1.853 +     (png_size_t)(name_len + 1));
   1.854 +   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1);
   1.855 +
   1.856 +   /* loop through each palette entry, writing appropriately */
   1.857 +#ifndef PNG_NO_POINTER_INDEXING
   1.858 +   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
   1.859 +   {
   1.860 +      if (spalette->depth == 8)
   1.861 +      {
   1.862 +          entrybuf[0] = (png_byte)ep->red;
   1.863 +          entrybuf[1] = (png_byte)ep->green;
   1.864 +          entrybuf[2] = (png_byte)ep->blue;
   1.865 +          entrybuf[3] = (png_byte)ep->alpha;
   1.866 +          png_save_uint_16(entrybuf + 4, ep->frequency);
   1.867 +      }
   1.868 +      else
   1.869 +      {
   1.870 +          png_save_uint_16(entrybuf + 0, ep->red);
   1.871 +          png_save_uint_16(entrybuf + 2, ep->green);
   1.872 +          png_save_uint_16(entrybuf + 4, ep->blue);
   1.873 +          png_save_uint_16(entrybuf + 6, ep->alpha);
   1.874 +          png_save_uint_16(entrybuf + 8, ep->frequency);
   1.875 +      }
   1.876 +      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
   1.877 +   }
   1.878 +#else
   1.879 +   ep=spalette->entries;
   1.880 +   for (i=0; i>spalette->nentries; i++)
   1.881 +   {
   1.882 +      if (spalette->depth == 8)
   1.883 +      {
   1.884 +          entrybuf[0] = (png_byte)ep[i].red;
   1.885 +          entrybuf[1] = (png_byte)ep[i].green;
   1.886 +          entrybuf[2] = (png_byte)ep[i].blue;
   1.887 +          entrybuf[3] = (png_byte)ep[i].alpha;
   1.888 +          png_save_uint_16(entrybuf + 4, ep[i].frequency);
   1.889 +      }
   1.890 +      else
   1.891 +      {
   1.892 +          png_save_uint_16(entrybuf + 0, ep[i].red);
   1.893 +          png_save_uint_16(entrybuf + 2, ep[i].green);
   1.894 +          png_save_uint_16(entrybuf + 4, ep[i].blue);
   1.895 +          png_save_uint_16(entrybuf + 6, ep[i].alpha);
   1.896 +          png_save_uint_16(entrybuf + 8, ep[i].frequency);
   1.897 +      }
   1.898 +      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
   1.899 +   }
   1.900 +#endif
   1.901 +
   1.902 +   png_write_chunk_end(png_ptr);
   1.903 +   png_free(png_ptr, new_name);
   1.904 +}
   1.905 +#endif
   1.906 +
   1.907 +#if defined(PNG_WRITE_sBIT_SUPPORTED)
   1.908 +/* write the sBIT chunk */
   1.909 +void /* PRIVATE */
   1.910 +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
   1.911 +{
   1.912 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.913 +   PNG_sBIT;
   1.914 +#endif
   1.915 +   png_byte buf[4];
   1.916 +   png_size_t size;
   1.917 +
   1.918 +   png_debug(1, "in png_write_sBIT\n");
   1.919 +   /* make sure we don't depend upon the order of PNG_COLOR_8 */
   1.920 +   if (color_type & PNG_COLOR_MASK_COLOR)
   1.921 +   {
   1.922 +      png_byte maxbits;
   1.923 +
   1.924 +      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
   1.925 +                png_ptr->usr_bit_depth);
   1.926 +      if (sbit->red == 0 || sbit->red > maxbits ||
   1.927 +          sbit->green == 0 || sbit->green > maxbits ||
   1.928 +          sbit->blue == 0 || sbit->blue > maxbits)
   1.929 +      {
   1.930 +         png_warning(png_ptr, "Invalid sBIT depth specified");
   1.931 +         return;
   1.932 +      }
   1.933 +      buf[0] = sbit->red;
   1.934 +      buf[1] = sbit->green;
   1.935 +      buf[2] = sbit->blue;
   1.936 +      size = 3;
   1.937 +   }
   1.938 +   else
   1.939 +   {
   1.940 +      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
   1.941 +      {
   1.942 +         png_warning(png_ptr, "Invalid sBIT depth specified");
   1.943 +         return;
   1.944 +      }
   1.945 +      buf[0] = sbit->gray;
   1.946 +      size = 1;
   1.947 +   }
   1.948 +
   1.949 +   if (color_type & PNG_COLOR_MASK_ALPHA)
   1.950 +   {
   1.951 +      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
   1.952 +      {
   1.953 +         png_warning(png_ptr, "Invalid sBIT depth specified");
   1.954 +         return;
   1.955 +      }
   1.956 +      buf[size++] = sbit->alpha;
   1.957 +   }
   1.958 +
   1.959 +   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
   1.960 +}
   1.961 +#endif
   1.962 +
   1.963 +#if defined(PNG_WRITE_cHRM_SUPPORTED)
   1.964 +/* write the cHRM chunk */
   1.965 +#ifdef PNG_FLOATING_POINT_SUPPORTED
   1.966 +void /* PRIVATE */
   1.967 +png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
   1.968 +   double red_x, double red_y, double green_x, double green_y,
   1.969 +   double blue_x, double blue_y)
   1.970 +{
   1.971 +#ifdef PNG_USE_LOCAL_ARRAYS
   1.972 +   PNG_cHRM;
   1.973 +#endif
   1.974 +   png_byte buf[32];
   1.975 +   png_uint_32 itemp;
   1.976 +
   1.977 +   png_debug(1, "in png_write_cHRM\n");
   1.978 +   /* each value is saved in 1/100,000ths */
   1.979 +   if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
   1.980 +       white_x + white_y > 1.0)
   1.981 +   {
   1.982 +      png_warning(png_ptr, "Invalid cHRM white point specified");
   1.983 +#if !defined(PNG_NO_CONSOLE_IO)
   1.984 +      fprintf(stderr, "white_x=%f, white_y=%f\n", white_x, white_y);
   1.985 +#endif
   1.986 +      return;
   1.987 +   }
   1.988 +   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
   1.989 +   png_save_uint_32(buf, itemp);
   1.990 +   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
   1.991 +   png_save_uint_32(buf + 4, itemp);
   1.992 +
   1.993 +   if (red_x < 0 ||  red_y < 0 || red_x + red_y > 1.0)
   1.994 +   {
   1.995 +      png_warning(png_ptr, "Invalid cHRM red point specified");
   1.996 +      return;
   1.997 +   }
   1.998 +   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
   1.999 +   png_save_uint_32(buf + 8, itemp);
  1.1000 +   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
  1.1001 +   png_save_uint_32(buf + 12, itemp);
  1.1002 +
  1.1003 +   if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
  1.1004 +   {
  1.1005 +      png_warning(png_ptr, "Invalid cHRM green point specified");
  1.1006 +      return;
  1.1007 +   }
  1.1008 +   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
  1.1009 +   png_save_uint_32(buf + 16, itemp);
  1.1010 +   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
  1.1011 +   png_save_uint_32(buf + 20, itemp);
  1.1012 +
  1.1013 +   if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
  1.1014 +   {
  1.1015 +      png_warning(png_ptr, "Invalid cHRM blue point specified");
  1.1016 +      return;
  1.1017 +   }
  1.1018 +   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
  1.1019 +   png_save_uint_32(buf + 24, itemp);
  1.1020 +   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
  1.1021 +   png_save_uint_32(buf + 28, itemp);
  1.1022 +
  1.1023 +   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
  1.1024 +}
  1.1025 +#endif
  1.1026 +#ifdef PNG_FIXED_POINT_SUPPORTED
  1.1027 +void /* PRIVATE */
  1.1028 +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
  1.1029 +   png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
  1.1030 +   png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
  1.1031 +   png_fixed_point blue_y)
  1.1032 +{
  1.1033 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1034 +   PNG_cHRM;
  1.1035 +#endif
  1.1036 +   png_byte buf[32];
  1.1037 +
  1.1038 +   png_debug(1, "in png_write_cHRM\n");
  1.1039 +   /* each value is saved in 1/100,000ths */
  1.1040 +   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
  1.1041 +   {
  1.1042 +      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
  1.1043 +#if !defined(PNG_NO_CONSOLE_IO)
  1.1044 +      fprintf(stderr, "white_x=%ld, white_y=%ld\n", (unsigned long)white_x,
  1.1045 +        (unsigned long)white_y);
  1.1046 +#endif
  1.1047 +      return;
  1.1048 +   }
  1.1049 +   png_save_uint_32(buf, (png_uint_32)white_x);
  1.1050 +   png_save_uint_32(buf + 4, (png_uint_32)white_y);
  1.1051 +
  1.1052 +   if (red_x + red_y > 100000L)
  1.1053 +   {
  1.1054 +      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
  1.1055 +      return;
  1.1056 +   }
  1.1057 +   png_save_uint_32(buf + 8, (png_uint_32)red_x);
  1.1058 +   png_save_uint_32(buf + 12, (png_uint_32)red_y);
  1.1059 +
  1.1060 +   if (green_x + green_y > 100000L)
  1.1061 +   {
  1.1062 +      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
  1.1063 +      return;
  1.1064 +   }
  1.1065 +   png_save_uint_32(buf + 16, (png_uint_32)green_x);
  1.1066 +   png_save_uint_32(buf + 20, (png_uint_32)green_y);
  1.1067 +
  1.1068 +   if (blue_x + blue_y > 100000L)
  1.1069 +   {
  1.1070 +      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
  1.1071 +      return;
  1.1072 +   }
  1.1073 +   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
  1.1074 +   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
  1.1075 +
  1.1076 +   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
  1.1077 +}
  1.1078 +#endif
  1.1079 +#endif
  1.1080 +
  1.1081 +#if defined(PNG_WRITE_tRNS_SUPPORTED)
  1.1082 +/* write the tRNS chunk */
  1.1083 +void /* PRIVATE */
  1.1084 +png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
  1.1085 +   int num_trans, int color_type)
  1.1086 +{
  1.1087 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1088 +   PNG_tRNS;
  1.1089 +#endif
  1.1090 +   png_byte buf[6];
  1.1091 +
  1.1092 +   png_debug(1, "in png_write_tRNS\n");
  1.1093 +   if (color_type == PNG_COLOR_TYPE_PALETTE)
  1.1094 +   {
  1.1095 +      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
  1.1096 +      {
  1.1097 +         png_warning(png_ptr, "Invalid number of transparent colors specified");
  1.1098 +         return;
  1.1099 +      }
  1.1100 +      /* write the chunk out as it is */
  1.1101 +      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans,
  1.1102 +        (png_size_t)num_trans);
  1.1103 +   }
  1.1104 +   else if (color_type == PNG_COLOR_TYPE_GRAY)
  1.1105 +   {
  1.1106 +      /* one 16 bit value */
  1.1107 +      if (tran->gray >= (1 << png_ptr->bit_depth))
  1.1108 +      {
  1.1109 +         png_warning(png_ptr,
  1.1110 +           "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
  1.1111 +         return;
  1.1112 +      }
  1.1113 +      png_save_uint_16(buf, tran->gray);
  1.1114 +      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
  1.1115 +   }
  1.1116 +   else if (color_type == PNG_COLOR_TYPE_RGB)
  1.1117 +   {
  1.1118 +      /* three 16 bit values */
  1.1119 +      png_save_uint_16(buf, tran->red);
  1.1120 +      png_save_uint_16(buf + 2, tran->green);
  1.1121 +      png_save_uint_16(buf + 4, tran->blue);
  1.1122 +      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
  1.1123 +      {
  1.1124 +         png_warning(png_ptr,
  1.1125 +           "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
  1.1126 +         return;
  1.1127 +      }
  1.1128 +      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
  1.1129 +   }
  1.1130 +   else
  1.1131 +   {
  1.1132 +      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
  1.1133 +   }
  1.1134 +}
  1.1135 +#endif
  1.1136 +
  1.1137 +#if defined(PNG_WRITE_bKGD_SUPPORTED)
  1.1138 +/* write the background chunk */
  1.1139 +void /* PRIVATE */
  1.1140 +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
  1.1141 +{
  1.1142 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1143 +   PNG_bKGD;
  1.1144 +#endif
  1.1145 +   png_byte buf[6];
  1.1146 +
  1.1147 +   png_debug(1, "in png_write_bKGD\n");
  1.1148 +   if (color_type == PNG_COLOR_TYPE_PALETTE)
  1.1149 +   {
  1.1150 +      if (
  1.1151 +#if defined(PNG_MNG_FEATURES_SUPPORTED)
  1.1152 +          (png_ptr->num_palette ||
  1.1153 +          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
  1.1154 +#endif
  1.1155 +         back->index > png_ptr->num_palette)
  1.1156 +      {
  1.1157 +         png_warning(png_ptr, "Invalid background palette index");
  1.1158 +         return;
  1.1159 +      }
  1.1160 +      buf[0] = back->index;
  1.1161 +      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
  1.1162 +   }
  1.1163 +   else if (color_type & PNG_COLOR_MASK_COLOR)
  1.1164 +   {
  1.1165 +      png_save_uint_16(buf, back->red);
  1.1166 +      png_save_uint_16(buf + 2, back->green);
  1.1167 +      png_save_uint_16(buf + 4, back->blue);
  1.1168 +      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
  1.1169 +      {
  1.1170 +         png_warning(png_ptr,
  1.1171 +           "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
  1.1172 +         return;
  1.1173 +      }
  1.1174 +      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
  1.1175 +   }
  1.1176 +   else
  1.1177 +   {
  1.1178 +      if (back->gray >= (1 << png_ptr->bit_depth))
  1.1179 +      {
  1.1180 +         png_warning(png_ptr,
  1.1181 +           "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
  1.1182 +         return;
  1.1183 +      }
  1.1184 +      png_save_uint_16(buf, back->gray);
  1.1185 +      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
  1.1186 +   }
  1.1187 +}
  1.1188 +#endif
  1.1189 +
  1.1190 +#if defined(PNG_WRITE_hIST_SUPPORTED)
  1.1191 +/* write the histogram */
  1.1192 +void /* PRIVATE */
  1.1193 +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
  1.1194 +{
  1.1195 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1196 +   PNG_hIST;
  1.1197 +#endif
  1.1198 +   int i;
  1.1199 +   png_byte buf[3];
  1.1200 +
  1.1201 +   png_debug(1, "in png_write_hIST\n");
  1.1202 +   if (num_hist > (int)png_ptr->num_palette)
  1.1203 +   {
  1.1204 +      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
  1.1205 +         png_ptr->num_palette);
  1.1206 +      png_warning(png_ptr, "Invalid number of histogram entries specified");
  1.1207 +      return;
  1.1208 +   }
  1.1209 +
  1.1210 +   png_write_chunk_start(png_ptr, (png_bytep)png_hIST,
  1.1211 +     (png_uint_32)(num_hist * 2));
  1.1212 +   for (i = 0; i < num_hist; i++)
  1.1213 +   {
  1.1214 +      png_save_uint_16(buf, hist[i]);
  1.1215 +      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
  1.1216 +   }
  1.1217 +   png_write_chunk_end(png_ptr);
  1.1218 +}
  1.1219 +#endif
  1.1220 +
  1.1221 +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
  1.1222 +    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
  1.1223 +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
  1.1224 + * and if invalid, correct the keyword rather than discarding the entire
  1.1225 + * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
  1.1226 + * length, forbids leading or trailing whitespace, multiple internal spaces,
  1.1227 + * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
  1.1228 + *
  1.1229 + * The new_key is allocated to hold the corrected keyword and must be freed
  1.1230 + * by the calling routine.  This avoids problems with trying to write to
  1.1231 + * static keywords without having to have duplicate copies of the strings.
  1.1232 + */
  1.1233 +png_size_t /* PRIVATE */
  1.1234 +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
  1.1235 +{
  1.1236 +   png_size_t key_len;
  1.1237 +   png_charp kp, dp;
  1.1238 +   int kflag;
  1.1239 +   int kwarn=0;
  1.1240 +
  1.1241 +   png_debug(1, "in png_check_keyword\n");
  1.1242 +   *new_key = NULL;
  1.1243 +
  1.1244 +   if (key == NULL || (key_len = png_strlen(key)) == 0)
  1.1245 +   {
  1.1246 +      png_warning(png_ptr, "zero length keyword");
  1.1247 +      return ((png_size_t)0);
  1.1248 +   }
  1.1249 +
  1.1250 +   png_debug1(2, "Keyword to be checked is '%s'\n", key);
  1.1251 +
  1.1252 +   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
  1.1253 +   if (*new_key == NULL)
  1.1254 +   {
  1.1255 +      png_warning(png_ptr, "Out of memory while procesing keyword");
  1.1256 +      return ((png_size_t)0);
  1.1257 +   }
  1.1258 +
  1.1259 +   /* Replace non-printing characters with a blank and print a warning */
  1.1260 +   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
  1.1261 +   {
  1.1262 +      if ((png_byte)*kp < 0x20 ||
  1.1263 +         ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
  1.1264 +      {
  1.1265 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
  1.1266 +         char msg[40];
  1.1267 +
  1.1268 +         png_snprintf(msg, 40,
  1.1269 +           "invalid keyword character 0x%02X", (png_byte)*kp);
  1.1270 +         png_warning(png_ptr, msg);
  1.1271 +#else
  1.1272 +         png_warning(png_ptr, "invalid character in keyword");
  1.1273 +#endif
  1.1274 +         *dp = ' ';
  1.1275 +      }
  1.1276 +      else
  1.1277 +      {
  1.1278 +         *dp = *kp;
  1.1279 +      }
  1.1280 +   }
  1.1281 +   *dp = '\0';
  1.1282 +
  1.1283 +   /* Remove any trailing white space. */
  1.1284 +   kp = *new_key + key_len - 1;
  1.1285 +   if (*kp == ' ')
  1.1286 +   {
  1.1287 +      png_warning(png_ptr, "trailing spaces removed from keyword");
  1.1288 +
  1.1289 +      while (*kp == ' ')
  1.1290 +      {
  1.1291 +        *(kp--) = '\0';
  1.1292 +        key_len--;
  1.1293 +      }
  1.1294 +   }
  1.1295 +
  1.1296 +   /* Remove any leading white space. */
  1.1297 +   kp = *new_key;
  1.1298 +   if (*kp == ' ')
  1.1299 +   {
  1.1300 +      png_warning(png_ptr, "leading spaces removed from keyword");
  1.1301 +
  1.1302 +      while (*kp == ' ')
  1.1303 +      {
  1.1304 +        kp++;
  1.1305 +        key_len--;
  1.1306 +      }
  1.1307 +   }
  1.1308 +
  1.1309 +   png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
  1.1310 +
  1.1311 +   /* Remove multiple internal spaces. */
  1.1312 +   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
  1.1313 +   {
  1.1314 +      if (*kp == ' ' && kflag == 0)
  1.1315 +      {
  1.1316 +         *(dp++) = *kp;
  1.1317 +         kflag = 1;
  1.1318 +      }
  1.1319 +      else if (*kp == ' ')
  1.1320 +      {
  1.1321 +         key_len--;
  1.1322 +         kwarn=1;
  1.1323 +      }
  1.1324 +      else
  1.1325 +      {
  1.1326 +         *(dp++) = *kp;
  1.1327 +         kflag = 0;
  1.1328 +      }
  1.1329 +   }
  1.1330 +   *dp = '\0';
  1.1331 +   if (kwarn)
  1.1332 +      png_warning(png_ptr, "extra interior spaces removed from keyword");
  1.1333 +
  1.1334 +   if (key_len == 0)
  1.1335 +   {
  1.1336 +      png_free(png_ptr, *new_key);
  1.1337 +       *new_key=NULL;
  1.1338 +      png_warning(png_ptr, "Zero length keyword");
  1.1339 +   }
  1.1340 +
  1.1341 +   if (key_len > 79)
  1.1342 +   {
  1.1343 +      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
  1.1344 +      new_key[79] = '\0';
  1.1345 +      key_len = 79;
  1.1346 +   }
  1.1347 +
  1.1348 +   return (key_len);
  1.1349 +}
  1.1350 +#endif
  1.1351 +
  1.1352 +#if defined(PNG_WRITE_tEXt_SUPPORTED)
  1.1353 +/* write a tEXt chunk */
  1.1354 +void /* PRIVATE */
  1.1355 +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
  1.1356 +   png_size_t text_len)
  1.1357 +{
  1.1358 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1359 +   PNG_tEXt;
  1.1360 +#endif
  1.1361 +   png_size_t key_len;
  1.1362 +   png_charp new_key;
  1.1363 +
  1.1364 +   png_debug(1, "in png_write_tEXt\n");
  1.1365 +   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
  1.1366 +   {
  1.1367 +      png_warning(png_ptr, "Empty keyword in tEXt chunk");
  1.1368 +      return;
  1.1369 +   }
  1.1370 +
  1.1371 +   if (text == NULL || *text == '\0')
  1.1372 +      text_len = 0;
  1.1373 +   else
  1.1374 +      text_len = png_strlen(text);
  1.1375 +
  1.1376 +   /* make sure we include the 0 after the key */
  1.1377 +   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt,
  1.1378 +      (png_uint_32)(key_len + text_len + 1));
  1.1379 +   /*
  1.1380 +    * We leave it to the application to meet PNG-1.0 requirements on the
  1.1381 +    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
  1.1382 +    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
  1.1383 +    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
  1.1384 +    */
  1.1385 +   png_write_chunk_data(png_ptr, (png_bytep)new_key,
  1.1386 +     (png_size_t)(key_len + 1));
  1.1387 +   if (text_len)
  1.1388 +      png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len);
  1.1389 +
  1.1390 +   png_write_chunk_end(png_ptr);
  1.1391 +   png_free(png_ptr, new_key);
  1.1392 +}
  1.1393 +#endif
  1.1394 +
  1.1395 +#if defined(PNG_WRITE_zTXt_SUPPORTED)
  1.1396 +/* write a compressed text chunk */
  1.1397 +void /* PRIVATE */
  1.1398 +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
  1.1399 +   png_size_t text_len, int compression)
  1.1400 +{
  1.1401 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1402 +   PNG_zTXt;
  1.1403 +#endif
  1.1404 +   png_size_t key_len;
  1.1405 +   char buf[1];
  1.1406 +   png_charp new_key;
  1.1407 +   compression_state comp;
  1.1408 +
  1.1409 +   png_debug(1, "in png_write_zTXt\n");
  1.1410 +
  1.1411 +   comp.num_output_ptr = 0;
  1.1412 +   comp.max_output_ptr = 0;
  1.1413 +   comp.output_ptr = NULL;
  1.1414 +   comp.input = NULL;
  1.1415 +   comp.input_len = 0;
  1.1416 +
  1.1417 +   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
  1.1418 +   {
  1.1419 +      png_warning(png_ptr, "Empty keyword in zTXt chunk");
  1.1420 +      png_free(png_ptr, new_key);
  1.1421 +      return;
  1.1422 +   }
  1.1423 +
  1.1424 +   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
  1.1425 +   {
  1.1426 +      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
  1.1427 +      png_free(png_ptr, new_key);
  1.1428 +      return;
  1.1429 +   }
  1.1430 +
  1.1431 +   text_len = png_strlen(text);
  1.1432 +
  1.1433 +   /* compute the compressed data; do it now for the length */
  1.1434 +   text_len = png_text_compress(png_ptr, text, text_len, compression,
  1.1435 +       &comp);
  1.1436 +
  1.1437 +   /* write start of chunk */
  1.1438 +   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt,
  1.1439 +     (png_uint_32)(key_len+text_len + 2));
  1.1440 +   /* write key */
  1.1441 +   png_write_chunk_data(png_ptr, (png_bytep)new_key,
  1.1442 +     (png_size_t)(key_len + 1));
  1.1443 +   png_free(png_ptr, new_key);
  1.1444 +
  1.1445 +   buf[0] = (png_byte)compression;
  1.1446 +   /* write compression */
  1.1447 +   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
  1.1448 +   /* write the compressed data */
  1.1449 +   png_write_compressed_data_out(png_ptr, &comp);
  1.1450 +
  1.1451 +   /* close the chunk */
  1.1452 +   png_write_chunk_end(png_ptr);
  1.1453 +}
  1.1454 +#endif
  1.1455 +
  1.1456 +#if defined(PNG_WRITE_iTXt_SUPPORTED)
  1.1457 +/* write an iTXt chunk */
  1.1458 +void /* PRIVATE */
  1.1459 +png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
  1.1460 +    png_charp lang, png_charp lang_key, png_charp text)
  1.1461 +{
  1.1462 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1463 +   PNG_iTXt;
  1.1464 +#endif
  1.1465 +   png_size_t lang_len, key_len, lang_key_len, text_len;
  1.1466 +   png_charp new_lang, new_key;
  1.1467 +   png_byte cbuf[2];
  1.1468 +   compression_state comp;
  1.1469 +
  1.1470 +   png_debug(1, "in png_write_iTXt\n");
  1.1471 +
  1.1472 +   comp.num_output_ptr = 0;
  1.1473 +   comp.max_output_ptr = 0;
  1.1474 +   comp.output_ptr = NULL;
  1.1475 +   comp.input = NULL;
  1.1476 +
  1.1477 +   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
  1.1478 +   {
  1.1479 +      png_warning(png_ptr, "Empty keyword in iTXt chunk");
  1.1480 +      return;
  1.1481 +   }
  1.1482 +   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
  1.1483 +   {
  1.1484 +      png_warning(png_ptr, "Empty language field in iTXt chunk");
  1.1485 +      new_lang = NULL;
  1.1486 +      lang_len = 0;
  1.1487 +   }
  1.1488 +
  1.1489 +   if (lang_key == NULL)
  1.1490 +     lang_key_len = 0;
  1.1491 +   else
  1.1492 +     lang_key_len = png_strlen(lang_key);
  1.1493 +
  1.1494 +   if (text == NULL)
  1.1495 +      text_len = 0;
  1.1496 +   else
  1.1497 +     text_len = png_strlen(text);
  1.1498 +
  1.1499 +   /* compute the compressed data; do it now for the length */
  1.1500 +   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
  1.1501 +      &comp);
  1.1502 +
  1.1503 +
  1.1504 +   /* make sure we include the compression flag, the compression byte,
  1.1505 +    * and the NULs after the key, lang, and lang_key parts */
  1.1506 +
  1.1507 +   png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
  1.1508 +          (png_uint_32)(
  1.1509 +        5 /* comp byte, comp flag, terminators for key, lang and lang_key */
  1.1510 +        + key_len
  1.1511 +        + lang_len
  1.1512 +        + lang_key_len
  1.1513 +        + text_len));
  1.1514 +
  1.1515 +   /*
  1.1516 +    * We leave it to the application to meet PNG-1.0 requirements on the
  1.1517 +    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
  1.1518 +    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
  1.1519 +    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
  1.1520 +    */
  1.1521 +   png_write_chunk_data(png_ptr, (png_bytep)new_key,
  1.1522 +     (png_size_t)(key_len + 1));
  1.1523 +
  1.1524 +   /* set the compression flag */
  1.1525 +   if (compression == PNG_ITXT_COMPRESSION_NONE || \
  1.1526 +       compression == PNG_TEXT_COMPRESSION_NONE)
  1.1527 +       cbuf[0] = 0;
  1.1528 +   else /* compression == PNG_ITXT_COMPRESSION_zTXt */
  1.1529 +       cbuf[0] = 1;
  1.1530 +   /* set the compression method */
  1.1531 +   cbuf[1] = 0;
  1.1532 +   png_write_chunk_data(png_ptr, cbuf, (png_size_t)2);
  1.1533 +
  1.1534 +   cbuf[0] = 0;
  1.1535 +   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf),
  1.1536 +     (png_size_t)(lang_len + 1));
  1.1537 +   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf),
  1.1538 +     (png_size_t)(lang_key_len + 1));
  1.1539 +   png_write_compressed_data_out(png_ptr, &comp);
  1.1540 +
  1.1541 +   png_write_chunk_end(png_ptr);
  1.1542 +   png_free(png_ptr, new_key);
  1.1543 +   png_free(png_ptr, new_lang);
  1.1544 +}
  1.1545 +#endif
  1.1546 +
  1.1547 +#if defined(PNG_WRITE_oFFs_SUPPORTED)
  1.1548 +/* write the oFFs chunk */
  1.1549 +void /* PRIVATE */
  1.1550 +png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
  1.1551 +   int unit_type)
  1.1552 +{
  1.1553 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1554 +   PNG_oFFs;
  1.1555 +#endif
  1.1556 +   png_byte buf[9];
  1.1557 +
  1.1558 +   png_debug(1, "in png_write_oFFs\n");
  1.1559 +   if (unit_type >= PNG_OFFSET_LAST)
  1.1560 +      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
  1.1561 +
  1.1562 +   png_save_int_32(buf, x_offset);
  1.1563 +   png_save_int_32(buf + 4, y_offset);
  1.1564 +   buf[8] = (png_byte)unit_type;
  1.1565 +
  1.1566 +   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
  1.1567 +}
  1.1568 +#endif
  1.1569 +#if defined(PNG_WRITE_pCAL_SUPPORTED)
  1.1570 +/* write the pCAL chunk (described in the PNG extensions document) */
  1.1571 +void /* PRIVATE */
  1.1572 +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
  1.1573 +   png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
  1.1574 +{
  1.1575 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1576 +   PNG_pCAL;
  1.1577 +#endif
  1.1578 +   png_size_t purpose_len, units_len, total_len;
  1.1579 +   png_uint_32p params_len;
  1.1580 +   png_byte buf[10];
  1.1581 +   png_charp new_purpose;
  1.1582 +   int i;
  1.1583 +
  1.1584 +   png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
  1.1585 +   if (type >= PNG_EQUATION_LAST)
  1.1586 +      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
  1.1587 +
  1.1588 +   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
  1.1589 +   png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
  1.1590 +   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
  1.1591 +   png_debug1(3, "pCAL units length = %d\n", (int)units_len);
  1.1592 +   total_len = purpose_len + units_len + 10;
  1.1593 +
  1.1594 +   params_len = (png_uint_32p)png_malloc(png_ptr,
  1.1595 +      (png_uint_32)(nparams * png_sizeof(png_uint_32)));
  1.1596 +
  1.1597 +   /* Find the length of each parameter, making sure we don't count the
  1.1598 +      null terminator for the last parameter. */
  1.1599 +   for (i = 0; i < nparams; i++)
  1.1600 +   {
  1.1601 +      params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
  1.1602 +      png_debug2(3, "pCAL parameter %d length = %lu\n", i,
  1.1603 +        (unsigned long) params_len[i]);
  1.1604 +      total_len += (png_size_t)params_len[i];
  1.1605 +   }
  1.1606 +
  1.1607 +   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
  1.1608 +   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
  1.1609 +   png_write_chunk_data(png_ptr, (png_bytep)new_purpose,
  1.1610 +     (png_size_t)purpose_len);
  1.1611 +   png_save_int_32(buf, X0);
  1.1612 +   png_save_int_32(buf + 4, X1);
  1.1613 +   buf[8] = (png_byte)type;
  1.1614 +   buf[9] = (png_byte)nparams;
  1.1615 +   png_write_chunk_data(png_ptr, buf, (png_size_t)10);
  1.1616 +   png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
  1.1617 +
  1.1618 +   png_free(png_ptr, new_purpose);
  1.1619 +
  1.1620 +   for (i = 0; i < nparams; i++)
  1.1621 +   {
  1.1622 +      png_write_chunk_data(png_ptr, (png_bytep)params[i],
  1.1623 +         (png_size_t)params_len[i]);
  1.1624 +   }
  1.1625 +
  1.1626 +   png_free(png_ptr, params_len);
  1.1627 +   png_write_chunk_end(png_ptr);
  1.1628 +}
  1.1629 +#endif
  1.1630 +
  1.1631 +#if defined(PNG_WRITE_sCAL_SUPPORTED)
  1.1632 +/* write the sCAL chunk */
  1.1633 +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
  1.1634 +void /* PRIVATE */
  1.1635 +png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
  1.1636 +{
  1.1637 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1638 +   PNG_sCAL;
  1.1639 +#endif
  1.1640 +   char buf[64];
  1.1641 +   png_size_t total_len;
  1.1642 +
  1.1643 +   png_debug(1, "in png_write_sCAL\n");
  1.1644 +
  1.1645 +   buf[0] = (char)unit;
  1.1646 +#if defined(_WIN32_WCE)
  1.1647 +/* sprintf() function is not supported on WindowsCE */
  1.1648 +   {
  1.1649 +      wchar_t wc_buf[32];
  1.1650 +      size_t wc_len;
  1.1651 +      swprintf(wc_buf, TEXT("%12.12e"), width);
  1.1652 +      wc_len = wcslen(wc_buf);
  1.1653 +      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL);
  1.1654 +      total_len = wc_len + 2;
  1.1655 +      swprintf(wc_buf, TEXT("%12.12e"), height);
  1.1656 +      wc_len = wcslen(wc_buf);
  1.1657 +      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len,
  1.1658 +         NULL, NULL);
  1.1659 +      total_len += wc_len;
  1.1660 +   }
  1.1661 +#else
  1.1662 +   png_snprintf(buf + 1, 63, "%12.12e", width);
  1.1663 +   total_len = 1 + png_strlen(buf + 1) + 1;
  1.1664 +   png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
  1.1665 +   total_len += png_strlen(buf + total_len);
  1.1666 +#endif
  1.1667 +
  1.1668 +   png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
  1.1669 +   png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len);
  1.1670 +}
  1.1671 +#else
  1.1672 +#ifdef PNG_FIXED_POINT_SUPPORTED
  1.1673 +void /* PRIVATE */
  1.1674 +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
  1.1675 +   png_charp height)
  1.1676 +{
  1.1677 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1678 +   PNG_sCAL;
  1.1679 +#endif
  1.1680 +   png_byte buf[64];
  1.1681 +   png_size_t wlen, hlen, total_len;
  1.1682 +
  1.1683 +   png_debug(1, "in png_write_sCAL_s\n");
  1.1684 +
  1.1685 +   wlen = png_strlen(width);
  1.1686 +   hlen = png_strlen(height);
  1.1687 +   total_len = wlen + hlen + 2;
  1.1688 +   if (total_len > 64)
  1.1689 +   {
  1.1690 +      png_warning(png_ptr, "Can't write sCAL (buffer too small)");
  1.1691 +      return;
  1.1692 +   }
  1.1693 +
  1.1694 +   buf[0] = (png_byte)unit;
  1.1695 +   png_memcpy(buf + 1, width, wlen + 1);      /* append the '\0' here */
  1.1696 +   png_memcpy(buf + wlen + 2, height, hlen);  /* do NOT append the '\0' here */
  1.1697 +
  1.1698 +   png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
  1.1699 +   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
  1.1700 +}
  1.1701 +#endif
  1.1702 +#endif
  1.1703 +#endif
  1.1704 +
  1.1705 +#if defined(PNG_WRITE_pHYs_SUPPORTED)
  1.1706 +/* write the pHYs chunk */
  1.1707 +void /* PRIVATE */
  1.1708 +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
  1.1709 +   png_uint_32 y_pixels_per_unit,
  1.1710 +   int unit_type)
  1.1711 +{
  1.1712 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1713 +   PNG_pHYs;
  1.1714 +#endif
  1.1715 +   png_byte buf[9];
  1.1716 +
  1.1717 +   png_debug(1, "in png_write_pHYs\n");
  1.1718 +   if (unit_type >= PNG_RESOLUTION_LAST)
  1.1719 +      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
  1.1720 +
  1.1721 +   png_save_uint_32(buf, x_pixels_per_unit);
  1.1722 +   png_save_uint_32(buf + 4, y_pixels_per_unit);
  1.1723 +   buf[8] = (png_byte)unit_type;
  1.1724 +
  1.1725 +   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
  1.1726 +}
  1.1727 +#endif
  1.1728 +
  1.1729 +#if defined(PNG_WRITE_tIME_SUPPORTED)
  1.1730 +/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
  1.1731 + * or png_convert_from_time_t(), or fill in the structure yourself.
  1.1732 + */
  1.1733 +void /* PRIVATE */
  1.1734 +png_write_tIME(png_structp png_ptr, png_timep mod_time)
  1.1735 +{
  1.1736 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1737 +   PNG_tIME;
  1.1738 +#endif
  1.1739 +   png_byte buf[7];
  1.1740 +
  1.1741 +   png_debug(1, "in png_write_tIME\n");
  1.1742 +   if (mod_time->month  > 12 || mod_time->month  < 1 ||
  1.1743 +       mod_time->day    > 31 || mod_time->day    < 1 ||
  1.1744 +       mod_time->hour   > 23 || mod_time->second > 60)
  1.1745 +   {
  1.1746 +      png_warning(png_ptr, "Invalid time specified for tIME chunk");
  1.1747 +      return;
  1.1748 +   }
  1.1749 +
  1.1750 +   png_save_uint_16(buf, mod_time->year);
  1.1751 +   buf[2] = mod_time->month;
  1.1752 +   buf[3] = mod_time->day;
  1.1753 +   buf[4] = mod_time->hour;
  1.1754 +   buf[5] = mod_time->minute;
  1.1755 +   buf[6] = mod_time->second;
  1.1756 +
  1.1757 +   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
  1.1758 +}
  1.1759 +#endif
  1.1760 +
  1.1761 +/* initializes the row writing capability of libpng */
  1.1762 +void /* PRIVATE */
  1.1763 +png_write_start_row(png_structp png_ptr)
  1.1764 +{
  1.1765 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED
  1.1766 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1767 +   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
  1.1768 +
  1.1769 +   /* start of interlace block */
  1.1770 +   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
  1.1771 +
  1.1772 +   /* offset to next interlace block */
  1.1773 +   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
  1.1774 +
  1.1775 +   /* start of interlace block in the y direction */
  1.1776 +   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
  1.1777 +
  1.1778 +   /* offset to next interlace block in the y direction */
  1.1779 +   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
  1.1780 +#endif
  1.1781 +#endif
  1.1782 +
  1.1783 +   png_size_t buf_size;
  1.1784 +
  1.1785 +   png_debug(1, "in png_write_start_row\n");
  1.1786 +   buf_size = (png_size_t)(PNG_ROWBYTES(
  1.1787 +      png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1);
  1.1788 +
  1.1789 +   /* set up row buffer */
  1.1790 +   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr,
  1.1791 +     (png_uint_32)buf_size);
  1.1792 +   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
  1.1793 +
  1.1794 +#ifndef PNG_NO_WRITE_FILTER
  1.1795 +   /* set up filtering buffer, if using this filter */
  1.1796 +   if (png_ptr->do_filter & PNG_FILTER_SUB)
  1.1797 +   {
  1.1798 +      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
  1.1799 +         (png_uint_32)(png_ptr->rowbytes + 1));
  1.1800 +      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
  1.1801 +   }
  1.1802 +
  1.1803 +   /* We only need to keep the previous row if we are using one of these. */
  1.1804 +   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
  1.1805 +   {
  1.1806 +     /* set up previous row buffer */
  1.1807 +      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr,
  1.1808 +        (png_uint_32)buf_size);
  1.1809 +      png_memset(png_ptr->prev_row, 0, buf_size);
  1.1810 +
  1.1811 +      if (png_ptr->do_filter & PNG_FILTER_UP)
  1.1812 +      {
  1.1813 +         png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
  1.1814 +           (png_uint_32)(png_ptr->rowbytes + 1));
  1.1815 +         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
  1.1816 +      }
  1.1817 +
  1.1818 +      if (png_ptr->do_filter & PNG_FILTER_AVG)
  1.1819 +      {
  1.1820 +         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
  1.1821 +           (png_uint_32)(png_ptr->rowbytes + 1));
  1.1822 +         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
  1.1823 +      }
  1.1824 +
  1.1825 +      if (png_ptr->do_filter & PNG_FILTER_PAETH)
  1.1826 +      {
  1.1827 +         png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
  1.1828 +           (png_uint_32)(png_ptr->rowbytes + 1));
  1.1829 +         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
  1.1830 +      }
  1.1831 +   }
  1.1832 +#endif /* PNG_NO_WRITE_FILTER */
  1.1833 +
  1.1834 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED
  1.1835 +   /* if interlaced, we need to set up width and height of pass */
  1.1836 +   if (png_ptr->interlaced)
  1.1837 +   {
  1.1838 +      if (!(png_ptr->transformations & PNG_INTERLACE))
  1.1839 +      {
  1.1840 +         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
  1.1841 +            png_pass_ystart[0]) / png_pass_yinc[0];
  1.1842 +         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
  1.1843 +            png_pass_start[0]) / png_pass_inc[0];
  1.1844 +      }
  1.1845 +      else
  1.1846 +      {
  1.1847 +         png_ptr->num_rows = png_ptr->height;
  1.1848 +         png_ptr->usr_width = png_ptr->width;
  1.1849 +      }
  1.1850 +   }
  1.1851 +   else
  1.1852 +#endif
  1.1853 +   {
  1.1854 +      png_ptr->num_rows = png_ptr->height;
  1.1855 +      png_ptr->usr_width = png_ptr->width;
  1.1856 +   }
  1.1857 +   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
  1.1858 +   png_ptr->zstream.next_out = png_ptr->zbuf;
  1.1859 +}
  1.1860 +
  1.1861 +/* Internal use only.  Called when finished processing a row of data. */
  1.1862 +void /* PRIVATE */
  1.1863 +png_write_finish_row(png_structp png_ptr)
  1.1864 +{
  1.1865 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED
  1.1866 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1867 +   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
  1.1868 +
  1.1869 +   /* start of interlace block */
  1.1870 +   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
  1.1871 +
  1.1872 +   /* offset to next interlace block */
  1.1873 +   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
  1.1874 +
  1.1875 +   /* start of interlace block in the y direction */
  1.1876 +   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
  1.1877 +
  1.1878 +   /* offset to next interlace block in the y direction */
  1.1879 +   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
  1.1880 +#endif
  1.1881 +#endif
  1.1882 +
  1.1883 +   int ret;
  1.1884 +
  1.1885 +   png_debug(1, "in png_write_finish_row\n");
  1.1886 +   /* next row */
  1.1887 +   png_ptr->row_number++;
  1.1888 +
  1.1889 +   /* see if we are done */
  1.1890 +   if (png_ptr->row_number < png_ptr->num_rows)
  1.1891 +      return;
  1.1892 +
  1.1893 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED
  1.1894 +   /* if interlaced, go to next pass */
  1.1895 +   if (png_ptr->interlaced)
  1.1896 +   {
  1.1897 +      png_ptr->row_number = 0;
  1.1898 +      if (png_ptr->transformations & PNG_INTERLACE)
  1.1899 +      {
  1.1900 +         png_ptr->pass++;
  1.1901 +      }
  1.1902 +      else
  1.1903 +      {
  1.1904 +         /* loop until we find a non-zero width or height pass */
  1.1905 +         do
  1.1906 +         {
  1.1907 +            png_ptr->pass++;
  1.1908 +            if (png_ptr->pass >= 7)
  1.1909 +               break;
  1.1910 +            png_ptr->usr_width = (png_ptr->width +
  1.1911 +               png_pass_inc[png_ptr->pass] - 1 -
  1.1912 +               png_pass_start[png_ptr->pass]) /
  1.1913 +               png_pass_inc[png_ptr->pass];
  1.1914 +            png_ptr->num_rows = (png_ptr->height +
  1.1915 +               png_pass_yinc[png_ptr->pass] - 1 -
  1.1916 +               png_pass_ystart[png_ptr->pass]) /
  1.1917 +               png_pass_yinc[png_ptr->pass];
  1.1918 +            if (png_ptr->transformations & PNG_INTERLACE)
  1.1919 +               break;
  1.1920 +         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
  1.1921 +
  1.1922 +      }
  1.1923 +
  1.1924 +      /* reset the row above the image for the next pass */
  1.1925 +      if (png_ptr->pass < 7)
  1.1926 +      {
  1.1927 +         if (png_ptr->prev_row != NULL)
  1.1928 +            png_memset(png_ptr->prev_row, 0,
  1.1929 +               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
  1.1930 +               png_ptr->usr_bit_depth, png_ptr->width)) + 1);
  1.1931 +         return;
  1.1932 +      }
  1.1933 +   }
  1.1934 +#endif
  1.1935 +
  1.1936 +   /* if we get here, we've just written the last row, so we need
  1.1937 +      to flush the compressor */
  1.1938 +   do
  1.1939 +   {
  1.1940 +      /* tell the compressor we are done */
  1.1941 +      ret = deflate(&png_ptr->zstream, Z_FINISH);
  1.1942 +      /* check for an error */
  1.1943 +      if (ret == Z_OK)
  1.1944 +      {
  1.1945 +         /* check to see if we need more room */
  1.1946 +         if (!(png_ptr->zstream.avail_out))
  1.1947 +         {
  1.1948 +            png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
  1.1949 +            png_ptr->zstream.next_out = png_ptr->zbuf;
  1.1950 +            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
  1.1951 +         }
  1.1952 +      }
  1.1953 +      else if (ret != Z_STREAM_END)
  1.1954 +      {
  1.1955 +         if (png_ptr->zstream.msg != NULL)
  1.1956 +            png_error(png_ptr, png_ptr->zstream.msg);
  1.1957 +         else
  1.1958 +            png_error(png_ptr, "zlib error");
  1.1959 +      }
  1.1960 +   } while (ret != Z_STREAM_END);
  1.1961 +
  1.1962 +   /* write any extra space */
  1.1963 +   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
  1.1964 +   {
  1.1965 +      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
  1.1966 +         png_ptr->zstream.avail_out);
  1.1967 +   }
  1.1968 +
  1.1969 +   deflateReset(&png_ptr->zstream);
  1.1970 +   png_ptr->zstream.data_type = Z_BINARY;
  1.1971 +}
  1.1972 +
  1.1973 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
  1.1974 +/* Pick out the correct pixels for the interlace pass.
  1.1975 + * The basic idea here is to go through the row with a source
  1.1976 + * pointer and a destination pointer (sp and dp), and copy the
  1.1977 + * correct pixels for the pass.  As the row gets compacted,
  1.1978 + * sp will always be >= dp, so we should never overwrite anything.
  1.1979 + * See the default: case for the easiest code to understand.
  1.1980 + */
  1.1981 +void /* PRIVATE */
  1.1982 +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
  1.1983 +{
  1.1984 +#ifdef PNG_USE_LOCAL_ARRAYS
  1.1985 +   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
  1.1986 +
  1.1987 +   /* start of interlace block */
  1.1988 +   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
  1.1989 +
  1.1990 +   /* offset to next interlace block */
  1.1991 +   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
  1.1992 +#endif
  1.1993 +
  1.1994 +   png_debug(1, "in png_do_write_interlace\n");
  1.1995 +   /* we don't have to do anything on the last pass (6) */
  1.1996 +#if defined(PNG_USELESS_TESTS_SUPPORTED)
  1.1997 +   if (row != NULL && row_info != NULL && pass < 6)
  1.1998 +#else
  1.1999 +   if (pass < 6)
  1.2000 +#endif
  1.2001 +   {
  1.2002 +      /* each pixel depth is handled separately */
  1.2003 +      switch (row_info->pixel_depth)
  1.2004 +      {
  1.2005 +         case 1:
  1.2006 +         {
  1.2007 +            png_bytep sp;
  1.2008 +            png_bytep dp;
  1.2009 +            int shift;
  1.2010 +            int d;
  1.2011 +            int value;
  1.2012 +            png_uint_32 i;
  1.2013 +            png_uint_32 row_width = row_info->width;
  1.2014 +
  1.2015 +            dp = row;
  1.2016 +            d = 0;
  1.2017 +            shift = 7;
  1.2018 +            for (i = png_pass_start[pass]; i < row_width;
  1.2019 +               i += png_pass_inc[pass])
  1.2020 +            {
  1.2021 +               sp = row + (png_size_t)(i >> 3);
  1.2022 +               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
  1.2023 +               d |= (value << shift);
  1.2024 +
  1.2025 +               if (shift == 0)
  1.2026 +               {
  1.2027 +                  shift = 7;
  1.2028 +                  *dp++ = (png_byte)d;
  1.2029 +                  d = 0;
  1.2030 +               }
  1.2031 +               else
  1.2032 +                  shift--;
  1.2033 +
  1.2034 +            }
  1.2035 +            if (shift != 7)
  1.2036 +               *dp = (png_byte)d;
  1.2037 +            break;
  1.2038 +         }
  1.2039 +         case 2:
  1.2040 +         {
  1.2041 +            png_bytep sp;
  1.2042 +            png_bytep dp;
  1.2043 +            int shift;
  1.2044 +            int d;
  1.2045 +            int value;
  1.2046 +            png_uint_32 i;
  1.2047 +            png_uint_32 row_width = row_info->width;
  1.2048 +
  1.2049 +            dp = row;
  1.2050 +            shift = 6;
  1.2051 +            d = 0;
  1.2052 +            for (i = png_pass_start[pass]; i < row_width;
  1.2053 +               i += png_pass_inc[pass])
  1.2054 +            {
  1.2055 +               sp = row + (png_size_t)(i >> 2);
  1.2056 +               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
  1.2057 +               d |= (value << shift);
  1.2058 +
  1.2059 +               if (shift == 0)
  1.2060 +               {
  1.2061 +                  shift = 6;
  1.2062 +                  *dp++ = (png_byte)d;
  1.2063 +                  d = 0;
  1.2064 +               }
  1.2065 +               else
  1.2066 +                  shift -= 2;
  1.2067 +            }
  1.2068 +            if (shift != 6)
  1.2069 +                   *dp = (png_byte)d;
  1.2070 +            break;
  1.2071 +         }
  1.2072 +         case 4:
  1.2073 +         {
  1.2074 +            png_bytep sp;
  1.2075 +            png_bytep dp;
  1.2076 +            int shift;
  1.2077 +            int d;
  1.2078 +            int value;
  1.2079 +            png_uint_32 i;
  1.2080 +            png_uint_32 row_width = row_info->width;
  1.2081 +
  1.2082 +            dp = row;
  1.2083 +            shift = 4;
  1.2084 +            d = 0;
  1.2085 +            for (i = png_pass_start[pass]; i < row_width;
  1.2086 +               i += png_pass_inc[pass])
  1.2087 +            {
  1.2088 +               sp = row + (png_size_t)(i >> 1);
  1.2089 +               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
  1.2090 +               d |= (value << shift);
  1.2091 +
  1.2092 +               if (shift == 0)
  1.2093 +               {
  1.2094 +                  shift = 4;
  1.2095 +                  *dp++ = (png_byte)d;
  1.2096 +                  d = 0;
  1.2097 +               }
  1.2098 +               else
  1.2099 +                  shift -= 4;
  1.2100 +            }
  1.2101 +            if (shift != 4)
  1.2102 +               *dp = (png_byte)d;
  1.2103 +            break;
  1.2104 +         }
  1.2105 +         default:
  1.2106 +         {
  1.2107 +            png_bytep sp;
  1.2108 +            png_bytep dp;
  1.2109 +            png_uint_32 i;
  1.2110 +            png_uint_32 row_width = row_info->width;
  1.2111 +            png_size_t pixel_bytes;
  1.2112 +
  1.2113 +            /* start at the beginning */
  1.2114 +            dp = row;
  1.2115 +            /* find out how many bytes each pixel takes up */
  1.2116 +            pixel_bytes = (row_info->pixel_depth >> 3);
  1.2117 +            /* loop through the row, only looking at the pixels that
  1.2118 +               matter */
  1.2119 +            for (i = png_pass_start[pass]; i < row_width;
  1.2120 +               i += png_pass_inc[pass])
  1.2121 +            {
  1.2122 +               /* find out where the original pixel is */
  1.2123 +               sp = row + (png_size_t)i * pixel_bytes;
  1.2124 +               /* move the pixel */
  1.2125 +               if (dp != sp)
  1.2126 +                  png_memcpy(dp, sp, pixel_bytes);
  1.2127 +               /* next pixel */
  1.2128 +               dp += pixel_bytes;
  1.2129 +            }
  1.2130 +            break;
  1.2131 +         }
  1.2132 +      }
  1.2133 +      /* set new row width */
  1.2134 +      row_info->width = (row_info->width +
  1.2135 +         png_pass_inc[pass] - 1 -
  1.2136 +         png_pass_start[pass]) /
  1.2137 +         png_pass_inc[pass];
  1.2138 +         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
  1.2139 +            row_info->width);
  1.2140 +   }
  1.2141 +}
  1.2142 +#endif
  1.2143 +
  1.2144 +/* This filters the row, chooses which filter to use, if it has not already
  1.2145 + * been specified by the application, and then writes the row out with the
  1.2146 + * chosen filter.
  1.2147 + */
  1.2148 +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
  1.2149 +#define PNG_HISHIFT 10
  1.2150 +#define PNG_LOMASK ((png_uint_32)0xffffL)
  1.2151 +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
  1.2152 +void /* PRIVATE */
  1.2153 +png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
  1.2154 +{
  1.2155 +   png_bytep best_row;
  1.2156 +#ifndef PNG_NO_WRITE_FILTER
  1.2157 +   png_bytep prev_row, row_buf;
  1.2158 +   png_uint_32 mins, bpp;
  1.2159 +   png_byte filter_to_do = png_ptr->do_filter;
  1.2160 +   png_uint_32 row_bytes = row_info->rowbytes;
  1.2161 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2162 +   int num_p_filters = (int)png_ptr->num_prev_filters;
  1.2163 +#endif
  1.2164 +
  1.2165 +   png_debug(1, "in png_write_find_filter\n");
  1.2166 +   /* find out how many bytes offset each pixel is */
  1.2167 +   bpp = (row_info->pixel_depth + 7) >> 3;
  1.2168 +
  1.2169 +   prev_row = png_ptr->prev_row;
  1.2170 +#endif
  1.2171 +   best_row = png_ptr->row_buf;
  1.2172 +#ifndef PNG_NO_WRITE_FILTER
  1.2173 +   row_buf = best_row;
  1.2174 +   mins = PNG_MAXSUM;
  1.2175 +
  1.2176 +   /* The prediction method we use is to find which method provides the
  1.2177 +    * smallest value when summing the absolute values of the distances
  1.2178 +    * from zero, using anything >= 128 as negative numbers.  This is known
  1.2179 +    * as the "minimum sum of absolute differences" heuristic.  Other
  1.2180 +    * heuristics are the "weighted minimum sum of absolute differences"
  1.2181 +    * (experimental and can in theory improve compression), and the "zlib
  1.2182 +    * predictive" method (not implemented yet), which does test compressions
  1.2183 +    * of lines using different filter methods, and then chooses the
  1.2184 +    * (series of) filter(s) that give minimum compressed data size (VERY
  1.2185 +    * computationally expensive).
  1.2186 +    *
  1.2187 +    * GRR 980525:  consider also
  1.2188 +    *   (1) minimum sum of absolute differences from running average (i.e.,
  1.2189 +    *       keep running sum of non-absolute differences & count of bytes)
  1.2190 +    *       [track dispersion, too?  restart average if dispersion too large?]
  1.2191 +    *  (1b) minimum sum of absolute differences from sliding average, probably
  1.2192 +    *       with window size <= deflate window (usually 32K)
  1.2193 +    *   (2) minimum sum of squared differences from zero or running average
  1.2194 +    *       (i.e., ~ root-mean-square approach)
  1.2195 +    */
  1.2196 +
  1.2197 +
  1.2198 +   /* We don't need to test the 'no filter' case if this is the only filter
  1.2199 +    * that has been chosen, as it doesn't actually do anything to the data.
  1.2200 +    */
  1.2201 +   if ((filter_to_do & PNG_FILTER_NONE) &&
  1.2202 +       filter_to_do != PNG_FILTER_NONE)
  1.2203 +   {
  1.2204 +      png_bytep rp;
  1.2205 +      png_uint_32 sum = 0;
  1.2206 +      png_uint_32 i;
  1.2207 +      int v;
  1.2208 +
  1.2209 +      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
  1.2210 +      {
  1.2211 +         v = *rp;
  1.2212 +         sum += (v < 128) ? v : 256 - v;
  1.2213 +      }
  1.2214 +
  1.2215 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2216 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2217 +      {
  1.2218 +         png_uint_32 sumhi, sumlo;
  1.2219 +         int j;
  1.2220 +         sumlo = sum & PNG_LOMASK;
  1.2221 +         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
  1.2222 +
  1.2223 +         /* Reduce the sum if we match any of the previous rows */
  1.2224 +         for (j = 0; j < num_p_filters; j++)
  1.2225 +         {
  1.2226 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
  1.2227 +            {
  1.2228 +               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
  1.2229 +                  PNG_WEIGHT_SHIFT;
  1.2230 +               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
  1.2231 +                  PNG_WEIGHT_SHIFT;
  1.2232 +            }
  1.2233 +         }
  1.2234 +
  1.2235 +         /* Factor in the cost of this filter (this is here for completeness,
  1.2236 +          * but it makes no sense to have a "cost" for the NONE filter, as
  1.2237 +          * it has the minimum possible computational cost - none).
  1.2238 +          */
  1.2239 +         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
  1.2240 +            PNG_COST_SHIFT;
  1.2241 +         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
  1.2242 +            PNG_COST_SHIFT;
  1.2243 +
  1.2244 +         if (sumhi > PNG_HIMASK)
  1.2245 +            sum = PNG_MAXSUM;
  1.2246 +         else
  1.2247 +            sum = (sumhi << PNG_HISHIFT) + sumlo;
  1.2248 +      }
  1.2249 +#endif
  1.2250 +      mins = sum;
  1.2251 +   }
  1.2252 +
  1.2253 +   /* sub filter */
  1.2254 +   if (filter_to_do == PNG_FILTER_SUB)
  1.2255 +   /* it's the only filter so no testing is needed */
  1.2256 +   {
  1.2257 +      png_bytep rp, lp, dp;
  1.2258 +      png_uint_32 i;
  1.2259 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
  1.2260 +           i++, rp++, dp++)
  1.2261 +      {
  1.2262 +         *dp = *rp;
  1.2263 +      }
  1.2264 +      for (lp = row_buf + 1; i < row_bytes;
  1.2265 +         i++, rp++, lp++, dp++)
  1.2266 +      {
  1.2267 +         *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
  1.2268 +      }
  1.2269 +      best_row = png_ptr->sub_row;
  1.2270 +   }
  1.2271 +
  1.2272 +   else if (filter_to_do & PNG_FILTER_SUB)
  1.2273 +   {
  1.2274 +      png_bytep rp, dp, lp;
  1.2275 +      png_uint_32 sum = 0, lmins = mins;
  1.2276 +      png_uint_32 i;
  1.2277 +      int v;
  1.2278 +
  1.2279 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2280 +      /* We temporarily increase the "minimum sum" by the factor we
  1.2281 +       * would reduce the sum of this filter, so that we can do the
  1.2282 +       * early exit comparison without scaling the sum each time.
  1.2283 +       */
  1.2284 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2285 +      {
  1.2286 +         int j;
  1.2287 +         png_uint_32 lmhi, lmlo;
  1.2288 +         lmlo = lmins & PNG_LOMASK;
  1.2289 +         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
  1.2290 +
  1.2291 +         for (j = 0; j < num_p_filters; j++)
  1.2292 +         {
  1.2293 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
  1.2294 +            {
  1.2295 +               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
  1.2296 +                  PNG_WEIGHT_SHIFT;
  1.2297 +               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
  1.2298 +                  PNG_WEIGHT_SHIFT;
  1.2299 +            }
  1.2300 +         }
  1.2301 +
  1.2302 +         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
  1.2303 +            PNG_COST_SHIFT;
  1.2304 +         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
  1.2305 +            PNG_COST_SHIFT;
  1.2306 +
  1.2307 +         if (lmhi > PNG_HIMASK)
  1.2308 +            lmins = PNG_MAXSUM;
  1.2309 +         else
  1.2310 +            lmins = (lmhi << PNG_HISHIFT) + lmlo;
  1.2311 +      }
  1.2312 +#endif
  1.2313 +
  1.2314 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
  1.2315 +           i++, rp++, dp++)
  1.2316 +      {
  1.2317 +         v = *dp = *rp;
  1.2318 +
  1.2319 +         sum += (v < 128) ? v : 256 - v;
  1.2320 +      }
  1.2321 +      for (lp = row_buf + 1; i < row_bytes;
  1.2322 +         i++, rp++, lp++, dp++)
  1.2323 +      {
  1.2324 +         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
  1.2325 +
  1.2326 +         sum += (v < 128) ? v : 256 - v;
  1.2327 +
  1.2328 +         if (sum > lmins)  /* We are already worse, don't continue. */
  1.2329 +            break;
  1.2330 +      }
  1.2331 +
  1.2332 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2333 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2334 +      {
  1.2335 +         int j;
  1.2336 +         png_uint_32 sumhi, sumlo;
  1.2337 +         sumlo = sum & PNG_LOMASK;
  1.2338 +         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
  1.2339 +
  1.2340 +         for (j = 0; j < num_p_filters; j++)
  1.2341 +         {
  1.2342 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
  1.2343 +            {
  1.2344 +               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
  1.2345 +                  PNG_WEIGHT_SHIFT;
  1.2346 +               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
  1.2347 +                  PNG_WEIGHT_SHIFT;
  1.2348 +            }
  1.2349 +         }
  1.2350 +
  1.2351 +         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
  1.2352 +            PNG_COST_SHIFT;
  1.2353 +         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
  1.2354 +            PNG_COST_SHIFT;
  1.2355 +
  1.2356 +         if (sumhi > PNG_HIMASK)
  1.2357 +            sum = PNG_MAXSUM;
  1.2358 +         else
  1.2359 +            sum = (sumhi << PNG_HISHIFT) + sumlo;
  1.2360 +      }
  1.2361 +#endif
  1.2362 +
  1.2363 +      if (sum < mins)
  1.2364 +      {
  1.2365 +         mins = sum;
  1.2366 +         best_row = png_ptr->sub_row;
  1.2367 +      }
  1.2368 +   }
  1.2369 +
  1.2370 +   /* up filter */
  1.2371 +   if (filter_to_do == PNG_FILTER_UP)
  1.2372 +   {
  1.2373 +      png_bytep rp, dp, pp;
  1.2374 +      png_uint_32 i;
  1.2375 +
  1.2376 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
  1.2377 +           pp = prev_row + 1; i < row_bytes;
  1.2378 +           i++, rp++, pp++, dp++)
  1.2379 +      {
  1.2380 +         *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
  1.2381 +      }
  1.2382 +      best_row = png_ptr->up_row;
  1.2383 +   }
  1.2384 +
  1.2385 +   else if (filter_to_do & PNG_FILTER_UP)
  1.2386 +   {
  1.2387 +      png_bytep rp, dp, pp;
  1.2388 +      png_uint_32 sum = 0, lmins = mins;
  1.2389 +      png_uint_32 i;
  1.2390 +      int v;
  1.2391 +
  1.2392 +
  1.2393 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2394 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2395 +      {
  1.2396 +         int j;
  1.2397 +         png_uint_32 lmhi, lmlo;
  1.2398 +         lmlo = lmins & PNG_LOMASK;
  1.2399 +         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
  1.2400 +
  1.2401 +         for (j = 0; j < num_p_filters; j++)
  1.2402 +         {
  1.2403 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
  1.2404 +            {
  1.2405 +               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
  1.2406 +                  PNG_WEIGHT_SHIFT;
  1.2407 +               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
  1.2408 +                  PNG_WEIGHT_SHIFT;
  1.2409 +            }
  1.2410 +         }
  1.2411 +
  1.2412 +         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
  1.2413 +            PNG_COST_SHIFT;
  1.2414 +         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
  1.2415 +            PNG_COST_SHIFT;
  1.2416 +
  1.2417 +         if (lmhi > PNG_HIMASK)
  1.2418 +            lmins = PNG_MAXSUM;
  1.2419 +         else
  1.2420 +            lmins = (lmhi << PNG_HISHIFT) + lmlo;
  1.2421 +      }
  1.2422 +#endif
  1.2423 +
  1.2424 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
  1.2425 +           pp = prev_row + 1; i < row_bytes; i++)
  1.2426 +      {
  1.2427 +         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
  1.2428 +
  1.2429 +         sum += (v < 128) ? v : 256 - v;
  1.2430 +
  1.2431 +         if (sum > lmins)  /* We are already worse, don't continue. */
  1.2432 +            break;
  1.2433 +      }
  1.2434 +
  1.2435 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2436 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2437 +      {
  1.2438 +         int j;
  1.2439 +         png_uint_32 sumhi, sumlo;
  1.2440 +         sumlo = sum & PNG_LOMASK;
  1.2441 +         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
  1.2442 +
  1.2443 +         for (j = 0; j < num_p_filters; j++)
  1.2444 +         {
  1.2445 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
  1.2446 +            {
  1.2447 +               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
  1.2448 +                  PNG_WEIGHT_SHIFT;
  1.2449 +               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
  1.2450 +                  PNG_WEIGHT_SHIFT;
  1.2451 +            }
  1.2452 +         }
  1.2453 +
  1.2454 +         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
  1.2455 +            PNG_COST_SHIFT;
  1.2456 +         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
  1.2457 +            PNG_COST_SHIFT;
  1.2458 +
  1.2459 +         if (sumhi > PNG_HIMASK)
  1.2460 +            sum = PNG_MAXSUM;
  1.2461 +         else
  1.2462 +            sum = (sumhi << PNG_HISHIFT) + sumlo;
  1.2463 +      }
  1.2464 +#endif
  1.2465 +
  1.2466 +      if (sum < mins)
  1.2467 +      {
  1.2468 +         mins = sum;
  1.2469 +         best_row = png_ptr->up_row;
  1.2470 +      }
  1.2471 +   }
  1.2472 +
  1.2473 +   /* avg filter */
  1.2474 +   if (filter_to_do == PNG_FILTER_AVG)
  1.2475 +   {
  1.2476 +      png_bytep rp, dp, pp, lp;
  1.2477 +      png_uint_32 i;
  1.2478 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
  1.2479 +           pp = prev_row + 1; i < bpp; i++)
  1.2480 +      {
  1.2481 +         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
  1.2482 +      }
  1.2483 +      for (lp = row_buf + 1; i < row_bytes; i++)
  1.2484 +      {
  1.2485 +         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
  1.2486 +                 & 0xff);
  1.2487 +      }
  1.2488 +      best_row = png_ptr->avg_row;
  1.2489 +   }
  1.2490 +
  1.2491 +   else if (filter_to_do & PNG_FILTER_AVG)
  1.2492 +   {
  1.2493 +      png_bytep rp, dp, pp, lp;
  1.2494 +      png_uint_32 sum = 0, lmins = mins;
  1.2495 +      png_uint_32 i;
  1.2496 +      int v;
  1.2497 +
  1.2498 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2499 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2500 +      {
  1.2501 +         int j;
  1.2502 +         png_uint_32 lmhi, lmlo;
  1.2503 +         lmlo = lmins & PNG_LOMASK;
  1.2504 +         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
  1.2505 +
  1.2506 +         for (j = 0; j < num_p_filters; j++)
  1.2507 +         {
  1.2508 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
  1.2509 +            {
  1.2510 +               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
  1.2511 +                  PNG_WEIGHT_SHIFT;
  1.2512 +               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
  1.2513 +                  PNG_WEIGHT_SHIFT;
  1.2514 +            }
  1.2515 +         }
  1.2516 +
  1.2517 +         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
  1.2518 +            PNG_COST_SHIFT;
  1.2519 +         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
  1.2520 +            PNG_COST_SHIFT;
  1.2521 +
  1.2522 +         if (lmhi > PNG_HIMASK)
  1.2523 +            lmins = PNG_MAXSUM;
  1.2524 +         else
  1.2525 +            lmins = (lmhi << PNG_HISHIFT) + lmlo;
  1.2526 +      }
  1.2527 +#endif
  1.2528 +
  1.2529 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
  1.2530 +           pp = prev_row + 1; i < bpp; i++)
  1.2531 +      {
  1.2532 +         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
  1.2533 +
  1.2534 +         sum += (v < 128) ? v : 256 - v;
  1.2535 +      }
  1.2536 +      for (lp = row_buf + 1; i < row_bytes; i++)
  1.2537 +      {
  1.2538 +         v = *dp++ =
  1.2539 +          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
  1.2540 +
  1.2541 +         sum += (v < 128) ? v : 256 - v;
  1.2542 +
  1.2543 +         if (sum > lmins)  /* We are already worse, don't continue. */
  1.2544 +            break;
  1.2545 +      }
  1.2546 +
  1.2547 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2548 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2549 +      {
  1.2550 +         int j;
  1.2551 +         png_uint_32 sumhi, sumlo;
  1.2552 +         sumlo = sum & PNG_LOMASK;
  1.2553 +         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
  1.2554 +
  1.2555 +         for (j = 0; j < num_p_filters; j++)
  1.2556 +         {
  1.2557 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
  1.2558 +            {
  1.2559 +               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
  1.2560 +                  PNG_WEIGHT_SHIFT;
  1.2561 +               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
  1.2562 +                  PNG_WEIGHT_SHIFT;
  1.2563 +            }
  1.2564 +         }
  1.2565 +
  1.2566 +         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
  1.2567 +            PNG_COST_SHIFT;
  1.2568 +         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
  1.2569 +            PNG_COST_SHIFT;
  1.2570 +
  1.2571 +         if (sumhi > PNG_HIMASK)
  1.2572 +            sum = PNG_MAXSUM;
  1.2573 +         else
  1.2574 +            sum = (sumhi << PNG_HISHIFT) + sumlo;
  1.2575 +      }
  1.2576 +#endif
  1.2577 +
  1.2578 +      if (sum < mins)
  1.2579 +      {
  1.2580 +         mins = sum;
  1.2581 +         best_row = png_ptr->avg_row;
  1.2582 +      }
  1.2583 +   }
  1.2584 +
  1.2585 +   /* Paeth filter */
  1.2586 +   if (filter_to_do == PNG_FILTER_PAETH)
  1.2587 +   {
  1.2588 +      png_bytep rp, dp, pp, cp, lp;
  1.2589 +      png_uint_32 i;
  1.2590 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
  1.2591 +           pp = prev_row + 1; i < bpp; i++)
  1.2592 +      {
  1.2593 +         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
  1.2594 +      }
  1.2595 +
  1.2596 +      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
  1.2597 +      {
  1.2598 +         int a, b, c, pa, pb, pc, p;
  1.2599 +
  1.2600 +         b = *pp++;
  1.2601 +         c = *cp++;
  1.2602 +         a = *lp++;
  1.2603 +
  1.2604 +         p = b - c;
  1.2605 +         pc = a - c;
  1.2606 +
  1.2607 +#ifdef PNG_USE_ABS
  1.2608 +         pa = abs(p);
  1.2609 +         pb = abs(pc);
  1.2610 +         pc = abs(p + pc);
  1.2611 +#else
  1.2612 +         pa = p < 0 ? -p : p;
  1.2613 +         pb = pc < 0 ? -pc : pc;
  1.2614 +         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
  1.2615 +#endif
  1.2616 +
  1.2617 +         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
  1.2618 +
  1.2619 +         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
  1.2620 +      }
  1.2621 +      best_row = png_ptr->paeth_row;
  1.2622 +   }
  1.2623 +
  1.2624 +   else if (filter_to_do & PNG_FILTER_PAETH)
  1.2625 +   {
  1.2626 +      png_bytep rp, dp, pp, cp, lp;
  1.2627 +      png_uint_32 sum = 0, lmins = mins;
  1.2628 +      png_uint_32 i;
  1.2629 +      int v;
  1.2630 +
  1.2631 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2632 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2633 +      {
  1.2634 +         int j;
  1.2635 +         png_uint_32 lmhi, lmlo;
  1.2636 +         lmlo = lmins & PNG_LOMASK;
  1.2637 +         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
  1.2638 +
  1.2639 +         for (j = 0; j < num_p_filters; j++)
  1.2640 +         {
  1.2641 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
  1.2642 +            {
  1.2643 +               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
  1.2644 +                  PNG_WEIGHT_SHIFT;
  1.2645 +               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
  1.2646 +                  PNG_WEIGHT_SHIFT;
  1.2647 +            }
  1.2648 +         }
  1.2649 +
  1.2650 +         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
  1.2651 +            PNG_COST_SHIFT;
  1.2652 +         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
  1.2653 +            PNG_COST_SHIFT;
  1.2654 +
  1.2655 +         if (lmhi > PNG_HIMASK)
  1.2656 +            lmins = PNG_MAXSUM;
  1.2657 +         else
  1.2658 +            lmins = (lmhi << PNG_HISHIFT) + lmlo;
  1.2659 +      }
  1.2660 +#endif
  1.2661 +
  1.2662 +      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
  1.2663 +           pp = prev_row + 1; i < bpp; i++)
  1.2664 +      {
  1.2665 +         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
  1.2666 +
  1.2667 +         sum += (v < 128) ? v : 256 - v;
  1.2668 +      }
  1.2669 +
  1.2670 +      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
  1.2671 +      {
  1.2672 +         int a, b, c, pa, pb, pc, p;
  1.2673 +
  1.2674 +         b = *pp++;
  1.2675 +         c = *cp++;
  1.2676 +         a = *lp++;
  1.2677 +
  1.2678 +#ifndef PNG_SLOW_PAETH
  1.2679 +         p = b - c;
  1.2680 +         pc = a - c;
  1.2681 +#ifdef PNG_USE_ABS
  1.2682 +         pa = abs(p);
  1.2683 +         pb = abs(pc);
  1.2684 +         pc = abs(p + pc);
  1.2685 +#else
  1.2686 +         pa = p < 0 ? -p : p;
  1.2687 +         pb = pc < 0 ? -pc : pc;
  1.2688 +         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
  1.2689 +#endif
  1.2690 +         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
  1.2691 +#else /* PNG_SLOW_PAETH */
  1.2692 +         p = a + b - c;
  1.2693 +         pa = abs(p - a);
  1.2694 +         pb = abs(p - b);
  1.2695 +         pc = abs(p - c);
  1.2696 +         if (pa <= pb && pa <= pc)
  1.2697 +            p = a;
  1.2698 +         else if (pb <= pc)
  1.2699 +            p = b;
  1.2700 +         else
  1.2701 +            p = c;
  1.2702 +#endif /* PNG_SLOW_PAETH */
  1.2703 +
  1.2704 +         v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
  1.2705 +
  1.2706 +         sum += (v < 128) ? v : 256 - v;
  1.2707 +
  1.2708 +         if (sum > lmins)  /* We are already worse, don't continue. */
  1.2709 +            break;
  1.2710 +      }
  1.2711 +
  1.2712 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2713 +      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
  1.2714 +      {
  1.2715 +         int j;
  1.2716 +         png_uint_32 sumhi, sumlo;
  1.2717 +         sumlo = sum & PNG_LOMASK;
  1.2718 +         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
  1.2719 +
  1.2720 +         for (j = 0; j < num_p_filters; j++)
  1.2721 +         {
  1.2722 +            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
  1.2723 +            {
  1.2724 +               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
  1.2725 +                  PNG_WEIGHT_SHIFT;
  1.2726 +               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
  1.2727 +                  PNG_WEIGHT_SHIFT;
  1.2728 +            }
  1.2729 +         }
  1.2730 +
  1.2731 +         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
  1.2732 +            PNG_COST_SHIFT;
  1.2733 +         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
  1.2734 +            PNG_COST_SHIFT;
  1.2735 +
  1.2736 +         if (sumhi > PNG_HIMASK)
  1.2737 +            sum = PNG_MAXSUM;
  1.2738 +         else
  1.2739 +            sum = (sumhi << PNG_HISHIFT) + sumlo;
  1.2740 +      }
  1.2741 +#endif
  1.2742 +
  1.2743 +      if (sum < mins)
  1.2744 +      {
  1.2745 +         best_row = png_ptr->paeth_row;
  1.2746 +      }
  1.2747 +   }
  1.2748 +#endif /* PNG_NO_WRITE_FILTER */
  1.2749 +   /* Do the actual writing of the filtered row data from the chosen filter. */
  1.2750 +
  1.2751 +   png_write_filtered_row(png_ptr, best_row);
  1.2752 +
  1.2753 +#ifndef PNG_NO_WRITE_FILTER
  1.2754 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  1.2755 +   /* Save the type of filter we picked this time for future calculations */
  1.2756 +   if (png_ptr->num_prev_filters > 0)
  1.2757 +   {
  1.2758 +      int j;
  1.2759 +      for (j = 1; j < num_p_filters; j++)
  1.2760 +      {
  1.2761 +         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
  1.2762 +      }
  1.2763 +      png_ptr->prev_filters[j] = best_row[0];
  1.2764 +   }
  1.2765 +#endif
  1.2766 +#endif /* PNG_NO_WRITE_FILTER */
  1.2767 +}
  1.2768 +
  1.2769 +
  1.2770 +/* Do the actual writing of a previously filtered row. */
  1.2771 +void /* PRIVATE */
  1.2772 +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
  1.2773 +{
  1.2774 +   png_debug(1, "in png_write_filtered_row\n");
  1.2775 +   png_debug1(2, "filter = %d\n", filtered_row[0]);
  1.2776 +   /* set up the zlib input buffer */
  1.2777 +
  1.2778 +   png_ptr->zstream.next_in = filtered_row;
  1.2779 +   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
  1.2780 +   /* repeat until we have compressed all the data */
  1.2781 +   do
  1.2782 +   {
  1.2783 +      int ret; /* return of zlib */
  1.2784 +
  1.2785 +      /* compress the data */
  1.2786 +      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
  1.2787 +      /* check for compression errors */
  1.2788 +      if (ret != Z_OK)
  1.2789 +      {
  1.2790 +         if (png_ptr->zstream.msg != NULL)
  1.2791 +            png_error(png_ptr, png_ptr->zstream.msg);
  1.2792 +         else
  1.2793 +            png_error(png_ptr, "zlib error");
  1.2794 +      }
  1.2795 +
  1.2796 +      /* see if it is time to write another IDAT */
  1.2797 +      if (!(png_ptr->zstream.avail_out))
  1.2798 +      {
  1.2799 +         /* write the IDAT and reset the zlib output buffer */
  1.2800 +         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
  1.2801 +         png_ptr->zstream.next_out = png_ptr->zbuf;
  1.2802 +         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
  1.2803 +      }
  1.2804 +   /* repeat until all data has been compressed */
  1.2805 +   } while (png_ptr->zstream.avail_in);
  1.2806 +
  1.2807 +   /* swap the current and previous rows */
  1.2808 +   if (png_ptr->prev_row != NULL)
  1.2809 +   {
  1.2810 +      png_bytep tptr;
  1.2811 +
  1.2812 +      tptr = png_ptr->prev_row;
  1.2813 +      png_ptr->prev_row = png_ptr->row_buf;
  1.2814 +      png_ptr->row_buf = tptr;
  1.2815 +   }
  1.2816 +
  1.2817 +   /* finish row - updates counters and flushes zlib if last row */
  1.2818 +   png_write_finish_row(png_ptr);
  1.2819 +
  1.2820 +#if defined(PNG_WRITE_FLUSH_SUPPORTED)
  1.2821 +   png_ptr->flush_rows++;
  1.2822 +
  1.2823 +   if (png_ptr->flush_dist > 0 &&
  1.2824 +       png_ptr->flush_rows >= png_ptr->flush_dist)
  1.2825 +   {
  1.2826 +      png_write_flush(png_ptr);
  1.2827 +   }
  1.2828 +#endif
  1.2829 +}
  1.2830 +#endif /* PNG_WRITE_SUPPORTED */