pngwutil.c 84.1 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.4.0 [October 26, 2008]
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2008 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
#include "png.h"
12
#ifdef PNG_WRITE_SUPPORTED
13
#include "pngpriv.h"
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);
}

28
#if defined(PNG_SAVE_INT_32_SUPPORTED)
A
Andreas Dilger 已提交
29
/* The png_save_int_32 function assumes integers are stored in two's
30 31 32
 * complement format.  If this isn't the case, then this routine needs to
 * be modified to write data in two's complement format.
 */
33
void PNGAPI
A
Andreas Dilger 已提交
34
png_save_int_32(png_bytep buf, png_int_32 i)
G
Guy Schalnat 已提交
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
#endif
G
Guy Schalnat 已提交
42

43 44 45 46
/* 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.
 */
47
void PNGAPI
48
png_save_uint_16(png_bytep buf, unsigned int i)
G
Guy Schalnat 已提交
49 50 51 52 53
{
   buf[0] = (png_byte)((i >> 8) & 0xff);
   buf[1] = (png_byte)(i & 0xff);
}

54 55 56 57 58 59 60 61 62 63
/* 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
 * bytes have already been written.
 */
void PNGAPI
png_write_sig(png_structp png_ptr)
{
   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
64 65 66 67 68 69

#ifdef PNG_IO_STATE_SUPPORTED
   /* inform the I/O callback that the signature is being written */
   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;
#endif

70 71
   /* write the rest of the 8 byte signature */
   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
72
      (png_size_t)(8 - png_ptr->sig_bytes));
73
   if (png_ptr->sig_bytes < 3)
74 75 76
      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
}

A
Andreas Dilger 已提交
77
/* Write a PNG chunk all at once.  The type is an array of ASCII characters
78 79 80 81 82 83 84 85
 * 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.
 */
86
void PNGAPI
A
Andreas Dilger 已提交
87
png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
A
Andreas Dilger 已提交
88
   png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
89
{
90
   if (png_ptr == NULL) return;
A
Andreas Dilger 已提交
91
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
92
   png_write_chunk_data(png_ptr, data, (png_size_t)length);
A
Andreas Dilger 已提交
93
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
94 95
}

A
Andreas Dilger 已提交
96
/* Write the start of a PNG chunk.  The type is the chunk type.
97 98 99
 * The total_length is the sum of the lengths of all the data you will be
 * passing in png_write_chunk_data().
 */
100
void PNGAPI
A
Andreas Dilger 已提交
101 102
png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
   png_uint_32 length)
G
Guy Schalnat 已提交
103
{
104 105 106 107 108 109 110 111
   png_byte buf[8];

#ifdef PNG_IO_STATE_SUPPORTED
   /* Inform the I/O callback that the chunk header is being written.
    * PNG_IO_CHUNK_HDR requires a single I/O call.
    */
   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;
#endif
A
Andreas Dilger 已提交
112

113
   png_debug2(0, "Writing %s chunk, length = %lu", chunk_name,
114 115 116
      (unsigned long)length);
   if (png_ptr == NULL) return;

117
   /* write the length and the chunk name */
A
Andreas Dilger 已提交
118
   png_save_uint_32(buf, length);
119
   png_memcpy(buf + 4, chunk_name, 4);
120
   png_write_data(png_ptr, buf, (png_size_t)8);
121 122
   /* put the chunk name into png_ptr->chunk_name */
   png_memcpy(png_ptr->chunk_name, chunk_name, 4);
G
Guy Schalnat 已提交
123 124
   /* reset the crc and run it over the chunk name */
   png_reset_crc(png_ptr);
125 126 127 128 129 130 131 132
   png_calculate_crc(png_ptr, chunk_name, 4);

#ifdef PNG_IO_STATE_SUPPORTED
   /* Inform the I/O callback that chunk data will (possibly) be written.
    * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
    */
   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;
#endif
G
Guy Schalnat 已提交
133 134
}

A
Andreas Dilger 已提交
135
/* Write the data of a PNG chunk started with png_write_chunk_start().
136 137 138 139
 * 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().
 */
140
void PNGAPI
A
Andreas Dilger 已提交
141
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
142
{
A
Andreas Dilger 已提交
143
   /* write the data, and run the CRC over it */
144
   if (png_ptr == NULL) return;
A
Andreas Dilger 已提交
145
   if (data != NULL && length > 0)
G
Guy Schalnat 已提交
146
   {
G
Guy Schalnat 已提交
147
      png_write_data(png_ptr, data, length);
148 149 150 151
      /* update the CRC after writing the data,
       * in case that the user I/O routine alters it.
       */
      png_calculate_crc(png_ptr, data, length);
G
Guy Schalnat 已提交
152 153 154
   }
}

A
Andreas Dilger 已提交
155
/* Finish a chunk started with png_write_chunk_start(). */
156
void PNGAPI
G
Guy Schalnat 已提交
157
png_write_chunk_end(png_structp png_ptr)
G
Guy Schalnat 已提交
158
{
A
Andreas Dilger 已提交
159 160
   png_byte buf[4];

161 162
   if (png_ptr == NULL) return;

163 164 165 166 167 168 169 170
#ifdef PNG_IO_STATE_SUPPORTED
   /* Inform the I/O callback that the chunk CRC is being written.
    * PNG_IO_CHUNK_CRC requires a single I/O function call.
    */
   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;
#endif

   /* write the crc in a single operation */
A
Andreas Dilger 已提交
171 172
   png_save_uint_32(buf, png_ptr->crc);

173
   png_write_data(png_ptr, buf, (png_size_t)4);
G
Guy Schalnat 已提交
174 175
}

176
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
/*
 * 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 */
194
static int /* PRIVATE */
195 196 197 198 199 200
png_text_compress(png_structp png_ptr,
        png_charp text, png_size_t text_len, int compression,
        compression_state *comp)
{
   int ret;

201 202
   comp->num_output_ptr = 0;
   comp->max_output_ptr = 0;
203 204
   comp->output_ptr = NULL;
   comp->input = NULL;
205
   comp->input_len = 0;
206 207 208 209 210 211

   /* we may just want to pass the text right through */
   if (compression == PNG_TEXT_COMPRESSION_NONE)
   {
       comp->input = text;
       comp->input_len = text_len;
212
       return((int)text_len);
213 214 215 216
   }

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
217
#if !defined(PNG_NO_STDIO)
218
      char msg[50];
219
      png_snprintf(msg, 50, "Unknown compression type %d", compression);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
      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 */
261
      if (!(png_ptr->zstream.avail_out))
262 263 264 265 266 267 268 269 270 271 272 273 274 275
      {
         /* 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,
276 277
                  (png_size_t)
                  (comp->max_output_ptr * png_sizeof(png_charpp)));
278
               png_memcpy(comp->output_ptr, old_ptr, old_max
279
                  * png_sizeof(png_charp));
280 281 282 283
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
284 285
                  (png_size_t)
                  (comp->max_output_ptr * png_sizeof(png_charp)));
286 287 288
         }

         /* save the data */
289
         comp->output_ptr[comp->num_output_ptr] =
290 291
            (png_charp)png_malloc(png_ptr,
            png_ptr->zbuf_size);
292 293 294
         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
            png_ptr->zbuf_size);
         comp->num_output_ptr++;
295 296 297 298 299 300 301 302 303 304 305 306 307 308

         /* 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);

309
      if (ret == Z_OK)
310
      {
311 312
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
313
         {
314 315
            /* check to make sure our output array has room */
            if (comp->num_output_ptr >= comp->max_output_ptr)
316
            {
317 318 319 320 321 322 323 324 325 326 327
               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,
328 329
                     (png_size_t)(comp->max_output_ptr *
                     png_sizeof(png_charp)));
330
                  png_memcpy(comp->output_ptr, old_ptr,
331
                     old_max * png_sizeof(png_charp));
332 333 334 335
                  png_free(png_ptr, old_ptr);
               }
               else
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
336 337
                     (png_size_t)(comp->max_output_ptr *
                     png_sizeof(png_charp)));
