pngwutil.c 81.9 KB
Newer Older
G
Guy Schalnat 已提交
1

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * Last changed in libpng 1.2.9 April 14, 2006
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2006 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9
 */
A
Andreas Dilger 已提交
10

G
Guy Schalnat 已提交
11 12
#define PNG_INTERNAL
#include "png.h"
13
#ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
14

A
Andreas Dilger 已提交
15 16 17 18
/* Place a 32-bit number into a buffer in PNG byte order.  We work
 * with unsigned numbers for convenience, although one supported
 * ancillary chunk uses signed (two's complement) numbers.
 */
19
void PNGAPI
G
Guy Schalnat 已提交
20
png_save_uint_32(png_bytep buf, png_uint_32 i)
G
Guy Schalnat 已提交
21 22 23 24 25 26 27
{
   buf[0] = (png_byte)((i >> 24) & 0xff);
   buf[1] = (png_byte)((i >> 16) & 0xff);
   buf[2] = (png_byte)((i >> 8) & 0xff);
   buf[3] = (png_byte)(i & 0xff);
}

A
Andreas Dilger 已提交
28
/* The png_save_int_32 function assumes integers are stored in two's
29 30 31
 * complement format.  If this isn't the case, then this routine needs to
 * be modified to write data in two's complement format.
 */
32
void PNGAPI
A
Andreas Dilger 已提交
33
png_save_int_32(png_bytep buf, png_int_32 i)
G
Guy Schalnat 已提交
34 35 36 37 38 39 40
{
   buf[0] = (png_byte)((i >> 24) & 0xff);
   buf[1] = (png_byte)((i >> 16) & 0xff);
   buf[2] = (png_byte)((i >> 8) & 0xff);
   buf[3] = (png_byte)(i & 0xff);
}

41 42 43 44
/* Place a 16-bit number into a buffer in PNG byte order.
 * The parameter is declared unsigned int, not png_uint_16,
 * just to avoid potential problems on pre-ANSI C compilers.
 */
45
void PNGAPI
46
png_save_uint_16(png_bytep buf, unsigned int i)
G
Guy Schalnat 已提交
47 48 49 50 51
{
   buf[0] = (png_byte)((i >> 8) & 0xff);
   buf[1] = (png_byte)(i & 0xff);
}

A
Andreas Dilger 已提交
52
/* Write a PNG chunk all at once.  The type is an array of ASCII characters
53 54 55 56 57 58 59 60
 * representing the chunk name.  The array must be at least 4 bytes in
 * length, and does not need to be null terminated.  To be safe, pass the
 * pre-defined chunk names here, and if you need a new one, define it
 * where the others are defined.  The length is the length of the data.
 * All the data must be present.  If that is not possible, use the
 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
 * functions instead.
 */
61
void PNGAPI
A
Andreas Dilger 已提交
62
png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
A
Andreas Dilger 已提交
63
   png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
64
{
A
Andreas Dilger 已提交
65
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
A
Andreas Dilger 已提交
66 67
   png_write_chunk_data(png_ptr, data, length);
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
68 69
}

A
Andreas Dilger 已提交
70
/* Write the start of a PNG chunk.  The type is the chunk type.
71 72 73
 * The total_length is the sum of the lengths of all the data you will be
 * passing in png_write_chunk_data().
 */
74
void PNGAPI
A
Andreas Dilger 已提交
75 76
png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
   png_uint_32 length)
G
Guy Schalnat 已提交
77
{
A
Andreas Dilger 已提交
78
   png_byte buf[4];
79
   png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
A
Andreas Dilger 已提交
80

G
Guy Schalnat 已提交
81
   /* write the length */
A
Andreas Dilger 已提交
82 83 84
   png_save_uint_32(buf, length);
   png_write_data(png_ptr, buf, (png_size_t)4);

G
Guy Schalnat 已提交
85
   /* write the chunk name */
A
Andreas Dilger 已提交
86
   png_write_data(png_ptr, chunk_name, (png_size_t)4);
G
Guy Schalnat 已提交
87 88
   /* reset the crc and run it over the chunk name */
   png_reset_crc(png_ptr);
A
Andreas Dilger 已提交
89
   png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
G
Guy Schalnat 已提交
90 91
}

A
Andreas Dilger 已提交
92
/* Write the data of a PNG chunk started with png_write_chunk_start().
93 94 95 96
 * Note that multiple calls to this function are allowed, and that the
 * sum of the lengths from these calls *must* add up to the total_length
 * given to png_write_chunk_start().
 */
97
void PNGAPI
A
Andreas Dilger 已提交
98
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
99
{
A
Andreas Dilger 已提交
100 101
   /* write the data, and run the CRC over it */
   if (data != NULL && length > 0)
G
Guy Schalnat 已提交
102 103
   {
      png_calculate_crc(png_ptr, data, length);
G
Guy Schalnat 已提交
104
      png_write_data(png_ptr, data, length);
G
Guy Schalnat 已提交
105 106 107
   }
}

A
Andreas Dilger 已提交
108
/* Finish a chunk started with png_write_chunk_start(). */
109
void PNGAPI
G
Guy Schalnat 已提交
110
png_write_chunk_end(png_structp png_ptr)
G
Guy Schalnat 已提交
111
{
A
Andreas Dilger 已提交
112 113
   png_byte buf[4];

G
Guy Schalnat 已提交
114
   /* write the crc */
A
Andreas Dilger 已提交
115 116 117
   png_save_uint_32(buf, png_ptr->crc);

   png_write_data(png_ptr, buf, (png_size_t)4);
G
Guy Schalnat 已提交
118 119
}

A
Andreas Dilger 已提交
120 121 122 123
/* Simple function to write the signature.  If we have already written
 * the magic bytes of the signature, or more likely, the PNG stream is
 * being embedded into another stream and doesn't need its own signature,
 * we should call png_set_sig_bytes() to tell libpng how many of the
124 125
 * bytes have already been written.
 */
126
void /* PRIVATE */
G
Guy Schalnat 已提交
127
png_write_sig(png_structp png_ptr)
G
Guy Schalnat 已提交
128
{
129
   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
A
Andreas Dilger 已提交
130
   /* write the rest of the 8 byte signature */
131
   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
A
Andreas Dilger 已提交
132
      (png_size_t)8 - png_ptr->sig_bytes);
133 134
   if(png_ptr->sig_bytes < 3)
      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
G
Guy Schalnat 已提交
135 136
}

137
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/*
 * This pair of functions encapsulates the operation of (a) compressing a
 * text string, and (b) issuing it later as a series of chunk data writes.
 * The compression_state structure is shared context for these functions
 * set up by the caller in order to make the whole mess thread-safe.
 */

typedef struct
{
    char *input;   /* the uncompressed input data */
    int input_len;   /* its length */
    int num_output_ptr; /* number of output pointers used */
    int max_output_ptr; /* size of output_ptr */
    png_charpp output_ptr; /* array of pointers to output */
} compression_state;

/* compress given text into storage in the png_ptr structure */
155
static int /* PRIVATE */
156 157 158 159 160 161
png_text_compress(png_structp png_ptr,
        png_charp text, png_size_t text_len, int compression,
        compression_state *comp)
{
   int ret;

162 163
   comp->num_output_ptr = 0;
   comp->max_output_ptr = 0;
164 165
   comp->output_ptr = NULL;
   comp->input = NULL;
166
   comp->input_len = 0;
167 168 169 170 171 172

   /* we may just want to pass the text right through */
   if (compression == PNG_TEXT_COMPRESSION_NONE)
   {
       comp->input = text;
       comp->input_len = text_len;
173
       return((int)text_len);
174 175 176 177
   }

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
178
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
      char msg[50];
      sprintf(msg, "Unknown compression type %d", compression);
      png_warning(png_ptr, msg);
#else
      png_warning(png_ptr, "Unknown compression type");
#endif
   }

   /* We can't write the chunk until we find out how much data we have,
    * which means we need to run the compressor first and save the
    * output.  This shouldn't be a problem, as the vast majority of
    * comments should be reasonable, but we will set up an array of
    * malloc'd pointers to be sure.
    *
    * If we knew the application was well behaved, we could simplify this
    * greatly by assuming we can always malloc an output buffer large
    * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
    * and malloc this directly.  The only time this would be a bad idea is
    * if we can't malloc more than 64K and we have 64K of random input
    * data, or if the input string is incredibly large (although this
    * wouldn't cause a failure, just a slowdown due to swapping).
    */

   /* set up the compression buffers */
   png_ptr->zstream.avail_in = (uInt)text_len;
   png_ptr->zstream.next_in = (Bytef *)text;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;

   /* this is the same compression loop as in png_write_row() */
   do
   {
      /* compress the data */
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
      if (ret != Z_OK)
      {
         /* error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
      }
      /* check to see if we need more room */
222
      if (!(png_ptr->zstream.avail_out))
223 224 225 226 227 228 229 230 231 232 233 234 235 236
      {
         /* make sure the output array has room */
         if (comp->num_output_ptr >= comp->max_output_ptr)
         {
            int old_max;

            old_max = comp->max_output_ptr;
            comp->max_output_ptr = comp->num_output_ptr + 4;
            if (comp->output_ptr != NULL)
            {
               png_charpp old_ptr;

               old_ptr = comp->output_ptr;
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
237 238
                  (png_uint_32)(comp->max_output_ptr *
                  png_sizeof (png_charpp)));
239
               png_memcpy(comp->output_ptr, old_ptr, old_max
240
                  * png_sizeof (png_charp));
241 242 243 244
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
245 246
                  (png_uint_32)(comp->max_output_ptr *
                  png_sizeof (png_charp)));
247 248 249 250 251
         }

         /* save the data */
         comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
            (png_uint_32)png_ptr->zbuf_size);
252 253 254
         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
            png_ptr->zbuf_size);
         comp->num_output_ptr++;
