pngwutil.c 83.0 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 [March 28, 2009]
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2009 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
                  (png_alloc_size_t)
277
                  (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
                  (png_alloc_size_t)
285
                  (comp->max_output_ptr * png_sizeof(png_charp)));
286 287 288
         }

         /* save the data */
289
         comp->output_ptr[comp->num_output_ptr] =
290
            (png_charp)png_malloc(png_ptr,
291
            (png_alloc_size_t)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
                     (png_alloc_size_t)(comp->max_output_ptr *
329
                     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
                     (png_alloc_size_t)(comp->max_output_ptr *
337
                     png_sizeof(png_charp)));
338 339
            }

340 341
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
342
               (png_charp)png_malloc(png_ptr,
343
               (png_alloc_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
   if ((name_len = png_check_keyword(png_ptr, name,
794 795 796
      &new_name)) == 0)
      return;

797
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
798
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
799

800
   if (profile == NULL)
801 802
      profile_len = 0;

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

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

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

824
   if (profile_len)
825 826
      profile_len = png_text_compress(png_ptr, profile,
        (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
827 828 829

   /* make sure we include the NULL after the name and the compression type */
   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
830 831 832 833
          (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));
834 835 836 837 838 839 840 841 842 843 844

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

861
   png_debug(1, "in png_write_sPLT");
862
   if ((name_len = png_check_keyword(png_ptr,
863
      spalette->name, &new_name))==0)
864
     return;
865 866

   /* make sure we include the NULL after the name */
867
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
868 869 870 871
     (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);
872 873

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

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

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

935
   png_debug(1, "in png_write_sBIT");
G
Guy Schalnat 已提交
936
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
937 938
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
939
      png_byte maxbits;
G
Guy Schalnat 已提交
940

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

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
968 969 970 971 972
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
973 974 975
      buf[size++] = sbit->alpha;
   }

976
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
977
}
G
Guy Schalnat 已提交
978
#endif
G
Guy Schalnat 已提交
979

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

   png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y,
      int_green_x, int_green_y, int_blue_x, int_blue_y;
G
Guy Schalnat 已提交
995

996
   png_debug(1, "in png_write_cHRM");
997 998 999 1000 1001 1002 1003 1004 1005 1006

   int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5);
   int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5);
   int_red_x   = (png_uint_32)(red_x   * 100000.0 + 0.5);
   int_red_y   = (png_uint_32)(red_y   * 100000.0 + 0.5);
   int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5);
   int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5);
   int_blue_x  = (png_uint_32)(blue_x  * 100000.0 + 0.5);
   int_blue_y  = (png_uint_32)(blue_y  * 100000.0 + 0.5);

1007
#if !defined(PNG_NO_CHECK_cHRM)
1008 1009
   if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y,
      int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y))
1010
#endif
G
Guy Schalnat 已提交
1011
   {
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
     /* each value is saved in 1/100,000ths */
   
     png_save_uint_32(buf, int_white_x);
     png_save_uint_32(buf + 4, int_white_y);

     png_save_uint_32(buf + 8, int_red_x);
     png_save_uint_32(buf + 12, int_red_y);

     png_save_uint_32(buf + 16, int_green_x);
     png_save_uint_32(buf + 20, int_green_y);

     png_save_uint_32(buf + 24, int_blue_x);
     png_save_uint_32(buf + 28, int_blue_y);

     png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1027
   }
G
Guy Schalnat 已提交
1028
}
G
Guy Schalnat 已提交
1029
#endif
1030
#ifdef PNG_FIXED_POINT_SUPPORTED
1031
void /* PRIVATE */
1032 1033 1034 1035
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)
1036 1037 1038 1039 1040 1041
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

1042
   png_debug(1, "in png_write_cHRM");
1043
   /* each value is saved in 1/100,000ths */
1044
#if !defined(PNG_NO_CHECK_cHRM)
1045 1046
   if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y,
      green_x, green_y, blue_x, blue_y))
1047
#endif
1048
   {
1049 1050
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
1051

1052 1053
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1054

1055 1056
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1057

1058 1059
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1060

1061
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1062
   }
1063 1064 1065
}
#endif
#endif
G
Guy Schalnat 已提交
1066

G
Guy Schalnat 已提交
1067
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
1068
/* write the tRNS chunk */
1069
void /* PRIVATE */
G
Guy Schalnat 已提交
1070
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
1071 1072
   int num_trans, int color_type)
{
1073 1074 1075
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
1076 1077
   png_byte buf[6];

1078
   png_debug(1, "in png_write_tRNS");
G
Guy Schalnat 已提交
1079 1080
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1081
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1082
      {
1083
         png_warning(png_ptr, "Invalid number of transparent colors specified");
G
Guy Schalnat 已提交
1084 1085
         return;
      }
G
Guy Schalnat 已提交
1086
      /* write the chunk out as it is */
1087 1088
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans,
        (png_size_t)num_trans);