338 339
            }

340 341
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
342 343
               (png_charp)png_malloc(png_ptr,
               (png_size_t)png_ptr->zbuf_size);
344 345 346
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
347

348 349 350 351 352 353 354 355 356 357 358 359
            /* 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");
360 361 362 363 364 365 366 367
      }
   } 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;

368
   return((int)text_len);
369 370 371
}

/* ship the compressed text out via chunk writes */
372
static void /* PRIVATE */
373 374 375 376 377 378 379
png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
{
   int i;

   /* handle the no-compression case */
   if (comp->input)
   {
380 381
       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
                            (png_size_t)comp->input_len);
382 383 384 385 386 387
       return;
   }

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
388 389
      png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i],
         (png_size_t)png_ptr->zbuf_size);
390 391 392 393 394 395 396
      png_free(png_ptr, comp->output_ptr[i]);
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
   /* 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,
397
         (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
398

399
   /* reset zlib for another zTXt/iTXt or image data */
400
   deflateReset(&png_ptr->zstream);
401
   png_ptr->zstream.data_type = Z_BINARY;
402 403 404
}
#endif

G
Guy Schalnat 已提交
405
/* Write the IHDR chunk, and update the png_struct with the necessary
406 407 408
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
409
void /* PRIVATE */
G
Guy Schalnat 已提交
410
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
411 412 413
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
414 415 416
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
417 418
   int ret;

G
Guy Schalnat 已提交
419 420
   png_byte buf[13]; /* buffer to store the IHDR info */

421
   png_debug(1, "in png_write_IHDR");
G
Guy Schalnat 已提交
422
   /* Check that we have valid input data from the application info */
G
Guy Schalnat 已提交
423 424
   switch (color_type)
   {
A
Andreas Dilger 已提交
425
      case PNG_COLOR_TYPE_GRAY:
G
Guy Schalnat 已提交
426 427 428 429 430 431 432
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8:
            case 16: png_ptr->channels = 1; break;
433
            default: png_error(png_ptr, "Invalid bit depth for grayscale image");
G
Guy Schalnat 已提交
434
         }
G
Guy Schalnat 已提交
435
         break;
A
Andreas Dilger 已提交
436
      case PNG_COLOR_TYPE_RGB:
G
Guy Schalnat 已提交
437 438
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGB image");
G
Guy Schalnat 已提交
439 440
         png_ptr->channels = 3;
         break;
A
Andreas Dilger 已提交
441
      case PNG_COLOR_TYPE_PALETTE:
G
Guy Schalnat 已提交
442 443 444 445 446 447 448 449 450
         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 已提交
451
      case PNG_COLOR_TYPE_GRAY_ALPHA:
G
Guy Schalnat 已提交
452 453
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
G
Guy Schalnat 已提交
454 455
         png_ptr->channels = 2;
         break;
A
Andreas Dilger 已提交
456
      case PNG_COLOR_TYPE_RGB_ALPHA:
G
Guy Schalnat 已提交
457 458
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGBA image");
G
Guy Schalnat 已提交
459 460
         png_ptr->channels = 4;
         break;
G
Guy Schalnat 已提交
461 462 463 464
      default:
         png_error(png_ptr, "Invalid image color type specified");
   }

A
Andreas Dilger 已提交
465
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
466 467
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
468
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
469 470
   }

471 472 473 474 475 476 477 478 479
   /* 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
    */
480 481 482
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
483
      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
484
      (color_type == PNG_COLOR_TYPE_RGB ||
485
       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
486 487 488
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
489 490
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
491
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
492 493
   }

494
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
495 496
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
497 498
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
499
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
500
   }
501 502 503
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
504 505 506 507 508

   /* 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;
509
#if defined(PNG_MNG_FEATURES_SUPPORTED)
510
   png_ptr->filter_type = (png_byte)filter_type;
511
#endif
512
   png_ptr->compression_type = (png_byte)compression_type;
G
Guy Schalnat 已提交
513 514 515
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
516
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
517
   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
G
Guy Schalnat 已提交
518 519 520
   /* 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 已提交
521 522 523 524 525 526 527 528 529 530
   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 已提交
531 532

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

A
Andreas Dilger 已提交
535
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
536 537 538
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
539
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
540
   {
A
Andreas Dilger 已提交
541 542
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
543
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
544
      else
G
Guy Schalnat 已提交
545
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
546
   }
G
Guy Schalnat 已提交
547
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
548
   {
G
Guy Schalnat 已提交
549
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
550 551 552 553
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
554
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
555
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
556
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
557
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
558
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
559
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
560
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
561
      png_ptr->zlib_method = 8;
562 563 564 565 566 567 568 569 570 571 572 573 574
   ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
         png_ptr->zlib_method, png_ptr->zlib_window_bits,
         png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
   if (ret != Z_OK)
   {
      if (ret == Z_VERSION_ERROR) png_error(png_ptr,
          "zlib failed to initialize compressor -- version error");
      if (ret == Z_STREAM_ERROR) png_error(png_ptr,
           "zlib failed to initialize compressor -- stream error");
      if (ret == Z_MEM_ERROR) png_error(png_ptr,
           "zlib failed to initialize compressor -- mem error");
      png_error(png_ptr, "zlib failed to initialize compressor");
   }
A
Andreas Dilger 已提交
575 576
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
577 578 579
   /* 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 已提交
580

G
Guy Schalnat 已提交
581
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
582 583 584
}

/* write the palette.  We are careful not to trust png_color to be in the
585
 * correct order for PNG, so people can redefine it to any convenient
586 587
 * structure.
 */
588
void /* PRIVATE */
A
Andreas Dilger 已提交
589
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
590
{
591 592 593
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
594
   png_uint_32 i;
G
Guy Schalnat 已提交
595
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
596 597
   png_byte buf[3];

598
   png_debug(1, "in png_write_PLTE");
599
   if ((
600
#if defined(PNG_MNG_FEATURES_SUPPORTED)
601
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
602 603
#endif
        num_pal == 0) || num_pal > 256)
604 605
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
606
     {
607 608 609 610 611 612 613 614 615 616 617 618 619 620
        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 已提交
621 622
   }

A
Andreas Dilger 已提交
623
   png_ptr->num_palette = (png_uint_16)num_pal;
624
   png_debug1(3, "num_palette = %d", png_ptr->num_palette);
G
Guy Schalnat 已提交
625

626 627
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE,
     (png_uint_32)(num_pal * 3));