255 256 257 258 259 260 261 262 263 264 265 266 267 268

         /* and reset the buffer */
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_out = png_ptr->zbuf;
      }
   /* continue until we don't have any more to compress */
   } while (png_ptr->zstream.avail_in);

   /* finish the compression */
   do
   {
      /* tell zlib we are finished */
      ret = deflate(&png_ptr->zstream, Z_FINISH);

269
      if (ret == Z_OK)
270
      {
271 272
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
273
         {
274 275
            /* check to make sure our output array has room */
            if (comp->num_output_ptr >= comp->max_output_ptr)
276
            {
277 278 279 280 281 282 283 284 285 286 287
               int old_max;

               old_max = comp->max_output_ptr;
               comp->max_output_ptr = comp->num_output_ptr + 4;
               if (comp->output_ptr != NULL)
               {
                  png_charpp old_ptr;

                  old_ptr = comp->output_ptr;
                  /* This could be optimized to realloc() */
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
288 289
                     (png_uint_32)(comp->max_output_ptr *
                     png_sizeof (png_charpp)));
290
                  png_memcpy(comp->output_ptr, old_ptr,
291
                     old_max * png_sizeof (png_charp));
292 293 294 295
                  png_free(png_ptr, old_ptr);
               }
               else
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
296 297
                     (png_uint_32)(comp->max_output_ptr *
                     png_sizeof (png_charp)));
298 299
            }

300 301 302
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
               (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
303 304 305
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
306

307 308 309 310 311 312 313 314 315 316 317 318
            /* and reset the buffer pointers */
            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
            png_ptr->zstream.next_out = png_ptr->zbuf;
         }
      }
      else if (ret != Z_STREAM_END)
      {
         /* we got an error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
319 320 321 322 323 324 325 326
      }
   } while (ret != Z_STREAM_END);

   /* text length is number of buffers plus last buffer */
   text_len = png_ptr->zbuf_size * comp->num_output_ptr;
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;

327
   return((int)text_len);
328 329 330
}

/* ship the compressed text out via chunk writes */
331
static void /* PRIVATE */
332 333 334 335 336 337 338
png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
{
   int i;

   /* handle the no-compression case */
   if (comp->input)
   {
339 340
       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
                            (png_size_t)comp->input_len);
341 342 343 344 345 346
       return;
   }

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
347 348
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
349
      png_free(png_ptr, comp->output_ptr[i]);
350
      comp->output_ptr[i]=NULL;
351 352 353
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
354
      comp->output_ptr=NULL;
355 356 357 358 359
   /* write anything left in zbuf */
   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
      png_write_chunk_data(png_ptr, png_ptr->zbuf,
         png_ptr->zbuf_size - png_ptr->zstream.avail_out);

360
   /* reset zlib for another zTXt/iTXt or image data */
361
   deflateReset(&png_ptr->zstream);
362
   png_ptr->zstream.data_type = Z_BINARY;
363 364 365
}
#endif

G
Guy Schalnat 已提交
366
/* Write the IHDR chunk, and update the png_struct with the necessary
367 368 369
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
370
void /* PRIVATE */
G
Guy Schalnat 已提交
371
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
372 373 374
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
375 376 377
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
G
Guy Schalnat 已提交
378 379
   png_byte buf[13]; /* buffer to store the IHDR info */

A
Andreas Dilger 已提交
380
   png_debug(1, "in png_write_IHDR\n");
G
Guy Schalnat 已提交
381
   /* Check that we have valid input data from the application info */
G
Guy Schalnat 已提交
382 383
   switch (color_type)
   {
A
Andreas Dilger 已提交
384
      case PNG_COLOR_TYPE_GRAY:
G
Guy Schalnat 已提交
385 386 387 388 389 390 391
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8:
            case 16: png_ptr->channels = 1; break;
A
Andreas Dilger 已提交
392
            default: png_error(png_ptr,"Invalid bit depth for grayscale image");
G
Guy Schalnat 已提交
393
         }
G
Guy Schalnat 已提交
394
         break;
A
Andreas Dilger 已提交
395
      case PNG_COLOR_TYPE_RGB:
G
Guy Schalnat 已提交
396 397
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGB image");
G
Guy Schalnat 已提交
398 399
         png_ptr->channels = 3;
         break;
A
Andreas Dilger 已提交
400
      case PNG_COLOR_TYPE_PALETTE:
G
Guy Schalnat 已提交
401 402 403 404 405 406 407 408 409
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8: png_ptr->channels = 1; break;
            default: png_error(png_ptr, "Invalid bit depth for paletted image");
         }
         break;
A
Andreas Dilger 已提交
410
      case PNG_COLOR_TYPE_GRAY_ALPHA:
G
Guy Schalnat 已提交
411 412
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
G
Guy Schalnat 已提交
413 414
         png_ptr->channels = 2;
         break;
A
Andreas Dilger 已提交
415
      case PNG_COLOR_TYPE_RGB_ALPHA:
G
Guy Schalnat 已提交
416 417
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGBA image");
G
Guy Schalnat 已提交
418 419
         png_ptr->channels = 4;
         break;
G
Guy Schalnat 已提交
420 421 422 423
      default:
         png_error(png_ptr, "Invalid image color type specified");
   }

A
Andreas Dilger 已提交
424
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
425 426
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
427
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
428 429
   }

430 431 432 433 434 435 436 437 438
   /* Write filter_method 64 (intrapixel differencing) only if
    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    * 2. Libpng did not write a PNG signature (this filter_method is only
    *    used in PNG datastreams that are embedded in MNG datastreams) and
    * 3. The application called png_permit_mng_features with a mask that
    *    included PNG_FLAG_MNG_FILTER_64 and
    * 4. The filter_method is 64 and
    * 5. The color_type is RGB or RGBA
    */
439 440 441
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
442
      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
443
      (color_type == PNG_COLOR_TYPE_RGB ||
444
       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
445 446 447
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
448 449
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
450
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
451 452
   }

453
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
454 455
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
456 457
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
458
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
459
   }
460 461 462
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
463 464 465 466 467

   /* save off the relevent information */
   png_ptr->bit_depth = (png_byte)bit_depth;
   png_ptr->color_type = (png_byte)color_type;
   png_ptr->interlaced = (png_byte)interlace_type;
468
#if defined(PNG_MNG_FEATURES_SUPPORTED)
469
   png_ptr->filter_type = (png_byte)filter_type;
470
#endif
471
   png_ptr->compression_type = (png_byte)compression_type;
G
Guy Schalnat 已提交
472 473 474
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
475
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
476
   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
G
Guy Schalnat 已提交
477 478 479
   /* set the usr info, so any transformations can modify it */
   png_ptr->usr_width = png_ptr->width;
   png_ptr->usr_bit_depth = png_ptr->bit_depth;
G
Guy Schalnat 已提交
480 481 482 483 484 485 486 487 488 489
   png_ptr->usr_channels = png_ptr->channels;

   /* pack the header information into the buffer */
   png_save_uint_32(buf, width);
   png_save_uint_32(buf + 4, height);
   buf[8] = (png_byte)bit_depth;
   buf[9] = (png_byte)color_type;
   buf[10] = (png_byte)compression_type;
   buf[11] = (png_byte)filter_type;
   buf[12] = (png_byte)interlace_type;
G
Guy Schalnat 已提交
490 491

   /* write the chunk */
492
   png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
G
Guy Schalnat 已提交
493

A
Andreas Dilger 已提交
494
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
495 496 497
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
498
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
499
   {
A
Andreas Dilger 已提交
500 501
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
502
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
503
      else
G
Guy Schalnat 已提交
504
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
505
   }