G
Guy Schalnat 已提交
1089 1090 1091 1092
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
1093
      if (tran->gray >= (1 << png_ptr->bit_depth))
1094 1095 1096 1097 1098
      {
         png_warning(png_ptr,
           "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1099
      png_save_uint_16(buf, tran->gray);
1100
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1101 1102 1103 1104 1105 1106 1107
   }
   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);
1108
      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1109 1110
      {
         png_warning(png_ptr,
1111
           "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
1112 1113
         return;
      }
1114
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1115
   }
G
Guy Schalnat 已提交
1116 1117
   else
   {
1118
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1119
   }
G
Guy Schalnat 已提交
1120
}
G
Guy Schalnat 已提交
1121
#endif
G
Guy Schalnat 已提交
1122

G
Guy Schalnat 已提交
1123
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1124
/* write the background chunk */
1125
void /* PRIVATE */
G
Guy Schalnat 已提交
1126
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1127
{
1128 1129 1130
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1131 1132
   png_byte buf[6];

1133
   png_debug(1, "in png_write_bKGD");
G
Guy Schalnat 已提交
1134 1135
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1136
      if (
1137
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1138 1139
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1140
#endif
1141
         back->index >= png_ptr->num_palette)
G
Guy Schalnat 已提交
1142 1143 1144 1145
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1146
      buf[0] = back->index;
1147
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1148 1149 1150 1151 1152 1153
   }
   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);
1154
      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1155 1156 1157 1158 1159
      {
         png_warning(png_ptr,
           "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
         return;
      }
1160
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1161 1162
   }
   else
G
Guy Schalnat 已提交
1163
   {
1164
      if (back->gray >= (1 << png_ptr->bit_depth))
1165 1166 1167 1168 1169
      {
         png_warning(png_ptr,
           "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
         return;
      }
G
Guy Schalnat 已提交
1170
      png_save_uint_16(buf, back->gray);
1171
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1172 1173
   }
}
G
Guy Schalnat 已提交
1174
#endif
G
Guy Schalnat 已提交
1175