628
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
629
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
630 631 632 633
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
634
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
635
   }
636 637 638 639 640 641 642 643
#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;
644
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
645 646
   }
#endif
G
Guy Schalnat 已提交
647
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
648
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
649 650 651
}

/* write an IDAT chunk */
652
void /* PRIVATE */
A
Andreas Dilger 已提交
653
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
654
{
655 656 657
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
658
   png_debug(1, "in png_write_IDAT");
659

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
   /* 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");
   }

699
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
700
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
701 702 703
}

/* write an IEND chunk */
704
void /* PRIVATE */
G
Guy Schalnat 已提交
705
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
706
{
707 708 709
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
710
   png_debug(1, "in png_write_IEND");
711 712
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL,
     (png_size_t)0);
A
Andreas Dilger 已提交
713
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
714 715
}

G
Guy Schalnat 已提交
716
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
717
/* write a gAMA chunk */
718
#ifdef PNG_FLOATING_POINT_SUPPORTED
719
void /* PRIVATE */
A
Andreas Dilger 已提交
720
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
721
{
722 723 724
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
725 726 727
   png_uint_32 igamma;
   png_byte buf[4];

728
   png_debug(1, "in png_write_gAMA");
729
   /* file_gamma is saved in 1/100,000ths */
730
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
731
   png_save_uint_32(buf, igamma);
732
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
733
}
G
Guy Schalnat 已提交
734
#endif
735
#ifdef PNG_FIXED_POINT_SUPPORTED
736
void /* PRIVATE */
737
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
738 739 740 741 742 743
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

744
   png_debug(1, "in png_write_gAMA");
745
   /* file_gamma is saved in 1/100,000ths */
746
   png_save_uint_32(buf, (png_uint_32)file_gamma);
747
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
748 749 750
}
#endif
#endif
G
Guy Schalnat 已提交
751

752 753
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
754
void /* PRIVATE */
755
png_write_sRGB(png_structp png_ptr, int srgb_intent)
756
{
757 758 759
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
760 761
   png_byte buf[1];

762
   png_debug(1, "in png_write_sRGB");
763
   if (srgb_intent >= PNG_sRGB_INTENT_LAST)
764 765
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
766
   buf[0]=(png_byte)srgb_intent;
767
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
768 769 770
}
#endif

771 772
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
773
void /* PRIVATE */
774 775 776 777 778 779 780 781 782
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;
783
   int embedded_profile_len = 0;
784

785
   png_debug(1, "in png_write_iCCP");
786 787 788 789 790 791 792

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

793 794 795 796 797 798 799
   if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
      &new_name)) == 0)
   {
      png_warning(png_ptr, "Empty keyword in iCCP chunk");
      return;
   }

800
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
801
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
802

803
   if (profile == NULL)
804 805
      profile_len = 0;

806
   if (profile_len > 3)
807
      embedded_profile_len =
808 809 810 811
          ((*( (png_bytep)profile    ))<<24) |
          ((*( (png_bytep)profile + 1))<<16) |
          ((*( (png_bytep)profile + 2))<< 8) |
          ((*( (png_bytep)profile + 3))    );
812 813

   if (profile_len < embedded_profile_len)
814 815 816 817 818
   {
      png_warning(png_ptr,
        "Embedded profile length too large in iCCP chunk");
      return;
   }
819 820

   if (profile_len > embedded_profile_len)
821 822 823 824 825
   {
      png_warning(png_ptr,
        "Truncating profile to actual length in iCCP chunk");
      profile_len = embedded_profile_len;
   }
826

827
   if (profile_len)
828 829
      profile_len = png_text_compress(png_ptr, profile,
        (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
830 831 832

   /* make sure we include the NULL after the name and the compression type */
   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
833 834 835 836
          (png_uint_32)(name_len + profile_len + 2));
   new_name[name_len + 1] = 0x00;
   png_write_chunk_data(png_ptr, (png_bytep)new_name,
     (png_size_t)(name_len + 2));
837 838 839 840 841 842 843 844 845 846 847

   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 */
848
void /* PRIVATE */
849
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
850 851 852 853 854 855 856
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sPLT;
#endif
   png_size_t name_len;
   png_charp new_name;
   png_byte entrybuf[10];
857 858
   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
   png_size_t palette_size = entry_size * spalette->nentries;
859
   png_sPLT_entryp ep;
860 861 862
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
863

864
   png_debug(1, "in png_write_sPLT");
865 866
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
867 868 869 870 871 872
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
873
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
874 875 876 877
     (png_uint_32)(name_len + 2 + palette_size));
   png_write_chunk_data(png_ptr, (png_bytep)new_name,
     (png_size_t)(name_len + 1));
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1);
878 879

   /* loop through each palette entry, writing appropriately */
880
#ifndef PNG_NO_POINTER_INDEXING
881
   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
882
   {
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
      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);
      }
899
      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
900
   }
901 902 903 904
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
      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);
      }
921
      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
922 923
   }
#endif
924 925 926 927 928 929

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

G
Guy Schalnat 已提交
930
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
931
/* write the sBIT chunk */
932
void /* PRIVATE */
G
Guy Schalnat 已提交
933
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
934
{
935 936 937
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
938
   png_byte buf[4];
A
Andreas Dilger 已提交
939
   png_size_t size;
G
Guy Schalnat 已提交
940

941
   png_debug(1, "in png_write_sBIT");
G
Guy Schalnat 已提交
942
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
943 944
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
945
      png_byte maxbits;
G
Guy Schalnat 已提交
946

947 948
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
949 950
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
951 952 953 954 955
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
956 957 958 959 960 961 962
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
963 964 965 966 967
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
968 969 970 971 972 973
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
974 975 976 977 978
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
979 980 981
      buf[size++] = sbit->alpha;
   }

982
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
983
}
G
Guy Schalnat 已提交
984
#endif
G
Guy Schalnat 已提交
985

G
Guy Schalnat 已提交
986
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
987
/* write the cHRM chunk */
988
#ifdef PNG_FLOATING_POINT_SUPPORTED
989
void /* PRIVATE */
A
Andreas Dilger 已提交
990
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
991 992
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
993
{
994 995 996
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
997
   png_byte buf[32];
998
   png_uint_32 itemp;
G
Guy Schalnat 已提交
999

1000
   png_debug(1, "in png_write_cHRM");
1001
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
1002 1003 1004 1005
   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");
1006
#if !defined(PNG_NO_CONSOLE_IO)
1007
      fprintf(stderr, "white_x=%f, white_y=%f\n", white_x, white_y);
1008
#endif
G
Guy Schalnat 已提交
1009 1010
      return;
   }
1011
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1012
   png_save_uint_32(buf, itemp);
1013
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1014
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
1015

1016
   if (red_x < 0 ||  red_y < 0 || red_x + red_y > 1.0)
G
Guy Schalnat 已提交
1017 1018 1019 1020
   {
      png_warning(png_ptr, "Invalid cHRM red point specified");
      return;
   }
1021
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1022
   png_save_uint_32(buf + 8, itemp);