G
Guy Schalnat 已提交
506
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
507
   {
G
Guy Schalnat 已提交
508
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
509 510 511 512
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
513
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
514
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
515
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
516
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
517
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
518
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
519
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
520
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
521
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
522 523
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
524 525
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
526 527 528
   /* libpng is not interested in zstream.data_type */
   /* set it to a predefined value, to avoid its evaluation inside zlib */
   png_ptr->zstream.data_type = Z_BINARY;
G
Guy Schalnat 已提交
529

G
Guy Schalnat 已提交
530
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
531 532 533
}

/* write the palette.  We are careful not to trust png_color to be in the
534
 * correct order for PNG, so people can redefine it to any convenient
535 536
 * structure.
 */
537
void /* PRIVATE */
A
Andreas Dilger 已提交
538
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
539
{
540 541 542
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
543
   png_uint_32 i;
G
Guy Schalnat 已提交
544
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
545 546
   png_byte buf[3];

A
Andreas Dilger 已提交
547
   png_debug(1, "in png_write_PLTE\n");
548
   if ((
549
#if defined(PNG_MNG_FEATURES_SUPPORTED)
550
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
551 552
#endif
        num_pal == 0) || num_pal > 256)
553 554
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
555
     {
556 557 558 559 560 561 562 563 564 565 566 567 568 569
        png_error(png_ptr, "Invalid number of colors in palette");
     }
     else
     {
        png_warning(png_ptr, "Invalid number of colors in palette");
        return;
     }
   }

   if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
   {
      png_warning(png_ptr,
        "Ignoring request to write a PLTE chunk in grayscale PNG");
      return;
G
Guy Schalnat 已提交
570 571
   }

A
Andreas Dilger 已提交
572 573
   png_ptr->num_palette = (png_uint_16)num_pal;
   png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
G
Guy Schalnat 已提交
574

575
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
576
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
577
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
578 579 580 581
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
582
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
583
   }
584 585 586 587 588 589 590 591 592 593 594
#else
   /* This is a little slower but some buggy compilers need to do this instead */
   pal_ptr=palette;
   for (i = 0; i < num_pal; i++)
   {
      buf[0] = pal_ptr[i].red;
      buf[1] = pal_ptr[i].green;
      buf[2] = pal_ptr[i].blue;
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
   }
#endif
G
Guy Schalnat 已提交
595
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
596
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
597 598 599
}

/* write an IDAT chunk */
600
void /* PRIVATE */
A
Andreas Dilger 已提交
601
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
602
{
603 604 605
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
606
   png_debug(1, "in png_write_IDAT\n");
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
   /* Optimize the CMF field in the zlib stream. */
   /* This hack of the zlib stream is compliant to the stream specification. */
   if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
       png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
   {
      unsigned int z_cmf = data[0];  /* zlib compression method and flags */
      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
      {
         /* Avoid memory underflows and multiplication overflows. */
         /* The conditions below are practically always satisfied;
            however, they still must be checked. */
         if (length >= 2 &&
             png_ptr->height < 16384 && png_ptr->width < 16384)
         {
            png_uint_32 uncompressed_idat_size = png_ptr->height *
               ((png_ptr->width *
               png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
            unsigned int z_cinfo = z_cmf >> 4;
            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
            while (uncompressed_idat_size <= half_z_window_size &&
                   half_z_window_size >= 256)
            {
               z_cinfo--;
               half_z_window_size >>= 1;
            }
            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
            if (data[0] != (png_byte)z_cmf)
            {
               data[0] = (png_byte)z_cmf;
               data[1] &= 0xe0;
               data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
            }
         }
      }
      else
         png_error(png_ptr,
            "Invalid zlib compression method or flags in IDAT");
   }

647
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
648
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
649 650 651
}

/* write an IEND chunk */
652
void /* PRIVATE */
G
Guy Schalnat 已提交
653
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
654
{
655 656 657
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
658
   png_debug(1, "in png_write_IEND\n");
659
   png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
660
     (png_size_t)0);
A
Andreas Dilger 已提交
661
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
662 663
}

G
Guy Schalnat 已提交
664
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
665
/* write a gAMA chunk */
666
#ifdef PNG_FLOATING_POINT_SUPPORTED
667
void /* PRIVATE */
A
Andreas Dilger 已提交
668
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
669
{
670 671 672
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
673 674 675
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
676
   png_debug(1, "in png_write_gAMA\n");
677
   /* file_gamma is saved in 1/100,000ths */
678
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
679
   png_save_uint_32(buf, igamma);
680
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
681
}
G
Guy Schalnat 已提交
682
#endif
683
#ifdef PNG_FIXED_POINT_SUPPORTED
684
void /* PRIVATE */
685
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
686 687 688 689 690 691 692
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
693
   /* file_gamma is saved in 1/100,000ths */
694
   png_save_uint_32(buf, (png_uint_32)file_gamma);
695 696 697 698
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
}
#endif
#endif
G
Guy Schalnat 已提交
699

700 701
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
702
void /* PRIVATE */
703
png_write_sRGB(png_structp png_ptr, int srgb_intent)
704
{
705 706 707
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
708 709 710
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
711
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
712 713
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
714
   buf[0]=(png_byte)srgb_intent;
715
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
716 717 718
}
#endif

719 720
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
721
void /* PRIVATE */
722 723 724 725 726 727 728 729 730 731 732
png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
   png_charp profile, int profile_len)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iCCP;
#endif
   png_size_t name_len;
   png_charp new_name;
   compression_state comp;

   png_debug(1, "in png_write_iCCP\n");
733 734 735 736 737 738 739

   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

740 741 742 743 744 745 746
   if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
      &new_name)) == 0)
   {
      png_warning(png_ptr, "Empty keyword in iCCP chunk");
      return;
   }

747
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
748
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
749

750
   if (profile == NULL)
751 752 753
      profile_len = 0;

   if (profile_len)
754
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
755
          PNG_COMPRESSION_TYPE_BASE, &comp);
756 757 758 759

   /* make sure we include the NULL after the name and the compression type */
   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
          (png_uint_32)name_len+profile_len+2);
760
   new_name[name_len+1]=0x00;
761 762 763 764 765 766 767 768 769 770 771 772
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);

   if (profile_len)
      png_write_compressed_data_out(png_ptr, &comp);

   png_write_chunk_end(png_ptr);
   png_free(png_ptr, new_name);
}
#endif

#if defined(PNG_WRITE_sPLT_SUPPORTED)
/* write a sPLT chunk */
773
void /* PRIVATE */
774
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
775 776 777 778 779 780 781 782 783
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sPLT;
#endif
   png_size_t name_len;
   png_charp new_name;
   png_byte entrybuf[10];
   int entry_size = (spalette->depth == 8 ? 6 : 10);
   int palette_size = entry_size * spalette->nentries;
784
   png_sPLT_entryp ep;
785 786 787
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
788 789

   png_debug(1, "in png_write_sPLT\n");
790 791
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
792 793 794 795 796 797
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
798
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
799
          (png_uint_32)(name_len + 2 + palette_size));
800
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
801
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
802 803

   /* loop through each palette entry, writing appropriately */
804
#ifndef PNG_NO_POINTER_INDEXING
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
   for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
   {
       if (spalette->depth == 8)
       {
           entrybuf[0] = (png_byte)ep->red;
           entrybuf[1] = (png_byte)ep->green;
           entrybuf[2] = (png_byte)ep->blue;
           entrybuf[3] = (png_byte)ep->alpha;
           png_save_uint_16(entrybuf + 4, ep->frequency);
       }
       else
       {
           png_save_uint_16(entrybuf + 0, ep->red);
           png_save_uint_16(entrybuf + 2, ep->green);
           png_save_uint_16(entrybuf + 4, ep->blue);
           png_save_uint_16(entrybuf + 6, ep->alpha);
           png_save_uint_16(entrybuf + 8, ep->frequency);
       }
823
       png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
824
   }
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
       if (spalette->depth == 8)
       {
           entrybuf[0] = (png_byte)ep[i].red;
           entrybuf[1] = (png_byte)ep[i].green;
           entrybuf[2] = (png_byte)ep[i].blue;
           entrybuf[3] = (png_byte)ep[i].alpha;
           png_save_uint_16(entrybuf + 4, ep[i].frequency);
       }
       else
       {
           png_save_uint_16(entrybuf + 0, ep[i].red);
           png_save_uint_16(entrybuf + 2, ep[i].green);
           png_save_uint_16(entrybuf + 4, ep[i].blue);
           png_save_uint_16(entrybuf + 6, ep[i].alpha);
           png_save_uint_16(entrybuf + 8, ep[i].frequency);
       }
       png_write_chunk_data(png_ptr, entrybuf, entry_size);
   }
#endif
848 849 850 851 852 853

   png_write_chunk_end(png_ptr);
   png_free(png_ptr, new_name);
}
#endif