G
Guy Schalnat 已提交
1176
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1177
/* write the histogram */
1178
void /* PRIVATE */
1179
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1180
{
1181 1182 1183
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1184
   int i;
G
Guy Schalnat 已提交
1185 1186
   png_byte buf[3];

1187
   png_debug(1, "in png_write_hIST");
1188
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1189
   {
1190
      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
A
Andreas Dilger 已提交
1191
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1192 1193 1194 1195
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1196
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST,
1197
     (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1198
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1199
   {
G
Guy Schalnat 已提交
1200
      png_save_uint_16(buf, hist[i]);
1201
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1202 1203 1204
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1205
#endif
G
Guy Schalnat 已提交
1206

1207 1208
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1209 1210 1211 1212 1213
/* 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 已提交
1214 1215 1216 1217
 *
 * 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 已提交
1218
 */
1219
png_size_t /* PRIVATE */
1220
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1221
{
A
Andreas Dilger 已提交
1222
   png_size_t key_len;
1223
   png_charp kp, dp;
A
Andreas Dilger 已提交
1224
   int kflag;
1225
   int kwarn=0;
A
Andreas Dilger 已提交
1226

1227
   png_debug(1, "in png_check_keyword");
A
Andreas Dilger 已提交
1228 1229 1230
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1231
   {
1232
      png_warning(png_ptr, "zero length keyword");
1233
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1234
   }
A
Andreas Dilger 已提交
1235

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

1238
   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
1239 1240 1241
   if (*new_key == NULL)
   {
      png_warning(png_ptr, "Out of memory while procesing keyword");
1242
      return ((png_size_t)0);
1243
   }
1244

A
Andreas Dilger 已提交
1245 1246
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1247
   {
1248 1249
      if ((png_byte)*kp < 0x20 ||
         ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1250
      {
1251
#if !defined(PNG_NO_STDIO)
A
Andreas Dilger 已提交
1252
         char msg[40];
A
Andreas Dilger 已提交
1253

1254 1255
         png_snprintf(msg, 40,
           "invalid keyword character 0x%02X", (png_byte)*kp);
1256
         png_warning(png_ptr, msg);
1257
#else
1258
         png_warning(png_ptr, "invalid character in keyword");
1259
#endif
A
Andreas Dilger 已提交
1260 1261 1262 1263 1264 1265
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1266
   }
A
Andreas Dilger 已提交
1267
   *dp = '\0';
A
Andreas Dilger 已提交
1268

A
Andreas Dilger 已提交
1269 1270 1271
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1272
   {
1273
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1274 1275 1276 1277 1278 1279

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1280 1281 1282
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1283 1284
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1285
   {
1286
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1287 1288 1289 1290 1291 1292

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

1295
   png_debug1(2, "Checking for multiple internal spaces in '%s'", kp);
A
Andreas Dilger 已提交
1296 1297 1298

   /* Remove multiple internal spaces. */
   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
A
Andreas Dilger 已提交
1299
   {
A
Andreas Dilger 已提交
1300
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1301
      {
A
Andreas Dilger 已提交
1302 1303
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1304
      }
A
Andreas Dilger 已提交
1305
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1306 1307
      {
         key_len--;
1308
         kwarn=1;
A
Andreas Dilger 已提交
1309 1310 1311
      }
      else
      {
A
Andreas Dilger 已提交
1312 1313
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1314 1315
      }
   }
A
Andreas Dilger 已提交
1316
   *dp = '\0';
1317
   if (kwarn)
1318
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1319 1320

   if (key_len == 0)
A
Andreas Dilger 已提交
1321
   {
1322
      png_free(png_ptr, *new_key);
1323
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1324 1325 1326 1327
   }

   if (key_len > 79)
   {
1328
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
1329
      (*new_key)[79] = '\0';
A
Andreas Dilger 已提交
1330 1331
      key_len = 79;
   }
A
Andreas Dilger 已提交
1332

1333
   return (key_len);
A
Andreas Dilger 已提交
1334 1335 1336
}
#endif

G
Guy Schalnat 已提交
1337
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1338
/* write a tEXt chunk */
1339
void /* PRIVATE */
G
Guy Schalnat 已提交
1340
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1341
   png_size_t text_len)
G
Guy Schalnat 已提交
1342
{
1343 1344 1345
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1346
   png_size_t key_len;
1347
   png_charp new_key;
A
Andreas Dilger 已提交
1348

1349
   png_debug(1, "in png_write_tEXt");
1350
   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1351 1352
      return;

A
Andreas Dilger 已提交
1353
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1354
      text_len = 0;
1355 1356
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1357 1358

   /* make sure we include the 0 after the key */
1359
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt,
1360
      (png_uint_32)(key_len + text_len + 1));
1361 1362 1363 1364
   /*
    * 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.
1365
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1366
    */
1367 1368
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
A
Andreas Dilger 已提交
1369
   if (text_len)
1370
      png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len);
A
Andreas Dilger 已提交
1371

G
Guy Schalnat 已提交
1372
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1373
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1374
}
G
Guy Schalnat 已提交
1375
#endif
G
Guy Schalnat 已提交
1376

G
Guy Schalnat 已提交
1377
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1378
/* write a compressed text chunk */
1379
void /* PRIVATE */
G
Guy Schalnat 已提交
1380
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1381
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1382
{
1383 1384 1385
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1386
   png_size_t key_len;
G
Guy Schalnat 已提交
1387
   char buf[1];
1388
   png_charp new_key;
1389
   compression_state comp;
G
Guy Schalnat 已提交
1390

1391
   png_debug(1, "in png_write_zTXt");
A
Andreas Dilger 已提交
1392

1393 1394 1395 1396 1397 1398
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

1399
   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
A
Andreas Dilger 已提交
1400
   {
1401
      png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1402
      return;
A
Andreas Dilger 已提交
1403
   }
A
Andreas Dilger 已提交
1404

A
Andreas Dilger 已提交
1405 1406
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
1407
      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
A
Andreas Dilger 已提交
1408 1409 1410 1411
      png_free(png_ptr, new_key);
      return;
   }

1412 1413
   text_len = png_strlen(text);

1414
   /* compute the compressed data; do it now for the length */
1415 1416
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1417

1418
   /* write start of chunk */
1419 1420
   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt,
     (png_uint_32)(key_len+text_len + 2));
1421
   /* write key */
1422 1423 1424 1425
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
   png_free(png_ptr, new_key);

1426 1427
   buf[0] = (png_byte)compression;
   /* write compression */
1428
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
1429 1430
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1431

1432 1433 1434 1435
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1436

1437 1438
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1439
void /* PRIVATE */
1440
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1441
    png_charp lang, png_charp lang_key, png_charp text)
1442 1443 1444 1445
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1446
   png_size_t lang_len, key_len, lang_key_len, text_len;
1447 1448
   png_charp new_lang;
   png_charp new_key = NULL;
1449 1450
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1451

1452
   png_debug(1, "in png_write_iTXt");
G
Guy Schalnat 已提交
1453

1454 1455 1456 1457 1458
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

1459
   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
1460
      return;
1461 1462

   if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1463
   {
1464
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1465
      new_lang = NULL;
1466
      lang_len = 0;
1467
   }
G
Guy Schalnat 已提交
1468

1469 1470 1471 1472 1473 1474
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1475
      text_len = 0;
1476 1477
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1478

1479
   /* compute the compressed data; do it now for the length */
1480 1481
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1482

1483

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

1487 1488 1489 1490 1491 1492 1493
   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 已提交
1494

1495 1496 1497 1498 1499 1500
   /*
    * 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.
    */
1501 1502
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
1503 1504 1505 1506 1507 1508 1509 1510 1511

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

1514
   cbuf[0] = 0;
1515 1516 1517 1518
   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));
1519
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1520 1521

   png_write_chunk_end(png_ptr);
1522
   png_free(png_ptr, new_key);
1523
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1524
}
G
Guy Schalnat 已提交
1525
#endif
G
Guy Schalnat 已提交
1526