1023
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1024
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
1025

1026
   if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
G
Guy Schalnat 已提交
1027 1028 1029 1030
   {
      png_warning(png_ptr, "Invalid cHRM green point specified");
      return;
   }
1031
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1032
   png_save_uint_32(buf + 16, itemp);
1033
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1034
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
1035

1036
   if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
G
Guy Schalnat 已提交
1037 1038 1039 1040
   {
      png_warning(png_ptr, "Invalid cHRM blue point specified");
      return;
   }
1041
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1042
   png_save_uint_32(buf + 24, itemp);
1043
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1044
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
1045

1046
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
1047
}
G
Guy Schalnat 已提交
1048
#endif
1049
#ifdef PNG_FIXED_POINT_SUPPORTED
1050
void /* PRIVATE */
1051 1052 1053 1054
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)
1055 1056 1057 1058 1059 1060
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

1061
   png_debug(1, "in png_write_cHRM");
1062
   /* each value is saved in 1/100,000ths */
1063 1064
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
1065
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
1066
#if !defined(PNG_NO_CONSOLE_IO)
1067
      fprintf(stderr, "white_x=%ld, white_y=%ld\n", (unsigned long)white_x,
1068
        (unsigned long)white_y);
1069
#endif
1070 1071
      return;
   }
1072 1073
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
1074

1075
   if (red_x + red_y > 100000L)
1076
   {
1077
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
1078 1079
      return;
   }
1080 1081
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1082

1083
   if (green_x + green_y > 100000L)
1084
   {
1085
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
1086 1087
      return;
   }
1088 1089
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1090

1091
   if (blue_x + blue_y > 100000L)
1092
   {
1093
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
1094 1095
      return;
   }
1096 1097
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1098

1099
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1100 1101 1102
}
#endif
#endif
G
Guy Schalnat 已提交
1103

G
Guy Schalnat 已提交
1104
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
1105
/* write the tRNS chunk */
1106
void /* PRIVATE */
G
Guy Schalnat 已提交
1107
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
1108 1109
   int num_trans, int color_type)
{
1110 1111 1112
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
1113 1114
   png_byte buf[6];

1115
   png_debug(1, "in png_write_tRNS");
G
Guy Schalnat 已提交
1116 1117
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1118
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1119
      {
1120
         png_warning(png_ptr, "Invalid number of transparent colors specified");
G
Guy Schalnat 已提交
1121 1122
         return;
      }
G
Guy Schalnat 已提交
1123
      /* write the chunk out as it is */
1124 1125
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans,
        (png_size_t)num_trans);
G
Guy Schalnat 已提交
1126 1127 1128 1129
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
1130
      if (tran->gray >= (1 << png_ptr->bit_depth))
1131 1132 1133 1134 1135
      {
         png_warning(png_ptr,
           "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1136
      png_save_uint_16(buf, tran->gray);
1137
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1138 1139 1140 1141 1142 1143 1144
   }
   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);
1145
      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1146 1147
      {
         png_warning(png_ptr,
1148
           "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
1149 1150
         return;
      }
1151
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1152
   }
G
Guy Schalnat 已提交
1153 1154
   else
   {
1155
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1156
   }
G
Guy Schalnat 已提交
1157
}
G
Guy Schalnat 已提交
1158
#endif
G
Guy Schalnat 已提交
1159

G
Guy Schalnat 已提交
1160
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1161
/* write the background chunk */
1162
void /* PRIVATE */
G
Guy Schalnat 已提交
1163
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1164
{
1165 1166 1167
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1168 1169
   png_byte buf[6];

1170
   png_debug(1, "in png_write_bKGD");
G
Guy Schalnat 已提交
1171 1172
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1173
      if (
1174
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1175 1176
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1177 1178
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1179 1180 1181 1182
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1183
      buf[0] = back->index;
1184
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1185 1186 1187 1188 1189 1190
   }
   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);
1191
      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1192 1193 1194 1195 1196
      {
         png_warning(png_ptr,
           "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
         return;
      }
1197
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1198 1199
   }
   else