G
Guy Schalnat 已提交
854
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
855
/* write the sBIT chunk */
856
void /* PRIVATE */
G
Guy Schalnat 已提交
857
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
858
{
859 860 861
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
862
   png_byte buf[4];
A
Andreas Dilger 已提交
863
   png_size_t size;
G
Guy Schalnat 已提交
864

A
Andreas Dilger 已提交
865
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
866
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
867 868
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
869
      png_byte maxbits;
G
Guy Schalnat 已提交
870

871 872
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
873 874
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
875 876 877 878 879
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
880 881 882 883 884 885 886
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
887 888 889 890 891
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
892 893 894 895 896 897
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
898 899 900 901 902
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
903 904 905
      buf[size++] = sbit->alpha;
   }

906
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
907
}
G
Guy Schalnat 已提交
908
#endif
G
Guy Schalnat 已提交
909

G
Guy Schalnat 已提交
910
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
911
/* write the cHRM chunk */
912
#ifdef PNG_FLOATING_POINT_SUPPORTED
913
void /* PRIVATE */
A
Andreas Dilger 已提交
914
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
915 916
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
917
{
918 919 920
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
921
   png_byte buf[32];
922
   png_uint_32 itemp;
G
Guy Schalnat 已提交
923

A
Andreas Dilger 已提交
924
   png_debug(1, "in png_write_cHRM\n");
925
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
926 927 928 929
   if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
       white_x + white_y > 1.0)
   {
      png_warning(png_ptr, "Invalid cHRM white point specified");
930 931
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
932
#endif
G
Guy Schalnat 已提交
933 934
      return;
   }
935
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
936
   png_save_uint_32(buf, itemp);
937
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
938
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
939

940
   if (red_x < 0 ||  red_y < 0 || red_x + red_y > 1.0)
G
Guy Schalnat 已提交
941 942 943 944
   {
      png_warning(png_ptr, "Invalid cHRM red point specified");
      return;
   }
945
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
946
   png_save_uint_32(buf + 8, itemp);
947
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
948
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
949

950
   if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
G
Guy Schalnat 已提交
951 952 953 954
   {
      png_warning(png_ptr, "Invalid cHRM green point specified");
      return;
   }
955
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
956
   png_save_uint_32(buf + 16, itemp);
957
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
958
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
959

960
   if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
G
Guy Schalnat 已提交
961 962 963 964
   {
      png_warning(png_ptr, "Invalid cHRM blue point specified");
      return;
   }
965
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
966
   png_save_uint_32(buf + 24, itemp);
967
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
968
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
969

970
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
971
}
G
Guy Schalnat 已提交
972
#endif
973
#ifdef PNG_FIXED_POINT_SUPPORTED
974
void /* PRIVATE */
975 976 977 978
png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
   png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
   png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
   png_fixed_point blue_y)
979 980 981 982 983 984 985
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
986
   /* each value is saved in 1/100,000ths */
987 988
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
989
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
990 991
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
992
#endif
993 994
      return;
   }
995 996
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
997

998
   if (red_x + red_y > 100000L)
999
   {
1000
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
1001 1002
      return;
   }
1003 1004
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1005

1006
   if (green_x + green_y > 100000L)
1007
   {
1008
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
1009 1010
      return;
   }
1011 1012
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1013

1014
   if (blue_x + blue_y > 100000L)
1015
   {
1016
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
1017 1018
      return;
   }
1019 1020
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1021 1022 1023 1024 1025

   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
}
#endif
#endif
G
Guy Schalnat 已提交
1026