A
Andreas Dilger 已提交
1527 1528
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1529
void /* PRIVATE */
1530
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1531 1532
   int unit_type)
{
1533 1534 1535
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1536 1537
   png_byte buf[9];

1538
   png_debug(1, "in png_write_oFFs");
A
Andreas Dilger 已提交
1539 1540
   if (unit_type >= PNG_OFFSET_LAST)
      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
G
Guy Schalnat 已提交
1541

1542 1543
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1544
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1545

1546
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1547
}
G
Guy Schalnat 已提交
1548
#endif
A
Andreas Dilger 已提交
1549
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1550
/* write the pCAL chunk (described in the PNG extensions document) */
1551
void /* PRIVATE */
A
Andreas Dilger 已提交
1552 1553 1554
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)
{
1555 1556 1557
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1558
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1559 1560
   png_uint_32p params_len;
   png_byte buf[10];
1561
   png_charp new_purpose;
A
Andreas Dilger 已提交
1562 1563
   int i;

1564
   png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
A
Andreas Dilger 已提交
1565 1566 1567 1568
   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;
1569
   png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
A
Andreas Dilger 已提交
1570
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1571
   png_debug1(3, "pCAL units length = %d", (int)units_len);
A
Andreas Dilger 已提交
1572 1573
   total_len = purpose_len + units_len + 10;

1574
   params_len = (png_uint_32p)png_malloc(png_ptr,
1575
      (png_alloc_size_t)(nparams * png_sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1576 1577 1578 1579 1580 1581

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

1587
   png_debug1(3, "pCAL total length = %d", (int)total_len);
1588
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1589 1590
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose,
     (png_size_t)purpose_len);
A
Andreas Dilger 已提交
1591 1592 1593 1594
   png_save_int_32(buf, X0);
   png_save_int_32(buf + 4, X1);
   buf[8] = (png_byte)type;
   buf[9] = (png_byte)nparams;
1595 1596
   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 已提交
1597 1598 1599 1600 1601 1602 1603 1604 1605

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

1606
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1607 1608 1609 1610
   png_write_chunk_end(png_ptr);
}
#endif

1611 1612
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1613
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1614
void /* PRIVATE */
1615
png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
1616 1617 1618 1619
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1620
   char buf[64];
1621
   png_size_t total_len;
1622

1623
   png_debug(1, "in png_write_sCAL");
1624

1625
   buf[0] = (char)unit;
1626
   png_snprintf(buf + 1, 63, "%12.12e", width);
1627
   total_len = 1 + png_strlen(buf + 1) + 1;
1628
   png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
1629
   total_len += png_strlen(buf + total_len);
1630

1631
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1632
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len);
1633
}
1634 1635
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1636
void /* PRIVATE */
1637
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1638 1639 1640 1641 1642
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1643 1644
   png_byte buf[64];
   png_size_t wlen, hlen, total_len;
1645

1646
   png_debug(1, "in png_write_sCAL_s");
1647

1648 1649 1650 1651 1652 1653 1654 1655
   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;
   }
1656

1657 1658 1659
   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 */
1660

1661
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1662
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
1663 1664
}
#endif
1665 1666
#endif
#endif
1667