G
Guy Schalnat 已提交
1200
   {
1201
      if (back->gray >= (1 << png_ptr->bit_depth))
1202 1203 1204 1205 1206
      {
         png_warning(png_ptr,
           "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1207
      png_save_uint_16(buf, back->gray);
1208
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1209 1210
   }
}
G
Guy Schalnat 已提交
1211
#endif
G
Guy Schalnat 已提交
1212

G
Guy Schalnat 已提交
1213
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1214
/* write the histogram */
1215
void /* PRIVATE */
1216
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1217
{
1218 1219 1220
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1221
   int i;
G
Guy Schalnat 已提交
1222 1223
   png_byte buf[3];

1224
   png_debug(1, "in png_write_hIST");
1225
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1226
   {
1227
      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
A
Andreas Dilger 已提交
1228
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1229 1230 1231 1232
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1233
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST,
1234
     (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1235
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1236
   {
G
Guy Schalnat 已提交
1237
      png_save_uint_16(buf, hist[i]);
1238
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1239 1240 1241
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1242
#endif
G
Guy Schalnat 已提交
1243

1244 1245
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1246 1247 1248 1249 1250
/* 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 已提交
1251 1252 1253 1254
 *
 * 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 已提交
1255
 */
1256
png_size_t /* PRIVATE */
1257
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1258
{
A
Andreas Dilger 已提交
1259
   png_size_t key_len;
1260
   png_charp kp, dp;
A
Andreas Dilger 已提交
1261
   int kflag;
1262
   int kwarn=0;
A
Andreas Dilger 已提交
1263

1264
   png_debug(1, "in png_check_keyword");
A
Andreas Dilger 已提交
1265 1266 1267
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1268
   {
1269
      png_warning(png_ptr, "zero length keyword");
1270
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1271
   }
A
Andreas Dilger 已提交
1272

1273
   png_debug1(2, "Keyword to be checked is '%s'", key);
A
Andreas Dilger 已提交
1274

1275
   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
1276 1277 1278
   if (*new_key == NULL)
   {
      png_warning(png_ptr, "Out of memory while procesing keyword");
1279
      return ((png_size_t)0);
1280
   }
1281

A
Andreas Dilger 已提交
1282 1283
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1284
   {
1285 1286
      if ((png_byte)*kp < 0x20 ||
         ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1287
      {
1288
#if !defined(PNG_NO_STDIO)
A
Andreas Dilger 已提交
1289
         char msg[40];
A
Andreas Dilger 已提交
1290

1291 1292
         png_snprintf(msg, 40,
           "invalid keyword character 0x%02X", (png_byte)*kp);
1293
         png_warning(png_ptr, msg);
1294
#else
1295
         png_warning(png_ptr, "invalid character in keyword");
1296
#endif
A
Andreas Dilger 已提交
1297 1298 1299 1300 1301 1302
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1303
   }
A
Andreas Dilger 已提交
1304
   *dp = '\0';
A
Andreas Dilger 已提交
1305

A
Andreas Dilger 已提交
1306 1307 1308
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1309
   {
1310
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1311 1312 1313 1314 1315 1316

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1317 1318 1319
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1320 1321
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1322
   {
1323
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1324 1325 1326 1327 1328 1329

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

1332
   png_debug1(2, "Checking for multiple internal spaces in '%s'", kp);
A
Andreas Dilger 已提交
1333 1334 1335

   /* Remove multiple internal spaces. */
   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
A
Andreas Dilger 已提交
1336
   {
A
Andreas Dilger 已提交
1337
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1338
      {
A
Andreas Dilger 已提交
1339 1340
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1341
      }
A
Andreas Dilger 已提交
1342
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1343 1344
      {
         key_len--;
1345
         kwarn=1;
A
Andreas Dilger 已提交
1346 1347 1348
      }
      else
      {
A
Andreas Dilger 已提交
1349 1350
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1351 1352
      }
   }
A
Andreas Dilger 已提交
1353
   *dp = '\0';
1354
   if (kwarn)
1355
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1356 1357

   if (key_len == 0)
A
Andreas Dilger 已提交
1358
   {
1359
      png_free(png_ptr, *new_key);
1360
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1361 1362 1363 1364
   }

   if (key_len > 79)
   {
1365
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
1366
      new_key[79] = '\0';
A
Andreas Dilger 已提交
1367 1368
      key_len = 79;
   }
A
Andreas Dilger 已提交
1369

1370
   return (key_len);
A
Andreas Dilger 已提交
1371 1372 1373
}
#endif

G
Guy Schalnat 已提交
1374
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1375
/* write a tEXt chunk */
1376
void /* PRIVATE */
G
Guy Schalnat 已提交
1377
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1378
   png_size_t text_len)
G
Guy Schalnat 已提交
1379
{
1380 1381 1382
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1383
   png_size_t key_len;
1384
   png_charp new_key;
A
Andreas Dilger 已提交
1385

1386
   png_debug(1, "in png_write_tEXt");
A
Andreas Dilger 已提交
1387 1388
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1389
      png_warning(png_ptr, "Empty keyword in tEXt chunk");
G
Guy Schalnat 已提交
1390
      return;
A
Andreas Dilger 已提交
1391
   }
G
Guy Schalnat 已提交
1392

A
Andreas Dilger 已提交
1393
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1394
      text_len = 0;
1395 1396
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1397 1398

   /* make sure we include the 0 after the key */
1399
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt,
1400
      (png_uint_32)(key_len + text_len + 1));
1401 1402 1403 1404
   /*
    * 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.
1405
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1406
    */
1407 1408
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
A
Andreas Dilger 已提交
1409
   if (text_len)
1410
      png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len);
A
Andreas Dilger 已提交
1411

G
Guy Schalnat 已提交
1412
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1413
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1414
}
G
Guy Schalnat 已提交
1415
#endif
G
Guy Schalnat 已提交
1416

G
Guy Schalnat 已提交
1417
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1418
/* write a compressed text chunk */
1419
void /* PRIVATE */
G
Guy Schalnat 已提交
1420
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1421
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1422
{
1423 1424 1425
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1426
   png_size_t key_len;
G
Guy Schalnat 已提交
1427
   char buf[1];
1428
   png_charp new_key;
1429
   compression_state comp;
G
Guy Schalnat 已提交
1430

1431
   png_debug(1, "in png_write_zTXt");
A
Andreas Dilger 已提交
1432

1433 1434 1435 1436 1437 1438
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

A
Andreas Dilger 已提交
1439 1440
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1441
      png_warning(png_ptr, "Empty keyword in zTXt chunk");
1442
      png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1443
      return;
A
Andreas Dilger 已提交
1444
   }
A
Andreas Dilger 已提交
1445

A
Andreas Dilger 已提交
1446 1447
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
1448
      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
A
Andreas Dilger 已提交
1449 1450 1451 1452
      png_free(png_ptr, new_key);
      return;
   }

1453 1454
   text_len = png_strlen(text);

1455
   /* compute the compressed data; do it now for the length */
1456 1457
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1458

1459
   /* write start of chunk */
1460 1461
   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt,
     (png_uint_32)(key_len+text_len + 2));
1462
   /* write key */
1463 1464 1465 1466
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
   png_free(png_ptr, new_key);

1467 1468
   buf[0] = (png_byte)compression;
   /* write compression */
1469
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
1470 1471
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1472

1473 1474 1475 1476
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1477

1478 1479
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1480
void /* PRIVATE */
1481
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1482
    png_charp lang, png_charp lang_key, png_charp text)
1483 1484 1485 1486
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1487
   png_size_t lang_len, key_len, lang_key_len, text_len;
1488 1489 1490
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1491

1492
   png_debug(1, "in png_write_iTXt");
G
Guy Schalnat 已提交
1493

1494 1495 1496 1497 1498
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

1499
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1500
   {
1501
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1502 1503
      return;
   }
1504
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1505
   {
1506
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1507
      new_lang = NULL;
1508
      lang_len = 0;
1509
   }
G
Guy Schalnat 已提交
1510

1511 1512 1513 1514 1515 1516
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1517
      text_len = 0;
1518 1519
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1520

1521
   /* compute the compressed data; do it now for the length */
1522 1523
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1524

1525

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

1529 1530 1531 1532 1533 1534 1535
   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 已提交
1536

1537 1538 1539 1540 1541 1542
   /*
    * 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.
    */
1543 1544
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
1545 1546 1547 1548 1549 1550 1551 1552 1553

   /* 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;
1554
   png_write_chunk_data(png_ptr, cbuf, (png_size_t)2);
1555

1556
   cbuf[0] = 0;
1557 1558 1559 1560
   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf),
     (png_size_t)(lang_len + 1));
   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf),
     (png_size_t)(lang_key_len + 1));
1561
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1562 1563

   png_write_chunk_end(png_ptr);
1564
   png_free(png_ptr, new_key);
1565
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1566
}
G
Guy Schalnat 已提交
1567
#endif
G
Guy Schalnat 已提交
1568

A
Andreas Dilger 已提交
1569 1570
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1571
void /* PRIVATE */
1572
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1573 1574
   int unit_type)
{
1575 1576 1577
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1578 1579
   png_byte buf[9];

1580
   png_debug(1, "in png_write_oFFs");
A
Andreas Dilger 已提交
1581 1582
   if (unit_type >= PNG_OFFSET_LAST)
      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
G
Guy Schalnat 已提交
1583

1584 1585
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1586
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1587

1588
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1589
}
G
Guy Schalnat 已提交
1590
#endif
A
Andreas Dilger 已提交
1591
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1592
/* write the pCAL chunk (described in the PNG extensions document) */
1593
void /* PRIVATE */
A
Andreas Dilger 已提交
1594 1595 1596
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)
{
1597 1598 1599
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1600
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1601 1602
   png_uint_32p params_len;
   png_byte buf[10];
1603
   png_charp new_purpose;
A
Andreas Dilger 已提交
1604 1605
   int i;

1606
   png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
A
Andreas Dilger 已提交
1607 1608 1609 1610
   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;
1611
   png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
A
Andreas Dilger 已提交
1612
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1613
   png_debug1(3, "pCAL units length = %d", (int)units_len);
A
Andreas Dilger 已提交
1614 1615
   total_len = purpose_len + units_len + 10;

1616
   params_len = (png_uint_32p)png_malloc(png_ptr,
1617
      (png_size_t)(nparams * png_sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1618 1619 1620 1621 1622 1623

   /* 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);
1624
      png_debug2(3, "pCAL parameter %d length = %lu", i,
1625
        (unsigned long) params_len[i]);
A
Andreas Dilger 已提交
1626 1627 1628
      total_len += (png_size_t)params_len[i];
   }

1629
   png_debug1(3, "pCAL total length = %d", (int)total_len);
1630
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1631 1632
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose,
     (png_size_t)purpose_len);
A
Andreas Dilger 已提交
1633 1634 1635 1636
   png_save_int_32(buf, X0);
   png_save_int_32(buf + 4, X1);
   buf[8] = (png_byte)type;
   buf[9] = (png_byte)nparams;
1637 1638
   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);
A
Andreas Dilger 已提交
1639 1640 1641 1642 1643 1644 1645 1646 1647

   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]);
   }

1648
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1649 1650 1651 1652
   png_write_chunk_end(png_ptr);
}
#endif

1653 1654
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1655
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1656
void /* PRIVATE */
1657
png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
1658 1659 1660 1661
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1662
   char buf[64];
1663
   png_size_t total_len;
1664

1665
   png_debug(1, "in png_write_sCAL");
1666

1667
   buf[0] = (char)unit;
1668
   png_snprintf(buf + 1, 63, "%12.12e", width);
1669
   total_len = 1 + png_strlen(buf + 1) + 1;
1670
   png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
1671
   total_len += png_strlen(buf + total_len);
1672

1673
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1674
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len);
1675
}
1676 1677
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1678
void /* PRIVATE */
1679
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1680 1681 1682 1683 1684
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1685 1686
   png_byte buf[64];
   png_size_t wlen, hlen, total_len;
1687

1688
   png_debug(1, "in png_write_sCAL_s");
1689

1690 1691 1692 1693 1694 1695 1696 1697
   wlen = png_strlen(width);
   hlen = png_strlen(height);
   total_len = wlen + hlen + 2;
   if (total_len > 64)
   {
      png_warning(png_ptr, "Can't write sCAL (buffer too small)");
      return;
   }
1698

1699 1700 1701
   buf[0] = (png_byte)unit;
   png_memcpy(buf + 1, width, wlen + 1);      /* append the '\0' here */
   png_memcpy(buf + wlen + 2, height, hlen);  /* do NOT append the '\0' here */
1702

1703
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1704
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
1705 1706
}
#endif
1707 1708
#endif
#endif
1709