G
Guy Schalnat 已提交
1027
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
1028
/* write the tRNS chunk */
1029
void /* PRIVATE */
G
Guy Schalnat 已提交
1030
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
1031 1032
   int num_trans, int color_type)
{
1033 1034 1035
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
1036 1037
   png_byte buf[6];

A
Andreas Dilger 已提交
1038
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
1039 1040
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1041
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1042 1043 1044 1045
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
1046
      /* write the chunk out as it is */
1047
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
1048 1049 1050 1051
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
1052 1053 1054 1055 1056 1057
      if(tran->gray >= (1 << png_ptr->bit_depth))
      {
         png_warning(png_ptr,
           "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1058
      png_save_uint_16(buf, tran->gray);
1059
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1060 1061 1062 1063 1064 1065 1066
   }
   else if (color_type == PNG_COLOR_TYPE_RGB)
   {
      /* three 16 bit values */
      png_save_uint_16(buf, tran->red);
      png_save_uint_16(buf + 2, tran->green);
      png_save_uint_16(buf + 4, tran->blue);
1067 1068 1069 1070 1071 1072
      if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
         {
            png_warning(png_ptr,
              "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
            return;
         }
1073
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1074
   }
G
Guy Schalnat 已提交
1075 1076
   else
   {
1077
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1078
   }
G
Guy Schalnat 已提交
1079
}
G
Guy Schalnat 已提交
1080
#endif
G
Guy Schalnat 已提交
1081

G
Guy Schalnat 已提交
1082
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1083
/* write the background chunk */
1084
void /* PRIVATE */
G
Guy Schalnat 已提交
1085
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1086
{
1087 1088 1089
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1090 1091
   png_byte buf[6];

A
Andreas Dilger 已提交
1092
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
1093 1094
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1095
      if (
1096
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1097 1098
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1099 1100
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1101 1102 1103 1104
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1105
      buf[0] = back->index;
1106
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1107 1108 1109 1110 1111 1112
   }
   else if (color_type & PNG_COLOR_MASK_COLOR)
   {
      png_save_uint_16(buf, back->red);
      png_save_uint_16(buf + 2, back->green);
      png_save_uint_16(buf + 4, back->blue);
1113 1114 1115 1116 1117 1118
      if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
         {
            png_warning(png_ptr,
              "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
            return;
         }
1119
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1120 1121
   }
   else
G
Guy Schalnat 已提交
1122
   {
1123 1124 1125 1126 1127 1128
      if(back->gray >= (1 << png_ptr->bit_depth))
      {
         png_warning(png_ptr,
           "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1129
      png_save_uint_16(buf, back->gray);
1130
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1131 1132
   }
}
G
Guy Schalnat 已提交
1133
#endif
G
Guy Schalnat 已提交
1134

G
Guy Schalnat 已提交
1135
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1136
/* write the histogram */
1137
void /* PRIVATE */
1138
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1139
{
1140 1141 1142
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1143
   int i;
G
Guy Schalnat 已提交
1144 1145
   png_byte buf[3];

A
Andreas Dilger 已提交
1146
   png_debug(1, "in png_write_hIST\n");
1147
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1148
   {
A
Andreas Dilger 已提交
1149 1150
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1151 1152 1153 1154
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1155
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1156
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1157
   {
G
Guy Schalnat 已提交
1158
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1159
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1160 1161 1162
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1163
#endif
G
Guy Schalnat 已提交
1164

1165 1166
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1167 1168 1169 1170 1171
/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
 * and if invalid, correct the keyword rather than discarding the entire
 * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
 * length, forbids leading or trailing whitespace, multiple internal spaces,
 * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
A
Andreas Dilger 已提交
1172 1173 1174 1175
 *
 * The new_key is allocated to hold the corrected keyword and must be freed
 * by the calling routine.  This avoids problems with trying to write to
 * static keywords without having to have duplicate copies of the strings.
A
Andreas Dilger 已提交
1176
 */
1177
png_size_t /* PRIVATE */
1178
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1179
{
A
Andreas Dilger 已提交
1180
   png_size_t key_len;
1181
   png_charp kp, dp;
A
Andreas Dilger 已提交
1182
   int kflag;
1183
   int kwarn=0;
A
Andreas Dilger 已提交
1184

A
Andreas Dilger 已提交
1185 1186 1187 1188
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1189
   {
1190
      png_warning(png_ptr, "zero length keyword");
1191
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1192
   }
A
Andreas Dilger 已提交
1193 1194 1195

   png_debug1(2, "Keyword to be checked is '%s'\n", key);

1196 1197 1198 1199 1200 1201
   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
   if (*new_key == NULL)
   {
      png_warning(png_ptr, "Out of memory while procesing keyword");
      return ((png_size_t)0);
   }
1202

A
Andreas Dilger 已提交
1203 1204
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1205
   {
1206
      if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1207
      {
1208
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
A
Andreas Dilger 已提交
1209
         char msg[40];
A
Andreas Dilger 已提交
1210

1211
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1212
         png_warning(png_ptr, msg);
1213
#else
1214
         png_warning(png_ptr, "invalid character in keyword");
1215
#endif
A
Andreas Dilger 已提交
1216 1217 1218 1219 1220 1221
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1222
   }
A
Andreas Dilger 已提交
1223
   *dp = '\0';
A
Andreas Dilger 已提交
1224

A
Andreas Dilger 已提交
1225 1226 1227
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1228
   {
1229
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1230 1231 1232 1233 1234 1235

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1236 1237 1238
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1239 1240
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1241
   {
1242
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1243 1244 1245 1246 1247 1248

      while (*kp == ' ')
      {
        kp++;
        key_len--;
      }
A
Andreas Dilger 已提交
1249 1250
   }

A
Andreas Dilger 已提交
1251 1252 1253 1254
   png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);

   /* Remove multiple internal spaces. */
   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
A
Andreas Dilger 已提交
1255
   {
A
Andreas Dilger 已提交
1256
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1257
      {
A
Andreas Dilger 已提交
1258 1259
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1260
      }
A
Andreas Dilger 已提交
1261
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1262 1263
      {
         key_len--;
1264
         kwarn=1;
A
Andreas Dilger 已提交
1265 1266 1267
      }
      else
      {
A
Andreas Dilger 已提交
1268 1269
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1270 1271
      }
   }
A
Andreas Dilger 已提交
1272
   *dp = '\0';
1273 1274
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1275 1276

   if (key_len == 0)
A
Andreas Dilger 已提交
1277
   {
1278 1279
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1280
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1281 1282 1283 1284
   }

   if (key_len > 79)
   {
1285
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1286 1287 1288
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1289

1290
   return (key_len);
A
Andreas Dilger 已提交
1291 1292 1293
}
#endif

G
Guy Schalnat 已提交
1294
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1295
/* write a tEXt chunk */
1296
void /* PRIVATE */
G
Guy Schalnat 已提交
1297
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1298
   png_size_t text_len)
G
Guy Schalnat 已提交
1299
{
1300 1301 1302
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1303
   png_size_t key_len;
1304
   png_charp new_key;
A
Andreas Dilger 已提交
1305 1306 1307 1308

   png_debug(1, "in png_write_tEXt\n");
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1309
      png_warning(png_ptr, "Empty keyword in tEXt chunk");
G
Guy Schalnat 已提交
1310
      return;
A
Andreas Dilger 已提交
1311
   }
G
Guy Schalnat 已提交
1312

A
Andreas Dilger 已提交
1313
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1314
      text_len = 0;
1315 1316
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1317 1318

   /* make sure we include the 0 after the key */
1319
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1320 1321 1322 1323
   /*
    * We leave it to the application to meet PNG-1.0 requirements on the
    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
1324
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1325
    */
1326
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1327
   if (text_len)
A
Andreas Dilger 已提交
1328
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1329

G
Guy Schalnat 已提交
1330
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1331
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1332
}
G
Guy Schalnat 已提交
1333
#endif
G
Guy Schalnat 已提交
1334

G
Guy Schalnat 已提交
1335
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1336
/* write a compressed text chunk */
1337
void /* PRIVATE */
G
Guy Schalnat 已提交
1338
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1339
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1340
{
1341 1342 1343
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1344
   png_size_t key_len;
G
Guy Schalnat 已提交
1345
   char buf[1];
1346
   png_charp new_key;
1347
   compression_state comp;
G
Guy Schalnat 已提交
1348

A
Andreas Dilger 已提交
1349 1350
   png_debug(1, "in png_write_zTXt\n");

1351 1352 1353 1354 1355 1356
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

A
Andreas Dilger 已提交
1357 1358
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1359
      png_warning(png_ptr, "Empty keyword in zTXt chunk");
G
Guy Schalnat 已提交
1360
      return;
A
Andreas Dilger 已提交
1361
   }
A
Andreas Dilger 已提交
1362

A
Andreas Dilger 已提交
1363 1364 1365 1366 1367 1368 1369
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
      png_free(png_ptr, new_key);
      return;
   }

1370 1371
   text_len = png_strlen(text);

A
Andreas Dilger 已提交
1372
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1373

1374
   /* compute the compressed data; do it now for the length */
1375 1376
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1377

1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
   /* write start of chunk */
   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
      (key_len+text_len+2));
   /* write key */
   png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
   buf[0] = (png_byte)compression;
   /* write compression */
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1388

1389 1390 1391 1392
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1393

1394 1395
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1396
void /* PRIVATE */
1397
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1398
    png_charp lang, png_charp lang_key, png_charp text)
1399 1400 1401 1402
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1403
   png_size_t lang_len, key_len, lang_key_len, text_len;
1404 1405 1406
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1407

1408
   png_debug(1, "in png_write_iTXt\n");
G
Guy Schalnat 已提交
1409

1410 1411 1412 1413 1414
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

1415
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1416
   {
1417
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1418 1419
      return;
   }
1420
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1421
   {
1422
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1423
      new_lang = NULL;
1424
      lang_len = 0;
1425
   }
G
Guy Schalnat 已提交
1426

1427 1428 1429 1430 1431 1432
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1433
      text_len = 0;
1434 1435
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1436

1437
   /* compute the compressed data; do it now for the length */
1438 1439
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1440

1441

1442
   /* make sure we include the compression flag, the compression byte,
1443
    * and the NULs after the key, lang, and lang_key parts */
G
Guy Schalnat 已提交
1444

1445 1446 1447 1448 1449 1450 1451
   png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
          (png_uint_32)(
        5 /* comp byte, comp flag, terminators for key, lang and lang_key */
        + key_len
        + lang_len
        + lang_key_len
        + text_len));
G
Guy Schalnat 已提交
1452

1453 1454 1455 1456 1457 1458 1459
   /*
    * We leave it to the application to meet PNG-1.0 requirements on the
    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
    */
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470

   /* set the compression flag */
   if (compression == PNG_ITXT_COMPRESSION_NONE || \
       compression == PNG_TEXT_COMPRESSION_NONE)
       cbuf[0] = 0;
   else /* compression == PNG_ITXT_COMPRESSION_zTXt */
       cbuf[0] = 1;
   /* set the compression method */
   cbuf[1] = 0;
   png_write_chunk_data(png_ptr, cbuf, 2);

1471 1472 1473
   cbuf[0] = 0;
   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
1474
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1475 1476

   png_write_chunk_end(png_ptr);
1477
   png_free(png_ptr, new_key);
1478 1479
   if (new_lang)
     png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1480
}
G
Guy Schalnat 已提交
1481
#endif
G
Guy Schalnat 已提交
1482

A
Andreas Dilger 已提交
1483 1484
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1485
void /* PRIVATE */
1486
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1487 1488
   int unit_type)
{
1489 1490 1491
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1492 1493
   png_byte buf[9];

A
Andreas Dilger 已提交
1494 1495 1496
   png_debug(1, "in png_write_oFFs\n");
   if (unit_type >= PNG_OFFSET_LAST)
      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
G
Guy Schalnat 已提交
1497

1498 1499
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1500
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1501

1502
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1503
}
G
Guy Schalnat 已提交
1504
#endif
G
Guy Schalnat 已提交
1505

A
Andreas Dilger 已提交
1506
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1507
/* write the pCAL chunk (described in the PNG extensions document) */
1508
void /* PRIVATE */
A
Andreas Dilger 已提交
1509 1510 1511
png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
   png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
{
1512 1513 1514
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1515
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1516 1517
   png_uint_32p params_len;
   png_byte buf[10];
1518
   png_charp new_purpose;
A
Andreas Dilger 已提交
1519 1520 1521 1522 1523 1524 1525
   int i;

   png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
   if (type >= PNG_EQUATION_LAST)
      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");

   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
1526
   png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
A
Andreas Dilger 已提交
1527
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1528
   png_debug1(3, "pCAL units length = %d\n", (int)units_len);
A
Andreas Dilger 已提交
1529 1530
   total_len = purpose_len + units_len + 10;

1531
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
1532
      *png_sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1533 1534 1535 1536 1537 1538

   /* Find the length of each parameter, making sure we don't count the
      null terminator for the last parameter. */
   for (i = 0; i < nparams; i++)
   {
      params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
1539
      png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
A
Andreas Dilger 已提交
1540 1541 1542
      total_len += (png_size_t)params_len[i];
   }

1543
   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1544
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1545
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
   png_save_int_32(buf, X0);
   png_save_int_32(buf + 4, X1);
   buf[8] = (png_byte)type;
   buf[9] = (png_byte)nparams;
   png_write_chunk_data(png_ptr, buf, (png_size_t)10);
   png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);

   png_free(png_ptr, new_purpose);

   for (i = 0; i < nparams; i++)
   {
      png_write_chunk_data(png_ptr, (png_bytep)params[i],
         (png_size_t)params_len[i]);
   }

1561
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1562 1563 1564 1565
   png_write_chunk_end(png_ptr);
}
#endif

1566 1567
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1568
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1569
void /* PRIVATE */
1570
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1571 1572 1573 1574 1575 1576
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];
1577
   png_byte bunit = (png_byte)unit;
1578 1579 1580

   png_debug(1, "in png_write_sCAL\n");

1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
#if defined(_WIN32_WCE)
/* sprintf() function is not supported on WindowsCE */
   {
      wchar_t wc_buf[32];
      swprintf(wc_buf, TEXT("%12.12e"), width);
      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL);
      swprintf(wc_buf, TEXT("%12.12e"), height);
      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL);
   }