A
Andreas Dilger 已提交
1668 1669
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1670
void /* PRIVATE */
A
Andreas Dilger 已提交
1671 1672
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1673 1674
   int unit_type)
{
1675 1676 1677
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1678 1679
   png_byte buf[9];

1680
   png_debug(1, "in png_write_pHYs");
A
Andreas Dilger 已提交
1681 1682
   if (unit_type >= PNG_RESOLUTION_LAST)
      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
G
Guy Schalnat 已提交
1683

A
Andreas Dilger 已提交
1684 1685
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1686
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1687

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

G
Guy Schalnat 已提交
1692
#if defined(PNG_WRITE_tIME_SUPPORTED)
1693 1694 1695
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1696
void /* PRIVATE */
G
Guy Schalnat 已提交
1697
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1698
{
1699 1700 1701
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1702 1703
   png_byte buf[7];

1704
   png_debug(1, "in png_write_tIME");
G
Guy Schalnat 已提交
1705 1706 1707 1708 1709 1710 1711 1712
   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 已提交
1713 1714 1715 1716 1717 1718 1719
   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;

1720
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1721
}
G
Guy Schalnat 已提交
1722
#endif
G
Guy Schalnat 已提交
1723 1724

/* initializes the row writing capability of libpng */
1725
void /* PRIVATE */
G
Guy Schalnat 已提交
1726
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1727
{
1728
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1729
#ifdef PNG_USE_LOCAL_ARRAYS
1730
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1731

1732 1733
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1734

1735 1736
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1737

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

1741 1742
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1743
#endif
1744
#endif
1745

A
Andreas Dilger 已提交
1746 1747
   png_size_t buf_size;

1748
   png_debug(1, "in png_write_start_row");
1749
   buf_size = (png_size_t)(PNG_ROWBYTES(
1750
      png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1);
A
Andreas Dilger 已提交
1751

G
Guy Schalnat 已提交
1752
   /* set up row buffer */
1753
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr,
1754
     (png_alloc_size_t)buf_size);
A
Andreas Dilger 已提交
1755
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1756

1757
#ifndef PNG_NO_WRITE_FILTER
G
Guy Schalnat 已提交
1758 1759
   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1760
   {
A
Andreas Dilger 已提交
1761
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1762
         (png_alloc_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1763
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1764 1765
   }

A
Andreas Dilger 已提交
1766
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1767 1768 1769
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1770 1771
#ifdef PNG_CALLOC_SUPPORTED
     png_ptr->prev_row = (png_bytep)png_calloc(png_ptr,
1772
        (png_alloc_size_t)buf_size);
1773 1774 1775 1776 1777
#else
     png_ptr->prev_row = (png_bytep)png_malloc(png_ptr,
        (png_uint_32)buf_size);
     png_memset(png_ptr->prev_row, 0, buf_size);
#endif
G
Guy Schalnat 已提交
1778 1779 1780

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
1781
         png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1782
           (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1783
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1784 1785 1786 1787
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1788
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1789
           (png_alloc_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1790
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1791 1792 1793 1794
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
1795
         png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1796
           (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1797
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1798
      }
G
Guy Schalnat 已提交
1799
   }
1800
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1801

1802
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1803
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1804
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1805 1806 1807 1808 1809
   {
      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 已提交
1810 1811
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1812 1813 1814 1815 1816 1817 1818 1819
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1820
#endif
G
Guy Schalnat 已提交
1821
   {
G
Guy Schalnat 已提交
1822 1823 1824
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1825 1826
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1827 1828
}

A
Andreas Dilger 已提交
1829
/* Internal use only.  Called when finished processing a row of data. */
1830
void /* PRIVATE */
G
Guy Schalnat 已提交
1831
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1832
{
1833
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1834
#ifdef PNG_USE_LOCAL_ARRAYS
1835
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1836

1837 1838
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1839

1840 1841
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1842

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

1846 1847
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1848
#endif
1849
#endif
1850

G
Guy Schalnat 已提交
1851 1852
   int ret;

1853
   png_debug(1, "in png_write_finish_row");
G
Guy Schalnat 已提交
1854 1855
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1856

G
Guy Schalnat 已提交
1857
   /* see if we are done */
G
Guy Schalnat 已提交
1858
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1859
      return;
G
Guy Schalnat 已提交
1860

1861
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
   /* 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 已提交
1878
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1879 1880 1881 1882 1883 1884 1885
               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 已提交
1886 1887
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1888 1889 1890 1891
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1892
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1893
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1894
      {
A
Andreas Dilger 已提交
1895
         if (png_ptr->prev_row != NULL)
1896
            png_memset(png_ptr->prev_row, 0,
1897
               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
1898
               png_ptr->usr_bit_depth, png_ptr->width)) + 1);
G
Guy Schalnat 已提交
1899
         return;
G
Guy Schalnat 已提交
1900
      }
G
Guy Schalnat 已提交
1901
   }
1902
#endif
G
Guy Schalnat 已提交
1903 1904 1905 1906 1907 1908

   /* 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 已提交
1909
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1910
      /* check for an error */
1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
      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 已提交
1922
      {
A
Andreas Dilger 已提交
1923
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1924
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1925
         else
G
Guy Schalnat 已提交
1926
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1927 1928 1929 1930
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1931
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1932 1933
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1934
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1935 1936
   }

A
Andreas Dilger 已提交
1937
   deflateReset(&png_ptr->zstream);
1938
   png_ptr->zstream.data_type = Z_BINARY;
G
Guy Schalnat 已提交
1939 1940
}

G
Guy Schalnat 已提交
1941
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1942 1943 1944 1945 1946 1947 1948
/* 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.
 */
1949
void /* PRIVATE */
G
Guy Schalnat 已提交
1950
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1951
{
1952
#ifdef PNG_USE_LOCAL_ARRAYS
1953
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1954

1955 1956
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1957

1958 1959
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1960
#endif
1961

1962
   png_debug(1, "in png_do_write_interlace");
G
Guy Schalnat 已提交
1963
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1964
   if (pass < 6)
G
Guy Schalnat 已提交
1965
   {
1966
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1967
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1968
      {
G
Guy Schalnat 已提交
1969 1970
         case 1:
         {
G
Guy Schalnat 已提交
1971 1972
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1973 1974 1975
            int shift;
            int d;
            int value;
1976 1977
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1978 1979 1980 1981

            dp = row;
            d = 0;
            shift = 7;
1982
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1983 1984 1985
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1986
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1987 1988 1989 1990 1991
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1992
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1993 1994 1995 1996 1997 1998 1999
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
2000
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2001 2002 2003
            break;
         }
         case 2:
G
Guy Schalnat 已提交
2004
         {
G
Guy Schalnat 已提交
2005 2006
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
2007 2008 2009
            int shift;
            int d;
            int value;
2010 2011
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2012 2013 2014 2015

            dp = row;
            shift = 6;
            d = 0;
2016
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2017 2018 2019
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
2020
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
2021 2022 2023 2024 2025
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
2026
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2027 2028 2029 2030 2031 2032
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
2033
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
2034 2035 2036 2037
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
2038 2039
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
2040
            int shift;
G
Guy Schalnat 已提交
2041 2042
            int d;
            int value;
2043 2044
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
2045 2046 2047 2048

            dp = row;
            shift = 4;
            d = 0;
2049
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2050 2051 2052
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
2053
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
2054 2055 2056 2057
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
2058 2059
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2060 2061 2062 2063 2064 2065
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
2066
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2067 2068 2069 2070
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
2071 2072
            png_bytep sp;
            png_bytep dp;
2073 2074
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
2075
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
2076

G
Guy Schalnat 已提交
2077
            /* start at the beginning */
G
Guy Schalnat 已提交
2078 2079 2080 2081 2082
            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 */
2083
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2084 2085 2086
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
2087
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
2088 2089
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
2090
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
2091 2092 2093
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
2094
            break;
G
Guy Schalnat 已提交
2095 2096 2097 2098 2099 2100 2101
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
2102 2103
         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
            row_info->width);
G
Guy Schalnat 已提交
2104 2105
   }
}
G
Guy Schalnat 已提交
2106
#endif
G
Guy Schalnat 已提交
2107

A
Andreas Dilger 已提交
2108 2109
/* 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
2110 2111
 * chosen filter.
 */
2112
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
A
Andreas Dilger 已提交
2113
#define PNG_HISHIFT 10
2114 2115
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2116
void /* PRIVATE */
G
Guy Schalnat 已提交
2117
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2118
{
2119 2120 2121
   png_bytep best_row;
#ifndef PNG_NO_WRITE_FILTER
   png_bytep prev_row, row_buf;
A
Andreas Dilger 已提交
2122
   png_uint_32 mins, bpp;
2123
   png_byte filter_to_do = png_ptr->do_filter;
2124 2125 2126 2127
   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 已提交
2128

2129
   png_debug(1, "in png_write_find_filter");
G
Guy Schalnat 已提交
2130
   /* find out how many bytes offset each pixel is */
2131
   bpp = (row_info->pixel_depth + 7) >> 3;
G
Guy Schalnat 已提交
2132 2133

   prev_row = png_ptr->prev_row;
2134 2135 2136 2137
#endif
   best_row = png_ptr->row_buf;
#ifndef PNG_NO_WRITE_FILTER
   row_buf = best_row;
A
Andreas Dilger 已提交
2138 2139 2140 2141
   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
2142
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2143
    * as the "minimum sum of absolute differences" heuristic.  Other
2144
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2145
    * (experimental and can in theory improve compression), and the "zlib
2146 2147 2148
    * 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 已提交
2149
    * computationally expensive).
2150 2151 2152 2153 2154 2155 2156 2157 2158
    *
    * 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 已提交
2159
    */
G
Guy Schalnat 已提交
2160

2161

G
Guy Schalnat 已提交
2162
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2163 2164
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2165
   if ((filter_to_do & PNG_FILTER_NONE) &&
2166
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2167
   {
G
Guy Schalnat 已提交
2168 2169
      png_bytep rp;
      png_uint_32 sum = 0;
2170
      png_uint_32 i;
A
Andreas Dilger 已提交
2171
      int v;
G
Guy Schalnat 已提交
2172

2173
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2174 2175 2176 2177
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2178 2179 2180 2181 2182

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2183
         int j;
A
Andreas Dilger 已提交
2184 2185 2186 2187
         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 */
2188
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2189
         {
2190
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2191
            {
2192
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2193
                  PNG_WEIGHT_SHIFT;
2194
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
                  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 已提交
2214 2215
      mins = sum;
   }
G
Guy Schalnat 已提交
2216

G
Guy Schalnat 已提交
2217
   /* sub filter */
2218 2219 2220 2221
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2222
      png_uint_32 i;
2223 2224 2225 2226 2227
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2228
      for (lp = row_buf + 1; i < row_bytes;
2229 2230 2231 2232 2233 2234 2235 2236
         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 已提交
2237 2238
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2239
      png_uint_32 sum = 0, lmins = mins;
2240
      png_uint_32 i;
A
Andreas Dilger 已提交
2241 2242 2243
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2244
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2245 2246 2247 2248 2249
       * 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)
      {
2250
         int j;
A
Andreas Dilger 已提交
2251 2252 2253 2254
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2255
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2256
         {
2257
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2258
            {
2259
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2260
                  PNG_WEIGHT_SHIFT;
2261
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
                  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 已提交
2277

G
Guy Schalnat 已提交
2278 2279 2280 2281
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2282

G
Guy Schalnat 已提交
2283 2284
         sum += (v < 128) ? v : 256 - v;
      }
2285
      for (lp = row_buf + 1; i < row_bytes;
2286
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2287 2288 2289 2290
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2291 2292 2293 2294 2295 2296 2297 2298

         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)
      {
2299
         int j;
A
Andreas Dilger 已提交
2300 2301 2302 2303
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2304
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2305
         {
2306
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2307
            {
2308
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2309
                  PNG_WEIGHT_SHIFT;
2310
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323
                  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 已提交
2324
      }
A
Andreas Dilger 已提交
2325 2326
#endif

G
Guy Schalnat 已提交
2327 2328 2329 2330 2331
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2332 2333
   }

G
Guy Schalnat 已提交
2334
   /* up filter */
2335 2336 2337
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2338
      png_uint_32 i;
2339 2340

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2341
           pp = prev_row + 1; i < row_bytes;
2342 2343 2344 2345 2346 2347 2348 2349
           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 已提交
2350 2351
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2352
      png_uint_32 sum = 0, lmins = mins;
2353
      png_uint_32 i;
A
Andreas Dilger 已提交
2354 2355
      int v;

2356

A
Andreas Dilger 已提交
2357 2358 2359
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2360
         int j;
A
Andreas Dilger 已提交
2361 2362 2363 2364
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2365
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2366
         {
2367
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2368
            {
2369
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2370
                  PNG_WEIGHT_SHIFT;
2371
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
                  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 已提交
2387

G
Guy Schalnat 已提交
2388
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2389
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2390
      {
2391
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2392 2393

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2394 2395 2396

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2397
      }
A
Andreas Dilger 已提交
2398 2399 2400 2401

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2402
         int j;
A
Andreas Dilger 已提交
2403 2404 2405 2406
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2407
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2408
         {
2409
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2410
            {
2411
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2412
                  PNG_WEIGHT_SHIFT;
2413
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429
                  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 已提交
2430 2431 2432 2433 2434 2435 2436 2437
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2438 2439 2440
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2441
      png_uint_32 i;
2442
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2443
           pp = prev_row + 1; i < bpp; i++)
2444
      {
2445
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2446
      }
2447
      for (lp = row_buf + 1; i < row_bytes; i++)
2448
      {
2449 2450
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2451 2452 2453 2454 2455
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2456
   {
G
Guy Schalnat 已提交
2457
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2458
      png_uint_32 sum = 0, lmins = mins;
2459
      png_uint_32 i;
A
Andreas Dilger 已提交
2460 2461 2462 2463 2464
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2465
         int j;
A
Andreas Dilger 已提交
2466 2467 2468 2469
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2470
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2471
         {
2472
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2473
            {
2474
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2475
                  PNG_WEIGHT_SHIFT;
2476
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
                  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 已提交
2492

G
Guy Schalnat 已提交
2493
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2494
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2495
      {
2496
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2497

G
Guy Schalnat 已提交
2498 2499
         sum += (v < 128) ? v : 256 - v;
      }
2500
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2501
      {
2502
         v = *dp++ =
2503
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2504

G
Guy Schalnat 已提交
2505
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2506 2507 2508

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2509
      }
A
Andreas Dilger 已提交
2510 2511 2512 2513

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2514
         int j;
A
Andreas Dilger 已提交
2515 2516 2517 2518
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2519
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2520
         {
2521
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2522
            {
2523
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2524
                  PNG_WEIGHT_SHIFT;
2525
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541
                  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 已提交
2542 2543 2544 2545 2546 2547
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2548

A
Andreas Dilger 已提交
2549
   /* Paeth filter */
2550 2551 2552
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2553
      png_uint_32 i;
2554
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2555
           pp = prev_row + 1; i < bpp; i++)
2556
      {
2557
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2558 2559
      }

2560
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2561 2562 2563
      {
         int a, b, c, pa, pb, pc, p;

2564 2565 2566
         b = *pp++;
         c = *cp++;
         a = *lp++;
2567

2568 2569
         p = b - c;
         pc = a - c;
2570 2571

#ifdef PNG_USE_ABS
2572 2573 2574
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2575
#else
2576 2577 2578
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2579 2580 2581 2582
#endif

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

2583
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2584 2585 2586 2587 2588
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2589 2590
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2591
      png_uint_32 sum = 0, lmins = mins;
2592
      png_uint_32 i;
A
Andreas Dilger 已提交
2593 2594 2595 2596 2597
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2598
         int j;
A
Andreas Dilger 已提交
2599 2600 2601 2602
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2603
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2604
         {
2605
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2606
            {
2607
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2608
                  PNG_WEIGHT_SHIFT;
2609
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
                  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 已提交
2625

G
Guy Schalnat 已提交
2626
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2627
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2628
      {
2629
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2630

G
Guy Schalnat 已提交
2631 2632
         sum += (v < 128) ? v : 256 - v;
      }
2633

2634
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2635 2636
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2637

2638 2639 2640
         b = *pp++;
         c = *cp++;
         a = *lp++;
2641 2642

#ifndef PNG_SLOW_PAETH
2643 2644
         p = b - c;
         pc = a - c;
2645
#ifdef PNG_USE_ABS
2646 2647 2648
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2649
#else
2650 2651 2652
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2653 2654 2655
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2656
         p = a + b - c;
2657 2658 2659
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2660 2661 2662 2663 2664 2665
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2666
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2667

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

G
Guy Schalnat 已提交
2670
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2671 2672 2673

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2674
      }
A
Andreas Dilger 已提交
2675 2676 2677 2678

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2679
         int j;
A
Andreas Dilger 已提交
2680 2681 2682 2683
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2684
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2685
         {
2686
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2687
            {
2688
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2689
                  PNG_WEIGHT_SHIFT;
2690
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
                  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 已提交
2707 2708 2709 2710
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2711
   }
2712
#endif /* PNG_NO_WRITE_FILTER */
A
Andreas Dilger 已提交
2713
   /* Do the actual writing of the filtered row data from the chosen filter. */
2714

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

2717
#ifndef PNG_NO_WRITE_FILTER
A
Andreas Dilger 已提交
2718 2719 2720 2721
#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)
   {
2722 2723
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2724
      {
2725
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2726
      }
2727
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2728 2729
   }
#endif
2730
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
2731
}
G
Guy Schalnat 已提交
2732

G
Guy Schalnat 已提交
2733

A
Andreas Dilger 已提交
2734
/* Do the actual writing of a previously filtered row. */
2735
void /* PRIVATE */
G
Guy Schalnat 已提交
2736 2737
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
2738 2739
   png_debug(1, "in png_write_filtered_row");
   png_debug1(2, "filter = %d", filtered_row[0]);
G
Guy Schalnat 已提交
2740
   /* set up the zlib input buffer */
2741

A
Andreas Dilger 已提交
2742 2743
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2744 2745
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2746
   {
G
Guy Schalnat 已提交
2747
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2748

G
Guy Schalnat 已提交
2749
      /* compress the data */
A
Andreas Dilger 已提交
2750
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2751 2752 2753
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2754
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2755
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2756 2757 2758
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2759

G
Guy Schalnat 已提交
2760
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2761
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2762 2763 2764
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2765 2766
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2767 2768
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2769
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2770

G
Guy Schalnat 已提交
2771
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2772
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2773 2774 2775 2776 2777 2778 2779 2780
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2781 2782
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2783

G
Guy Schalnat 已提交
2784 2785 2786 2787 2788 2789 2790
#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 已提交
2791
   }
2792
#endif
G
Guy Schalnat 已提交
2793
}
2794
#endif /* PNG_WRITE_SUPPORTED */