A
Andreas Dilger 已提交
1710 1711
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1712
void /* PRIVATE */
A
Andreas Dilger 已提交
1713 1714
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1715 1716
   int unit_type)
{
1717 1718 1719
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1720 1721
   png_byte buf[9];

1722
   png_debug(1, "in png_write_pHYs");
A
Andreas Dilger 已提交
1723 1724
   if (unit_type >= PNG_RESOLUTION_LAST)
      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
G
Guy Schalnat 已提交
1725

A
Andreas Dilger 已提交
1726 1727
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1728
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1729

1730
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1731
}
G
Guy Schalnat 已提交
1732
#endif
G
Guy Schalnat 已提交
1733

G
Guy Schalnat 已提交
1734
#if defined(PNG_WRITE_tIME_SUPPORTED)
1735 1736 1737
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1738
void /* PRIVATE */
G
Guy Schalnat 已提交
1739
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1740
{
1741 1742 1743
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1744 1745
   png_byte buf[7];

1746
   png_debug(1, "in png_write_tIME");
G
Guy Schalnat 已提交
1747 1748 1749 1750 1751 1752 1753 1754
   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 已提交
1755 1756 1757 1758 1759 1760 1761
   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;

1762
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1763
}
G
Guy Schalnat 已提交
1764
#endif
G
Guy Schalnat 已提交
1765 1766