#else
1591 1592
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1593
#endif
1594
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1595

1596
   png_debug1(3, "sCAL total length = %d\n", (int)total_len);
1597
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1598
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1599 1600
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1601 1602 1603

   png_write_chunk_end(png_ptr);
}
1604 1605
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1606
void /* PRIVATE */
1607
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1608 1609 1610 1611 1612 1613 1614
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];
1615
   png_byte bunit = unit;
1616

1617
   png_debug(1, "in png_write_sCAL_s\n");
1618

1619 1620
   png_strcpy(wbuf,(const char *)width);
   png_strcpy(hbuf,(const char *)height);
1621
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1622 1623 1624

   png_debug1(3, "sCAL total length = %d\n", total_len);
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1625
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1626 1627
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1628 1629 1630 1631

   png_write_chunk_end(png_ptr);
}
#endif
1632 1633
#endif
#endif
1634

A
Andreas Dilger 已提交
1635 1636
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1637
void /* PRIVATE */
A
Andreas Dilger 已提交
1638 1639
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1640 1641
   int unit_type)
{
1642 1643 1644
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1645 1646
   png_byte buf[9];

A
Andreas Dilger 已提交
1647 1648 1649
   png_debug(1, "in png_write_pHYs\n");
   if (unit_type >= PNG_RESOLUTION_LAST)
      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
G
Guy Schalnat 已提交
1650

A
Andreas Dilger 已提交
1651 1652
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1653
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1654

1655
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1656
}
G
Guy Schalnat 已提交
1657
#endif
G
Guy Schalnat 已提交
1658

G
Guy Schalnat 已提交
1659
#if defined(PNG_WRITE_tIME_SUPPORTED)
1660 1661 1662
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1663
void /* PRIVATE */
G
Guy Schalnat 已提交
1664
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1665
{
1666 1667 1668
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1669 1670
   png_byte buf[7];

A
Andreas Dilger 已提交
1671
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1672 1673 1674 1675 1676 1677 1678 1679
   if (mod_time->month  > 12 || mod_time->month  < 1 ||
       mod_time->day    > 31 || mod_time->day    < 1 ||
       mod_time->hour   > 23 || mod_time->second > 60)
   {
      png_warning(png_ptr, "Invalid time specified for tIME chunk");
      return;
   }

G
Guy Schalnat 已提交
1680 1681 1682 1683 1684 1685 1686
   png_save_uint_16(buf, mod_time->year);
   buf[2] = mod_time->month;
   buf[3] = mod_time->day;
   buf[4] = mod_time->hour;
   buf[5] = mod_time->minute;
   buf[6] = mod_time->second;

1687
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1688
}
G
Guy Schalnat 已提交
1689
#endif
G
Guy Schalnat 已提交
1690 1691

/* initializes the row writing capability of libpng */
1692
void /* PRIVATE */
G
Guy Schalnat 已提交
1693
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1694
{
1695
#ifdef PNG_USE_LOCAL_ARRAYS
1696
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1697

1698 1699
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1700

1701 1702
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1703

1704 1705
   /* start of interlace block in the y direction */
   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1706

1707 1708
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1709
#endif
1710

A
Andreas Dilger 已提交
1711 1712 1713
   png_size_t buf_size;

   png_debug(1, "in png_write_start_row\n");
1714 1715
   buf_size = (png_size_t)(PNG_ROWBYTES(
      png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
A
Andreas Dilger 已提交
1716

G
Guy Schalnat 已提交
1717
   /* set up row buffer */
1718
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1719
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1720 1721 1722

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1723
   {
A
Andreas Dilger 已提交
1724
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1725
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1726
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1727 1728
   }

A
Andreas Dilger 已提交
1729
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1730 1731 1732
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1733
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1734
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1735 1736 1737

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1738
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1739
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1740
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1741 1742 1743 1744
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1745 1746
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1747
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1748 1749 1750 1751
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1752
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1753
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1754
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1755
      }
G
Guy Schalnat 已提交
1756 1757
   }

1758
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1759
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1760
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1761 1762 1763 1764 1765
   {
      if (!(png_ptr->transformations & PNG_INTERLACE))
      {
         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
            png_pass_ystart[0]) / png_pass_yinc[0];
A
Andreas Dilger 已提交
1766 1767
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1768 1769 1770 1771 1772 1773 1774 1775
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1776
#endif
G
Guy Schalnat 已提交
1777
   {
G
Guy Schalnat 已提交
1778 1779 1780
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1781 1782
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1783 1784
}

A
Andreas Dilger 已提交
1785
/* Internal use only.  Called when finished processing a row of data. */
1786
void /* PRIVATE */
G
Guy Schalnat 已提交
1787
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1788
{
1789
#ifdef PNG_USE_LOCAL_ARRAYS
1790
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1791

1792 1793
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1794

1795 1796
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1797

1798 1799
   /* start of interlace block in the y direction */
   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1800

1801 1802
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1803
#endif
1804

G
Guy Schalnat 已提交
1805 1806
   int ret;

A
Andreas Dilger 已提交
1807
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1808 1809
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1810

G
Guy Schalnat 已提交
1811
   /* see if we are done */
G
Guy Schalnat 已提交
1812
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1813
      return;
G
Guy Schalnat 已提交
1814

1815
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831
   /* if interlaced, go to next pass */
   if (png_ptr->interlaced)
   {
      png_ptr->row_number = 0;
      if (png_ptr->transformations & PNG_INTERLACE)
      {
         png_ptr->pass++;
      }
      else
      {
         /* loop until we find a non-zero width or height pass */
         do
         {
            png_ptr->pass++;
            if (png_ptr->pass >= 7)
               break;
G
Guy Schalnat 已提交
1832
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1833 1834 1835 1836 1837 1838 1839
               png_pass_inc[png_ptr->pass] - 1 -
               png_pass_start[png_ptr->pass]) /
               png_pass_inc[png_ptr->pass];
            png_ptr->num_rows = (png_ptr->height +
               png_pass_yinc[png_ptr->pass] - 1 -
               png_pass_ystart[png_ptr->pass]) /
               png_pass_yinc[png_ptr->pass];
G
Guy Schalnat 已提交
1840 1841
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1842 1843 1844 1845
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1846
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1847
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1848
      {
A
Andreas Dilger 已提交
1849
         if (png_ptr->prev_row != NULL)
1850
            png_memset(png_ptr->prev_row, 0,
1851 1852
               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
               png_ptr->usr_bit_depth,png_ptr->width))+1);
G
Guy Schalnat 已提交
1853
         return;
G
Guy Schalnat 已提交
1854
      }
G
Guy Schalnat 已提交
1855
   }
1856
#endif
G
Guy Schalnat 已提交
1857 1858 1859 1860 1861 1862

   /* if we get here, we've just written the last row, so we need
      to flush the compressor */
   do
   {
      /* tell the compressor we are done */
A
Andreas Dilger 已提交
1863
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1864
      /* check for an error */
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
      if (ret == Z_OK)
      {
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
         {
            png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
            png_ptr->zstream.next_out = png_ptr->zbuf;
            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         }
      }
      else if (ret != Z_STREAM_END)
G
Guy Schalnat 已提交
1876
      {
A
Andreas Dilger 已提交
1877
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1878
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1879
         else
G
Guy Schalnat 已提交
1880
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1881 1882 1883 1884
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1885
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1886 1887
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1888
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1889 1890
   }

A
Andreas Dilger 已提交
1891
   deflateReset(&png_ptr->zstream);
1892
   png_ptr->zstream.data_type = Z_BINARY;
G
Guy Schalnat 已提交
1893 1894
}

G
Guy Schalnat 已提交
1895
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1896 1897 1898 1899 1900 1901 1902
/* Pick out the correct pixels for the interlace pass.
 * The basic idea here is to go through the row with a source
 * pointer and a destination pointer (sp and dp), and copy the
 * correct pixels for the pass.  As the row gets compacted,
 * sp will always be >= dp, so we should never overwrite anything.
 * See the default: case for the easiest code to understand.
 */
1903
void /* PRIVATE */
G
Guy Schalnat 已提交
1904
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1905
{
1906
#ifdef PNG_USE_LOCAL_ARRAYS
1907
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1908

1909 1910
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1911

1912 1913
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1914
#endif
1915

A
Andreas Dilger 已提交
1916
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1917
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1918 1919 1920 1921 1922
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1923
   {
1924
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1925
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1926
      {
G
Guy Schalnat 已提交
1927 1928
         case 1:
         {
G
Guy Schalnat 已提交
1929 1930
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1931 1932 1933
            int shift;
            int d;
            int value;
1934 1935
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1936 1937 1938 1939

            dp = row;
            d = 0;
            shift = 7;
1940
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1941 1942 1943
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1944
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1945 1946 1947 1948 1949
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1950
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1951 1952 1953 1954 1955 1956 1957
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1958
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1959 1960 1961
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1962
         {
G
Guy Schalnat 已提交
1963 1964
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1965 1966 1967
            int shift;
            int d;
            int value;
1968 1969
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1970 1971 1972 1973

            dp = row;
            shift = 6;
            d = 0;
1974
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1975 1976 1977
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1978
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1979 1980 1981 1982 1983
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1984
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1985 1986 1987 1988 1989 1990
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1991
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1992 1993 1994 1995
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1996 1997
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1998
            int shift;
G
Guy Schalnat 已提交
1999 2000
            int d;
            int value;
2001 2002
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2003 2004 2005 2006

            dp = row;
            shift = 4;
            d = 0;
2007
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2008 2009 2010
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
2011
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
2012 2013 2014 2015
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
2016 2017
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2018 2019 2020 2021 2022 2023
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
2024
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2025 2026 2027 2028
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
2029 2030
            png_bytep sp;
            png_bytep dp;
2031 2032
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
2033
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
2034

G
Guy Schalnat 已提交
2035
            /* start at the beginning */
G
Guy Schalnat 已提交
2036 2037 2038 2039 2040
            dp = row;
            /* find out how many bytes each pixel takes up */
            pixel_bytes = (row_info->pixel_depth >> 3);
            /* loop through the row, only looking at the pixels that
               matter */
2041
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2042 2043 2044
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
2045
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
2046 2047
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
2048
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
2049 2050 2051
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
2052
            break;
G
Guy Schalnat 已提交
2053 2054 2055 2056 2057 2058 2059
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
2060 2061
         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
            row_info->width);
G
Guy Schalnat 已提交
2062 2063
   }
}
G
Guy Schalnat 已提交
2064
#endif
G
Guy Schalnat 已提交
2065

A
Andreas Dilger 已提交
2066 2067
/* This filters the row, chooses which filter to use, if it has not already
 * been specified by the application, and then writes the row out with the
2068 2069
 * chosen filter.
 */
2070
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
A
Andreas Dilger 已提交
2071
#define PNG_HISHIFT 10
2072 2073
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2074
void /* PRIVATE */
G
Guy Schalnat 已提交
2075
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2076
{
G
Guy Schalnat 已提交
2077
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2078
   png_uint_32 mins, bpp;
2079
   png_byte filter_to_do = png_ptr->do_filter;
2080 2081 2082 2083
   png_uint_32 row_bytes = row_info->rowbytes;
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   int num_p_filters = (int)png_ptr->num_prev_filters;
#endif
G
Guy Schalnat 已提交
2084

A
Andreas Dilger 已提交
2085
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
2086
   /* find out how many bytes offset each pixel is */
2087
   bpp = (row_info->pixel_depth + 7) >> 3;
G
Guy Schalnat 已提交
2088 2089 2090

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
2091 2092 2093 2094
   mins = PNG_MAXSUM;

   /* The prediction method we use is to find which method provides the
    * smallest value when summing the absolute values of the distances
2095
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2096
    * as the "minimum sum of absolute differences" heuristic.  Other
2097
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2098
    * (experimental and can in theory improve compression), and the "zlib
2099 2100 2101
    * predictive" method (not implemented yet), which does test compressions
    * of lines using different filter methods, and then chooses the
    * (series of) filter(s) that give minimum compressed data size (VERY
A
Andreas Dilger 已提交
2102
    * computationally expensive).
2103 2104 2105 2106 2107 2108 2109 2110 2111
    *
    * GRR 980525:  consider also
    *   (1) minimum sum of absolute differences from running average (i.e.,
    *       keep running sum of non-absolute differences & count of bytes)
    *       [track dispersion, too?  restart average if dispersion too large?]
    *  (1b) minimum sum of absolute differences from sliding average, probably
    *       with window size <= deflate window (usually 32K)
    *   (2) minimum sum of squared differences from zero or running average
    *       (i.e., ~ root-mean-square approach)
A
Andreas Dilger 已提交
2112
    */
G
Guy Schalnat 已提交
2113

2114

G
Guy Schalnat 已提交
2115
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2116 2117
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2118
   if ((filter_to_do & PNG_FILTER_NONE) &&
2119
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2120
   {
G
Guy Schalnat 已提交
2121 2122
      png_bytep rp;
      png_uint_32 sum = 0;
2123
      png_uint_32 i;
A
Andreas Dilger 已提交
2124
      int v;
G
Guy Schalnat 已提交
2125

2126
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2127 2128 2129 2130
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2131 2132 2133 2134 2135

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2136
         int j;
A
Andreas Dilger 已提交
2137 2138 2139 2140
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */

         /* Reduce the sum if we match any of the previous rows */
2141
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2142
         {
2143
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2144
            {
2145
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2146
                  PNG_WEIGHT_SHIFT;
2147
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166
                  PNG_WEIGHT_SHIFT;
            }
         }

         /* Factor in the cost of this filter (this is here for completeness,
          * but it makes no sense to have a "cost" for the NONE filter, as
          * it has the minimum possible computational cost - none).
          */
         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
            PNG_COST_SHIFT;
         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
            PNG_COST_SHIFT;

         if (sumhi > PNG_HIMASK)
            sum = PNG_MAXSUM;
         else
            sum = (sumhi << PNG_HISHIFT) + sumlo;
      }
#endif
G
Guy Schalnat 已提交
2167 2168
      mins = sum;
   }
G
Guy Schalnat 已提交
2169

G
Guy Schalnat 已提交
2170
   /* sub filter */
2171 2172 2173 2174
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2175
      png_uint_32 i;
2176 2177 2178 2179 2180
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2181
      for (lp = row_buf + 1; i < row_bytes;
2182 2183 2184 2185 2186 2187 2188 2189
         i++, rp++, lp++, dp++)
      {
         *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
      }
      best_row = png_ptr->sub_row;
   }

   else if (filter_to_do & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
2190 2191
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2192
      png_uint_32 sum = 0, lmins = mins;
2193
      png_uint_32 i;
A
Andreas Dilger 已提交
2194 2195 2196
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2197
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2198 2199 2200 2201 2202
       * would reduce the sum of this filter, so that we can do the
       * early exit comparison without scaling the sum each time.
       */
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2203
         int j;
A
Andreas Dilger 已提交
2204 2205 2206 2207
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2208
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2209
         {
2210
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2211
            {
2212
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2213
                  PNG_WEIGHT_SHIFT;
2214
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229
                  PNG_WEIGHT_SHIFT;
            }
         }

         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
            PNG_COST_SHIFT;
         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
            PNG_COST_SHIFT;

         if (lmhi > PNG_HIMASK)
            lmins = PNG_MAXSUM;
         else
            lmins = (lmhi << PNG_HISHIFT) + lmlo;
      }
#endif
G
Guy Schalnat 已提交
2230

G
Guy Schalnat 已提交
2231 2232 2233 2234
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2235

G
Guy Schalnat 已提交
2236 2237
         sum += (v < 128) ? v : 256 - v;
      }
2238
      for (lp = row_buf + 1; i < row_bytes;
2239
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2240 2241 2242 2243
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2244 2245 2246 2247 2248 2249 2250 2251

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
      }

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2252
         int j;
A
Andreas Dilger 已提交
2253 2254 2255 2256
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2257
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2258
         {
2259
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2260
            {
2261
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2262
                  PNG_WEIGHT_SHIFT;
2263
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
                  PNG_WEIGHT_SHIFT;
            }
         }

         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
            PNG_COST_SHIFT;
         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
            PNG_COST_SHIFT;

         if (sumhi > PNG_HIMASK)
            sum = PNG_MAXSUM;
         else
            sum = (sumhi << PNG_HISHIFT) + sumlo;
G
Guy Schalnat 已提交
2277
      }
A
Andreas Dilger 已提交
2278 2279
#endif

G
Guy Schalnat 已提交
2280 2281 2282 2283 2284
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2285 2286
   }

G
Guy Schalnat 已提交
2287
   /* up filter */
2288 2289 2290
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2291
      png_uint_32 i;
2292 2293

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2294
           pp = prev_row + 1; i < row_bytes;
2295 2296 2297 2298 2299 2300 2301 2302
           i++, rp++, pp++, dp++)
      {
         *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
      }
      best_row = png_ptr->up_row;
   }

   else if (filter_to_do & PNG_FILTER_UP)
G
Guy Schalnat 已提交
2303 2304
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2305
      png_uint_32 sum = 0, lmins = mins;
2306
      png_uint_32 i;
A
Andreas Dilger 已提交
2307 2308
      int v;

2309

A
Andreas Dilger 已提交
2310 2311 2312
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2313
         int j;