/* initializes the row writing capability of libpng */
1767
void /* PRIVATE */
G
Guy Schalnat 已提交
1768
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1769
{
1770
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1771
#ifdef PNG_USE_LOCAL_ARRAYS
1772
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1773

1774 1775
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1776

1777 1778
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1779

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

1783 1784
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1785
#endif
1786
#endif
1787

A
Andreas Dilger 已提交
1788 1789
   png_size_t buf_size;

1790
   png_debug(1, "in png_write_start_row");
1791
   buf_size = (png_size_t)(PNG_ROWBYTES(
1792
      png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1);
A
Andreas Dilger 已提交
1793

G
Guy Schalnat 已提交
1794
   /* set up row buffer */
1795 1796
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr,
     (png_size_t)buf_size);
A
Andreas Dilger 已提交
1797
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1798

1799
#ifndef PNG_NO_WRITE_FILTER
G
Guy Schalnat 已提交
1800 1801
   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1802
   {
A
Andreas Dilger 已提交
1803
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1804
         (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1805
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1806 1807
   }

A
Andreas Dilger 已提交
1808
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1809 1810 1811
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1812 1813
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr,
        (png_size_t)buf_size);
A
Andreas Dilger 已提交
1814
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1815 1816 1817

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
1818
         png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1819
           (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1820
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1821 1822 1823 1824
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1825
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1826
           (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1827
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1828 1829 1830 1831
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
1832
         png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1833
           (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1834
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1835
      }
G
Guy Schalnat 已提交
1836
   }
1837
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1838

1839
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1840
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1841
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1842 1843 1844 1845 1846
   {
      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 已提交
1847 1848
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1849 1850 1851 1852 1853 1854 1855 1856
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1857
#endif
G
Guy Schalnat 已提交
1858
   {
G
Guy Schalnat 已提交
1859 1860 1861
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1862 1863
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1864 1865
}

A
Andreas Dilger 已提交
1866
/* Internal use only.  Called when finished processing a row of data. */
1867
void /* PRIVATE */
G
Guy Schalnat 已提交
1868
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1869
{
1870
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1871
#ifdef PNG_USE_LOCAL_ARRAYS
1872
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1873

1874 1875
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1876

1877 1878
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1879

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

1883 1884
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1885
#endif
1886
#endif
1887

G
Guy Schalnat 已提交
1888 1889
   int ret;

1890
   png_debug(1, "in png_write_finish_row");
G
Guy Schalnat 已提交
1891 1892
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1893

G
Guy Schalnat 已提交
1894
   /* see if we are done */
G
Guy Schalnat 已提交
1895
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1896
      return;
G
Guy Schalnat 已提交
1897

1898
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
   /* 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 已提交
1915
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1916 1917 1918 1919 1920 1921 1922
               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 已提交
1923 1924
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1925 1926 1927 1928
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1929
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1930
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1931
      {
A
Andreas Dilger 已提交
1932
         if (png_ptr->prev_row != NULL)
1933
            png_memset(png_ptr->prev_row, 0,
1934
               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
1935
               png_ptr->usr_bit_depth, png_ptr->width)) + 1);
G
Guy Schalnat 已提交
1936
         return;
G
Guy Schalnat 已提交
1937
      }
G
Guy Schalnat 已提交
1938
   }
1939
#endif
G
Guy Schalnat 已提交
1940 1941 1942 1943 1944 1945

   /* 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 已提交
1946
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1947
      /* check for an error */
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
      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 已提交
1959
      {
A
Andreas Dilger 已提交
1960
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1961
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1962
         else
G
Guy Schalnat 已提交
1963
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1964 1965 1966 1967
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1968
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1969 1970
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1971
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1972 1973
   }

A
Andreas Dilger 已提交
1974
   deflateReset(&png_ptr->zstream);
1975
   png_ptr->zstream.data_type = Z_BINARY;
G
Guy Schalnat 已提交
1976 1977
}

G
Guy Schalnat 已提交
1978
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1979 1980 1981 1982 1983 1984 1985
/* 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.
 */
1986
void /* PRIVATE */
G
Guy Schalnat 已提交
1987
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1988
{
1989
#ifdef PNG_USE_LOCAL_ARRAYS
1990
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1991

1992 1993
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1994

1995 1996
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1997
#endif
1998

1999
   png_debug(1, "in png_do_write_interlace");
G
Guy Schalnat 已提交
2000
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
2001
   if (pass < 6)
G
Guy Schalnat 已提交
2002
   {
2003
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
2004
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
2005
      {
G
Guy Schalnat 已提交
2006 2007
         case 1:
         {
G
Guy Schalnat 已提交
2008 2009
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
2010 2011 2012
            int shift;
            int d;
            int value;
2013 2014
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2015 2016 2017 2018

            dp = row;
            d = 0;
            shift = 7;
2019
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2020 2021 2022
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
2023
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
2024 2025 2026 2027 2028
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
2029
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2030 2031 2032 2033 2034 2035 2036
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
2037
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2038 2039 2040
            break;
         }
         case 2:
G
Guy Schalnat 已提交
2041
         {
G
Guy Schalnat 已提交
2042 2043
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
2044 2045 2046
            int shift;
            int d;
            int value;
2047 2048
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2049 2050 2051 2052

            dp = row;
            shift = 6;
            d = 0;
2053
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2054 2055 2056
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
2057
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
2058 2059 2060 2061 2062
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
2063
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2064 2065 2066 2067 2068 2069
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
2070
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
2071 2072 2073 2074
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
2075 2076
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
2077
            int shift;
G
Guy Schalnat 已提交
2078 2079
            int d;
            int value;
2080 2081
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2082 2083 2084 2085

            dp = row;
            shift = 4;
            d = 0;
2086
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2087 2088 2089
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
2090
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
2091 2092 2093 2094
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
2095 2096
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2097 2098 2099 2100 2101 2102
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
2103
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2104 2105 2106 2107
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
2108 2109
            png_bytep sp;
            png_bytep dp;
2110 2111
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
2112
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
2113

G
Guy Schalnat 已提交
2114
            /* start at the beginning */
G
Guy Schalnat 已提交
2115 2116 2117 2118 2119
            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 */
2120
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2121 2122 2123
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
2124
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
2125 2126
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
2127
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
2128 2129 2130
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
2131
            break;
G
Guy Schalnat 已提交
2132 2133 2134 2135 2136 2137 2138
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
2139 2140
         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
            row_info->width);
G
Guy Schalnat 已提交
2141 2142
   }
}
G
Guy Schalnat 已提交
2143
#endif
G
Guy Schalnat 已提交
2144

A
Andreas Dilger 已提交
2145 2146
/* 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
2147 2148
 * chosen filter.
 */
2149
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
A
Andreas Dilger 已提交
2150
#define PNG_HISHIFT 10
2151 2152
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2153
void /* PRIVATE */
G
Guy Schalnat 已提交
2154
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2155
{
2156 2157 2158
   png_bytep best_row;
#ifndef PNG_NO_WRITE_FILTER
   png_bytep prev_row, row_buf;
A
Andreas Dilger 已提交
2159
   png_uint_32 mins, bpp;
2160
   png_byte filter_to_do = png_ptr->do_filter;
2161 2162 2163 2164
   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 已提交
2165

2166
   png_debug(1, "in png_write_find_filter");
G
Guy Schalnat 已提交
2167
   /* find out how many bytes offset each pixel is */
2168
   bpp = (row_info->pixel_depth + 7) >> 3;
G
Guy Schalnat 已提交
2169 2170

   prev_row = png_ptr->prev_row;
2171 2172 2173 2174
#endif
   best_row = png_ptr->row_buf;
#ifndef PNG_NO_WRITE_FILTER
   row_buf = best_row;
A
Andreas Dilger 已提交
2175 2176 2177 2178
   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
2179
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2180
    * as the "minimum sum of absolute differences" heuristic.  Other
2181
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2182
    * (experimental and can in theory improve compression), and the "zlib
2183 2184 2185
    * 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 已提交
2186
    * computationally expensive).
2187 2188 2189 2190 2191 2192 2193 2194 2195
    *
    * 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 已提交
2196
    */
G
Guy Schalnat 已提交
2197

2198

G
Guy Schalnat 已提交
2199
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2200 2201
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2202
   if ((filter_to_do & PNG_FILTER_NONE) &&
2203
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2204
   {
G
Guy Schalnat 已提交
2205 2206
      png_bytep rp;
      png_uint_32 sum = 0;
2207
      png_uint_32 i;
A
Andreas Dilger 已提交
2208
      int v;
G
Guy Schalnat 已提交
2209

2210
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2211 2212 2213 2214
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2215 2216 2217 2218 2219

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2220
         int j;
A
Andreas Dilger 已提交
2221 2222 2223 2224
         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 */
2225
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2226
         {
2227
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2228
            {
2229
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2230
                  PNG_WEIGHT_SHIFT;
2231
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
                  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 已提交
2251 2252
      mins = sum;
   }
G
Guy Schalnat 已提交
2253

G
Guy Schalnat 已提交
2254
   /* sub filter */
2255 2256 2257 2258
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2259
      png_uint_32 i;
2260 2261 2262 2263 2264
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2265
      for (lp = row_buf + 1; i < row_bytes;
2266 2267 2268 2269 2270 2271 2272 2273
         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 已提交
2274 2275
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2276
      png_uint_32 sum = 0, lmins = mins;
2277
      png_uint_32 i;
A
Andreas Dilger 已提交
2278 2279 2280
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2281
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2282 2283 2284 2285 2286
       * 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)
      {
2287
         int j;
A
Andreas Dilger 已提交
2288 2289 2290 2291
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2292
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2293
         {
2294
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2295
            {
2296
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2297
                  PNG_WEIGHT_SHIFT;
2298
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
                  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 已提交
2314

G
Guy Schalnat 已提交
2315 2316 2317 2318
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2319

G
Guy Schalnat 已提交
2320 2321
         sum += (v < 128) ? v : 256 - v;
      }
2322
      for (lp = row_buf + 1; i < row_bytes;
2323
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2324 2325 2326 2327
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2328 2329 2330 2331 2332 2333 2334 2335

         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)
      {
2336
         int j;
A
Andreas Dilger 已提交
2337 2338 2339 2340
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2341
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2342
         {
2343
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2344
            {
2345
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2346
                  PNG_WEIGHT_SHIFT;
2347
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
                  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 已提交
2361
      }
A
Andreas Dilger 已提交
2362 2363
#endif

G
Guy Schalnat 已提交
2364 2365 2366 2367 2368
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2369 2370
   }

G
Guy Schalnat 已提交
2371
   /* up filter */
2372 2373 2374
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2375
      png_uint_32 i;
2376 2377

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2378
           pp = prev_row + 1; i < row_bytes;
2379 2380 2381 2382 2383 2384 2385 2386
           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 已提交
2387 2388
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2389
      png_uint_32 sum = 0, lmins = mins;
2390
      png_uint_32 i;
A
Andreas Dilger 已提交
2391 2392
      int v;

2393

A
Andreas Dilger 已提交
2394 2395 2396
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2397
         int j;
A
Andreas Dilger 已提交
2398 2399 2400 2401
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2402
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2403
         {
2404
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2405
            {
2406
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2407
                  PNG_WEIGHT_SHIFT;
2408
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423
                  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 已提交
2424

G
Guy Schalnat 已提交
2425
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2426
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2427
      {
2428
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2429 2430

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2431 2432 2433

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2434
      }
A
Andreas Dilger 已提交
2435 2436 2437 2438

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2439
         int j;
A
Andreas Dilger 已提交
2440 2441 2442 2443
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2444
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2445
         {
2446
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2447
            {
2448
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2449
                  PNG_WEIGHT_SHIFT;
2450
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466
                  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 已提交
2467 2468 2469 2470 2471 2472 2473 2474
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2475 2476 2477
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2478
      png_uint_32 i;
2479
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2480
           pp = prev_row + 1; i < bpp; i++)
2481
      {
2482
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2483
      }
2484
      for (lp = row_buf + 1; i < row_bytes; i++)
2485
      {
2486 2487
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2488 2489 2490 2491 2492
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2493
   {
G
Guy Schalnat 已提交
2494
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2495
      png_uint_32 sum = 0, lmins = mins;
2496
      png_uint_32 i;
A
Andreas Dilger 已提交
2497 2498 2499 2500 2501
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2502
         int j;
A
Andreas Dilger 已提交
2503 2504 2505 2506
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2507
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2508
         {
2509
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2510
            {
2511
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2512
                  PNG_WEIGHT_SHIFT;
2513
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
                  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 已提交
2529

G
Guy Schalnat 已提交
2530
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2531
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2532
      {
2533
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2534

G
Guy Schalnat 已提交
2535 2536
         sum += (v < 128) ? v : 256 - v;
      }
2537
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2538
      {
2539
         v = *dp++ =
2540
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2541

G
Guy Schalnat 已提交
2542
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2543 2544 2545

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2546
      }
A
Andreas Dilger 已提交
2547 2548 2549 2550

#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 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> 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_NONE)
A
Andreas Dilger 已提交
2559
            {
2560
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2561
                  PNG_WEIGHT_SHIFT;
2562
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578
                  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 已提交
2579 2580 2581 2582 2583 2584
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2585

A
Andreas Dilger 已提交
2586
   /* Paeth filter */
2587 2588 2589
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2590
      png_uint_32 i;
2591
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2592
           pp = prev_row + 1; i < bpp; i++)
2593
      {
2594
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2595 2596
      }

2597
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2598 2599 2600
      {
         int a, b, c, pa, pb, pc, p;

2601 2602 2603
         b = *pp++;
         c = *cp++;
         a = *lp++;
2604

2605 2606
         p = b - c;
         pc = a - c;
2607 2608

#ifdef PNG_USE_ABS
2609 2610 2611
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2612
#else
2613 2614 2615
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2616 2617 2618 2619
#endif

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

2620
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2621 2622 2623 2624 2625
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2626 2627
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2628
      png_uint_32 sum = 0, lmins = mins;
2629
      png_uint_32 i;
A
Andreas Dilger 已提交
2630 2631 2632 2633 2634
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2635
         int j;
A
Andreas Dilger 已提交
2636 2637 2638 2639
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2640
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2641
         {
2642
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2643
            {
2644
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2645
                  PNG_WEIGHT_SHIFT;
2646
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
                  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 已提交
2662

G
Guy Schalnat 已提交
2663
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2664
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2665
      {
2666
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2667

G
Guy Schalnat 已提交
2668 2669
         sum += (v < 128) ? v : 256 - v;
      }
2670

2671
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2672 2673
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2674

2675 2676 2677
         b = *pp++;
         c = *cp++;
         a = *lp++;
2678 2679

#ifndef PNG_SLOW_PAETH
2680 2681
         p = b - c;
         pc = a - c;
2682
#ifdef PNG_USE_ABS
2683 2684 2685
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2686
#else
2687 2688 2689
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2690 2691 2692
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2693
         p = a + b - c;
2694 2695 2696
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2697 2698 2699 2700 2701 2702
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2703
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2704

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

G
Guy Schalnat 已提交
2707
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2708 2709 2710

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2711
      }
A
Andreas Dilger 已提交
2712 2713 2714 2715

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2716
         int j;
A
Andreas Dilger 已提交
2717 2718 2719 2720
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2721
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2722
         {
2723
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2724
            {
2725
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2726
                  PNG_WEIGHT_SHIFT;
2727
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743
                  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 已提交
2744 2745 2746 2747
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2748
   }
2749
#endif /* PNG_NO_WRITE_FILTER */
A
Andreas Dilger 已提交
2750
   /* Do the actual writing of the filtered row data from the chosen filter. */
2751

G
Guy Schalnat 已提交
2752
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2753

2754
#ifndef PNG_NO_WRITE_FILTER
A
Andreas Dilger 已提交
2755 2756 2757 2758
#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)
   {
2759 2760
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2761
      {
2762
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2763
      }
2764
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2765 2766
   }
#endif
2767
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
2768
}
G
Guy Schalnat 已提交
2769

G
Guy Schalnat 已提交
2770

A
Andreas Dilger 已提交
2771
/* Do the actual writing of a previously filtered row. */
2772
void /* PRIVATE */
G
Guy Schalnat 已提交
2773 2774
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
2775 2776
   png_debug(1, "in png_write_filtered_row");
   png_debug1(2, "filter = %d", filtered_row[0]);
G
Guy Schalnat 已提交
2777
   /* set up the zlib input buffer */
2778

A
Andreas Dilger 已提交
2779 2780
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2781 2782
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2783
   {
G
Guy Schalnat 已提交
2784
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2785

G
Guy Schalnat 已提交
2786
      /* compress the data */
A
Andreas Dilger 已提交
2787
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2788 2789 2790
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2791
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2792
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2793 2794 2795
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2796

G
Guy Schalnat 已提交
2797
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2798
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2799 2800 2801
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2802 2803
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2804 2805
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2806
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2807

G
Guy Schalnat 已提交
2808
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2809
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2810 2811 2812 2813 2814 2815 2816 2817
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2818 2819
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2820

G
Guy Schalnat 已提交
2821 2822 2823 2824 2825 2826 2827
#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 已提交
2828
   }
2829
#endif
G
Guy Schalnat 已提交
2830
}
2831
#endif /* PNG_WRITE_SUPPORTED */