A
Andreas Dilger 已提交
2314 2315 2316 2317
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2318
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2319
         {
2320
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2321
            {
2322
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2323
                  PNG_WEIGHT_SHIFT;
2324
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339
                  PNG_WEIGHT_SHIFT;
            }
         }

         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
            PNG_COST_SHIFT;
         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
            PNG_COST_SHIFT;

         if (lmhi > PNG_HIMASK)
            lmins = PNG_MAXSUM;
         else
            lmins = (lmhi << PNG_HISHIFT) + lmlo;
      }
#endif
G
Guy Schalnat 已提交
2340

G
Guy Schalnat 已提交
2341
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2342
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2343
      {
2344
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2345 2346

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2347 2348 2349

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2350
      }
A
Andreas Dilger 已提交
2351 2352 2353 2354

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2355
         int j;
A
Andreas Dilger 已提交
2356 2357 2358 2359
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2360
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2361
         {
2362
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2363
            {
2364
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2365
                  PNG_WEIGHT_SHIFT;
2366
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
                  PNG_WEIGHT_SHIFT;
            }
         }

         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
            PNG_COST_SHIFT;
         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
            PNG_COST_SHIFT;

         if (sumhi > PNG_HIMASK)
            sum = PNG_MAXSUM;
         else
            sum = (sumhi << PNG_HISHIFT) + sumlo;
      }
#endif

G
Guy Schalnat 已提交
2383 2384 2385 2386 2387 2388 2389 2390
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2391 2392 2393
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2394
      png_uint_32 i;
2395
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2396
           pp = prev_row + 1; i < bpp; i++)
2397
      {
2398
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2399
      }
2400
      for (lp = row_buf + 1; i < row_bytes; i++)
2401
      {
2402 2403
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2404 2405 2406 2407 2408
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2409
   {
G
Guy Schalnat 已提交
2410
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2411
      png_uint_32 sum = 0, lmins = mins;
2412
      png_uint_32 i;
A
Andreas Dilger 已提交
2413 2414 2415 2416 2417
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2418
         int j;
A
Andreas Dilger 已提交
2419 2420 2421 2422
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2423
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2424
         {
2425
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2426
            {
2427
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2428
                  PNG_WEIGHT_SHIFT;
2429
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
                  PNG_WEIGHT_SHIFT;
            }
         }

         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
            PNG_COST_SHIFT;
         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
            PNG_COST_SHIFT;

         if (lmhi > PNG_HIMASK)
            lmins = PNG_MAXSUM;
         else
            lmins = (lmhi << PNG_HISHIFT) + lmlo;
      }
#endif
G
Guy Schalnat 已提交
2445

G
Guy Schalnat 已提交
2446
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2447
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2448
      {
2449
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2450

G
Guy Schalnat 已提交
2451 2452
         sum += (v < 128) ? v : 256 - v;
      }
2453
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2454
      {
2455
         v = *dp++ =
2456
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2457

G
Guy Schalnat 已提交
2458
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2459 2460 2461

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2462
      }
A
Andreas Dilger 已提交
2463 2464 2465 2466

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2467
         int j;
A
Andreas Dilger 已提交
2468 2469 2470 2471
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2472
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2473
         {
2474
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2475
            {
2476
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2477
                  PNG_WEIGHT_SHIFT;
2478
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494
                  PNG_WEIGHT_SHIFT;
            }
         }

         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
            PNG_COST_SHIFT;
         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
            PNG_COST_SHIFT;

         if (sumhi > PNG_HIMASK)
            sum = PNG_MAXSUM;
         else
            sum = (sumhi << PNG_HISHIFT) + sumlo;
      }
#endif

G
Guy Schalnat 已提交
2495 2496 2497 2498 2499 2500
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2501

A
Andreas Dilger 已提交
2502
   /* Paeth filter */
2503 2504 2505
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2506
      png_uint_32 i;
2507
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2508
           pp = prev_row + 1; i < bpp; i++)
2509
      {
2510
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2511 2512
      }

2513
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2514 2515 2516
      {
         int a, b, c, pa, pb, pc, p;

2517 2518 2519
         b = *pp++;
         c = *cp++;
         a = *lp++;
2520

2521 2522
         p = b - c;
         pc = a - c;
2523 2524

#ifdef PNG_USE_ABS
2525 2526 2527
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2528
#else
2529 2530 2531
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2532 2533 2534 2535
#endif

         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;

2536
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2537 2538 2539 2540 2541
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2542 2543
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2544
      png_uint_32 sum = 0, lmins = mins;
2545
      png_uint_32 i;
A
Andreas Dilger 已提交
2546 2547 2548 2549 2550
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2551
         int j;
A
Andreas Dilger 已提交
2552 2553 2554 2555
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2556
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2557
         {
2558
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2559
            {
2560
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2561
                  PNG_WEIGHT_SHIFT;
2562
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
                  PNG_WEIGHT_SHIFT;
            }
         }

         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
            PNG_COST_SHIFT;
         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
            PNG_COST_SHIFT;

         if (lmhi > PNG_HIMASK)
            lmins = PNG_MAXSUM;
         else
            lmins = (lmhi << PNG_HISHIFT) + lmlo;
      }
#endif
G
Guy Schalnat 已提交
2578

G
Guy Schalnat 已提交
2579
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2580
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2581
      {
2582
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2583

G
Guy Schalnat 已提交
2584 2585
         sum += (v < 128) ? v : 256 - v;
      }
2586

2587
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2588 2589
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2590

2591 2592 2593
         b = *pp++;
         c = *cp++;
         a = *lp++;
2594 2595

#ifndef PNG_SLOW_PAETH
2596 2597
         p = b - c;
         pc = a - c;
2598
#ifdef PNG_USE_ABS
2599 2600 2601
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2602
#else
2603 2604 2605
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2606 2607 2608
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2609
         p = a + b - c;
2610 2611 2612
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2613 2614 2615 2616 2617 2618
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2619
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2620

2621
         v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
G
Guy Schalnat 已提交
2622

G
Guy Schalnat 已提交
2623
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2624 2625 2626

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2627
      }
A
Andreas Dilger 已提交
2628 2629 2630 2631

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2632
         int j;
A
Andreas Dilger 已提交
2633 2634 2635 2636
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2637
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2638
         {
2639
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2640
            {
2641
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2642
                  PNG_WEIGHT_SHIFT;
2643
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659
                  PNG_WEIGHT_SHIFT;
            }
         }

         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
            PNG_COST_SHIFT;
         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
            PNG_COST_SHIFT;

         if (sumhi > PNG_HIMASK)
            sum = PNG_MAXSUM;
         else
            sum = (sumhi << PNG_HISHIFT) + sumlo;
      }
#endif

G
Guy Schalnat 已提交
2660 2661 2662 2663
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2664 2665
   }

A
Andreas Dilger 已提交
2666
   /* Do the actual writing of the filtered row data from the chosen filter. */
2667

G
Guy Schalnat 已提交
2668
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2669 2670 2671 2672 2673

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   /* Save the type of filter we picked this time for future calculations */
   if (png_ptr->num_prev_filters > 0)
   {
2674 2675
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2676
      {
2677
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2678
      }
2679
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2680 2681
   }
#endif
G
Guy Schalnat 已提交
2682
}
G
Guy Schalnat 已提交
2683

G
Guy Schalnat 已提交
2684

A
Andreas Dilger 已提交
2685
/* Do the actual writing of a previously filtered row. */
2686
void /* PRIVATE */
G
Guy Schalnat 已提交
2687 2688
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2689 2690
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2691
   /* set up the zlib input buffer */
2692

A
Andreas Dilger 已提交
2693 2694
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2695 2696
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2697
   {
G
Guy Schalnat 已提交
2698
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2699

G
Guy Schalnat 已提交
2700
      /* compress the data */
A
Andreas Dilger 已提交
2701
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2702 2703 2704
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2705
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2706
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2707 2708 2709
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2710

G
Guy Schalnat 已提交
2711
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2712
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2713 2714 2715
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2716 2717
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2718 2719
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2720
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2721

G
Guy Schalnat 已提交
2722
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2723
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2724 2725 2726 2727 2728 2729 2730 2731
   {
      png_bytep tptr;

      tptr = png_ptr->prev_row;
      png_ptr->prev_row = png_ptr->row_buf;
      png_ptr->row_buf = tptr;
   }

G
Guy Schalnat 已提交
2732 2733
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2734

G
Guy Schalnat 已提交
2735 2736 2737 2738 2739 2740 2741
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
   png_ptr->flush_rows++;

   if (png_ptr->flush_dist > 0 &&
       png_ptr->flush_rows >= png_ptr->flush_dist)
   {
      png_write_flush(png_ptr);
G
Guy Schalnat 已提交
2742
   }
2743
#endif
G
Guy Schalnat 已提交
2744
}
2745
#endif /* PNG_WRITE_SUPPORTED */