pngwutil.c 83.2 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 [November 25, 2008]
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9
 */
A
Andreas Dilger 已提交
10

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

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

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

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

54 55 56 57 58 59 60 61 62 63
/* Simple function to write the signature.  If we have already written
 * the magic bytes of the signature, or more likely, the PNG stream is
 * being embedded into another stream and doesn't need its own signature,
 * we should call png_set_sig_bytes() to tell libpng how many of the
 * bytes have already been written.
 */
void PNGAPI
png_write_sig(png_structp png_ptr)
{
   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
64 65 66 67 68 69

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

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

A
Andreas Dilger 已提交
77
/* Write a PNG chunk all at once.  The type is an array of ASCII characters
78 79 80 81 82 83 84 85
 * representing the chunk name.  The array must be at least 4 bytes in
 * length, and does not need to be null terminated.  To be safe, pass the
 * pre-defined chunk names here, and if you need a new one, define it
 * where the others are defined.  The length is the length of the data.
 * All the data must be present.  If that is not possible, use the
 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
 * functions instead.
 */
86
void PNGAPI
A
Andreas Dilger 已提交
87
png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
A
Andreas Dilger 已提交
88
   png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
89
{
90
   if (png_ptr == NULL) return;
A
Andreas Dilger 已提交
91
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
92
   png_write_chunk_data(png_ptr, data, (png_size_t)length);
A
Andreas Dilger 已提交
93
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
94 95
}

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

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

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

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

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

A
Andreas Dilger 已提交
135
/* Write the data of a PNG chunk started with png_write_chunk_start().
136 137 138 139
 * Note that multiple calls to this function are allowed, and that the
 * sum of the lengths from these calls *must* add up to the total_length
 * given to png_write_chunk_start().
 */
140
void PNGAPI
A
Andreas Dilger 已提交
141
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
142
{
A
Andreas Dilger 已提交
143
   /* write the data, and run the CRC over it */
144
   if (png_ptr == NULL) return;
A
Andreas Dilger 已提交
145
   if (data != NULL && length > 0)
G
Guy Schalnat 已提交
146
   {
G
Guy Schalnat 已提交
147
      png_write_data(png_ptr, data, length);
148 149 150 151
      /* update the CRC after writing the data,
       * in case that the user I/O routine alters it.
       */
      png_calculate_crc(png_ptr, data, length);
G
Guy Schalnat 已提交
152 153 154
   }
}

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

161 162
   if (png_ptr == NULL) return;

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

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

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

176
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
/*
 * This pair of functions encapsulates the operation of (a) compressing a
 * text string, and (b) issuing it later as a series of chunk data writes.
 * The compression_state structure is shared context for these functions
 * set up by the caller in order to make the whole mess thread-safe.
 */

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

/* compress given text into storage in the png_ptr structure */
194
static int /* PRIVATE */
195 196 197 198 199 200
png_text_compress(png_structp png_ptr,
        png_charp text, png_size_t text_len, int compression,
        compression_state *comp)
{
   int ret;

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

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
217
#if !defined(PNG_NO_STDIO)
218
      char msg[50];
219
      png_snprintf(msg, 50, "Unknown compression type %d", compression);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
      png_warning(png_ptr, msg);
#else
      png_warning(png_ptr, "Unknown compression type");
#endif
   }

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

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

   /* this is the same compression loop as in png_write_row() */
   do
   {
      /* compress the data */
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
      if (ret != Z_OK)
      {
         /* error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
      }
      /* check to see if we need more room */
261
      if (!(png_ptr->zstream.avail_out))
262 263 264 265 266 267 268 269 270 271 272 273 274 275
      {
         /* make sure the output array has room */
         if (comp->num_output_ptr >= comp->max_output_ptr)
         {
            int old_max;

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

               old_ptr = comp->output_ptr;
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
276 277
                  (png_size_t)
                  (comp->max_output_ptr * png_sizeof(png_charpp)));
278
               png_memcpy(comp->output_ptr, old_ptr, old_max
279
                  * png_sizeof(png_charp));
280 281 282 283
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
284 285
                  (png_size_t)
                  (comp->max_output_ptr * png_sizeof(png_charp)));
286 287 288
         }

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

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

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

309
      if (ret == Z_OK)
310
      {
311 312
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
313
         {
314 315
            /* check to make sure our output array has room */
            if (comp->num_output_ptr >= comp->max_output_ptr)
316
            {
317 318 319 320 321 322 323 324 325 326 327
               int old_max;

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

                  old_ptr = comp->output_ptr;
                  /* This could be optimized to realloc() */
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
328 329
                     (png_size_t)(comp->max_output_ptr *
                     png_sizeof(png_charp)));
330
                  png_memcpy(comp->output_ptr, old_ptr,
331
                     old_max * png_sizeof(png_charp));
332 333 334 335
                  png_free(png_ptr, old_ptr);
               }
               else
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
336 337
                     (png_size_t)(comp->max_output_ptr *
                     png_sizeof(png_charp)));
338 339
            }

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

348 349 350 351 352 353 354 355 356 357 358 359
            /* and reset the buffer pointers */
            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
            png_ptr->zstream.next_out = png_ptr->zbuf;
         }
      }
      else if (ret != Z_STREAM_END)
      {
         /* we got an error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
360 361 362 363 364 365 366 367
      }
   } while (ret != Z_STREAM_END);

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

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

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

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

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

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

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

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

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

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

471 472 473 474 475 476 477 478 479
   /* Write filter_method 64 (intrapixel differencing) only if
    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    * 2. Libpng did not write a PNG signature (this filter_method is only
    *    used in PNG datastreams that are embedded in MNG datastreams) and
    * 3. The application called png_permit_mng_features with a mask that
    *    included PNG_FLAG_MNG_FILTER_64 and
    * 4. The filter_method is 64 and
    * 5. The color_type is RGB or RGBA
    */
480 481 482
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
483
      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
484
      (color_type == PNG_COLOR_TYPE_RGB ||
485
       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
486 487 488
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
489 490
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
491
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
492 493
   }

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

   /* save off the relevent information */
   png_ptr->bit_depth = (png_byte)bit_depth;
   png_ptr->color_type = (png_byte)color_type;
   png_ptr->interlaced = (png_byte)interlace_type;
509
#if defined(PNG_MNG_FEATURES_SUPPORTED)
510
   png_ptr->filter_type = (png_byte)filter_type;
511
#endif
512
   png_ptr->compression_type = (png_byte)compression_type;
G
Guy Schalnat 已提交
513 514 515
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
516
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
517
   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
G
Guy Schalnat 已提交
518 519 520
   /* set the usr info, so any transformations can modify it */
   png_ptr->usr_width = png_ptr->width;
   png_ptr->usr_bit_depth = png_ptr->bit_depth;
G
Guy Schalnat 已提交
521 522 523 524 525 526 527 528 529 530
   png_ptr->usr_channels = png_ptr->channels;

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

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

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

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

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

598
   png_debug(1, "in png_write_PLTE");
599
   if ((
600
#if defined(PNG_MNG_FEATURES_SUPPORTED)
601
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
602 603
#endif
        num_pal == 0) || num_pal > 256)
604 605
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
606
     {
607 608 609 610 611 612 613 614 615 616 617 618 619 620
        png_error(png_ptr, "Invalid number of colors in palette");
     }
     else
     {
        png_warning(png_ptr, "Invalid number of colors in palette");
        return;
     }
   }

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

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

626 627
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE,
     (png_uint_32)(num_pal * 3));
628
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
629
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
630 631 632 633
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
634
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
635
   }
636 637 638 639 640 641 642 643
#else
   /* This is a little slower but some buggy compilers need to do this instead */
   pal_ptr=palette;
   for (i = 0; i < num_pal; i++)
   {
      buf[0] = pal_ptr[i].red;
      buf[1] = pal_ptr[i].green;
      buf[2] = pal_ptr[i].blue;
644
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
645 646
   }
#endif
G
Guy Schalnat 已提交
647
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
648
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
649 650 651
}

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

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
   /* Optimize the CMF field in the zlib stream. */
   /* This hack of the zlib stream is compliant to the stream specification. */
   if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
       png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
   {
      unsigned int z_cmf = data[0];  /* zlib compression method and flags */
      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
      {
         /* Avoid memory underflows and multiplication overflows. */
         /* The conditions below are practically always satisfied;
            however, they still must be checked. */
         if (length >= 2 &&
             png_ptr->height < 16384 && png_ptr->width < 16384)
         {
            png_uint_32 uncompressed_idat_size = png_ptr->height *
               ((png_ptr->width *
               png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
            unsigned int z_cinfo = z_cmf >> 4;
            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
            while (uncompressed_idat_size <= half_z_window_size &&
                   half_z_window_size >= 256)
            {
               z_cinfo--;
               half_z_window_size >>= 1;
            }
            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
            if (data[0] != (png_byte)z_cmf)
            {
               data[0] = (png_byte)z_cmf;
               data[1] &= 0xe0;
               data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
            }
         }
      }
      else
         png_error(png_ptr,
            "Invalid zlib compression method or flags in IDAT");
   }

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

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

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

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

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

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

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

771 772
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
773
void /* PRIVATE */
774 775 776 777 778 779 780 781 782
png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
   png_charp profile, int profile_len)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iCCP;
#endif
   png_size_t name_len;
   png_charp new_name;
   compression_state comp;
783
   int embedded_profile_len = 0;
784

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   /* loop through each palette entry, writing appropriately */
880
#ifndef PNG_NO_POINTER_INDEXING
881
   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
882
   {
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
      if (spalette->depth == 8)
      {
          entrybuf[0] = (png_byte)ep->red;
          entrybuf[1] = (png_byte)ep->green;
          entrybuf[2] = (png_byte)ep->blue;
          entrybuf[3] = (png_byte)ep->alpha;
          png_save_uint_16(entrybuf + 4, ep->frequency);
      }
      else
      {
          png_save_uint_16(entrybuf + 0, ep->red);
          png_save_uint_16(entrybuf + 2, ep->green);
          png_save_uint_16(entrybuf + 4, ep->blue);
          png_save_uint_16(entrybuf + 6, ep->alpha);
          png_save_uint_16(entrybuf + 8, ep->frequency);
      }
899
      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
900
   }
901 902 903 904
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
      if (spalette->depth == 8)
      {
          entrybuf[0] = (png_byte)ep[i].red;
          entrybuf[1] = (png_byte)ep[i].green;
          entrybuf[2] = (png_byte)ep[i].blue;
          entrybuf[3] = (png_byte)ep[i].alpha;
          png_save_uint_16(entrybuf + 4, ep[i].frequency);
      }
      else
      {
          png_save_uint_16(entrybuf + 0, ep[i].red);
          png_save_uint_16(entrybuf + 2, ep[i].green);
          png_save_uint_16(entrybuf + 4, ep[i].blue);
          png_save_uint_16(entrybuf + 6, ep[i].alpha);
          png_save_uint_16(entrybuf + 8, ep[i].frequency);
      }
921
      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
922 923
   }
#endif
924 925 926 927 928 929

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

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

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

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

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

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

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

   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 已提交
1001

1002
   png_debug(1, "in png_write_cHRM");
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014

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

   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))
G
Guy Schalnat 已提交
1015
   {
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
     /* 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);
1031
   }
G
Guy Schalnat 已提交
1032
}
G
Guy Schalnat 已提交
1033
#endif
1034
#ifdef PNG_FIXED_POINT_SUPPORTED
1035
void /* PRIVATE */
1036 1037 1038 1039
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)
1040 1041 1042 1043 1044 1045
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

1046
   png_debug(1, "in png_write_cHRM");
1047
   /* each value is saved in 1/100,000ths */
1048 1049
   if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y,
      green_x, green_y, blue_x, blue_y))
1050
   {
1051 1052
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
1053

1054 1055
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1056

1057 1058
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1059

1060 1061
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1062

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1351
   png_debug(1, "in png_write_tEXt");
A
Andreas Dilger 已提交
1352 1353
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1354
      png_warning(png_ptr, "Empty keyword in tEXt chunk");
G
Guy Schalnat 已提交
1355
      return;
A
Andreas Dilger 已提交
1356
   }
G
Guy Schalnat 已提交
1357

A
Andreas Dilger 已提交
1358
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1359
      text_len = 0;
1360 1361
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1362 1363

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

G
Guy Schalnat 已提交
1377
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1378
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1379
}
G
Guy Schalnat 已提交
1380
#endif
G
Guy Schalnat 已提交
1381

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

1396
   png_debug(1, "in png_write_zTXt");
A
Andreas Dilger 已提交
1397

1398 1399 1400 1401 1402 1403
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

A
Andreas Dilger 已提交
1404 1405
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1406
      png_warning(png_ptr, "Empty keyword in zTXt chunk");
1407
      png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1408
      return;
A
Andreas Dilger 已提交
1409
   }
A
Andreas Dilger 已提交
1410

A
Andreas Dilger 已提交
1411 1412
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
1413
      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
A
Andreas Dilger 已提交
1414 1415 1416 1417
      png_free(png_ptr, new_key);
      return;
   }

1418 1419
   text_len = png_strlen(text);

1420
   /* compute the compressed data; do it now for the length */
1421 1422
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1423

1424
   /* write start of chunk */
1425 1426
   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt,
     (png_uint_32)(key_len+text_len + 2));
1427
   /* write key */
1428 1429 1430 1431
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
   png_free(png_ptr, new_key);

1432 1433
   buf[0] = (png_byte)compression;
   /* write compression */
1434
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
1435 1436
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1437

1438 1439 1440 1441
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1442

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

1457
   png_debug(1, "in png_write_iTXt");
G
Guy Schalnat 已提交
1458

1459 1460 1461 1462 1463
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

1464
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1465
   {
1466
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1467 1468
      return;
   }
1469
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1470
   {
1471
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1472
      new_lang = NULL;
1473
      lang_len = 0;
1474
   }
G
Guy Schalnat 已提交
1475

1476 1477 1478 1479 1480 1481
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1482
      text_len = 0;
1483 1484
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1485

1486
   /* compute the compressed data; do it now for the length */
1487 1488
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1489

1490

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

1494 1495 1496 1497 1498 1499 1500
   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 已提交
1501

1502 1503 1504 1505 1506 1507
   /*
    * 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.
    */
1508 1509
   png_write_chunk_data(png_ptr, (png_bytep)new_key,
     (png_size_t)(key_len + 1));
1510 1511 1512 1513 1514 1515 1516 1517 1518

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

1521
   cbuf[0] = 0;
1522 1523 1524 1525
   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));
1526
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1527 1528

   png_write_chunk_end(png_ptr);
1529
   png_free(png_ptr, new_key);
1530
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1531
}
G
Guy Schalnat 已提交
1532
#endif
G
Guy Schalnat 已提交
1533

A
Andreas Dilger 已提交
1534 1535
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1536
void /* PRIVATE */
1537
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1538 1539
   int unit_type)
{
1540 1541 1542
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1543 1544
   png_byte buf[9];

1545
   png_debug(1, "in png_write_oFFs");
A
Andreas Dilger 已提交
1546 1547
   if (unit_type >= PNG_OFFSET_LAST)
      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
G
Guy Schalnat 已提交
1548

1549 1550
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1551
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1552

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

1571
   png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
A
Andreas Dilger 已提交
1572 1573 1574 1575
   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;
1576
   png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
A
Andreas Dilger 已提交
1577
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1578
   png_debug1(3, "pCAL units length = %d", (int)units_len);
A
Andreas Dilger 已提交
1579 1580
   total_len = purpose_len + units_len + 10;

1581
   params_len = (png_uint_32p)png_malloc(png_ptr,
1582
      (png_size_t)(nparams * png_sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1583 1584 1585 1586 1587 1588

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

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

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

1613
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1614 1615 1616 1617
   png_write_chunk_end(png_ptr);
}
#endif

1618 1619
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1620
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1621
void /* PRIVATE */
1622
png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
1623 1624 1625 1626
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1627
   char buf[64];
1628
   png_size_t total_len;
1629

1630
   png_debug(1, "in png_write_sCAL");
1631

1632
   buf[0] = (char)unit;
1633
   png_snprintf(buf + 1, 63, "%12.12e", width);
1634
   total_len = 1 + png_strlen(buf + 1) + 1;
1635
   png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
1636
   total_len += png_strlen(buf + total_len);
1637

1638
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1639
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len);
1640
}
1641 1642
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1643
void /* PRIVATE */
1644
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1645 1646 1647 1648 1649
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1650 1651
   png_byte buf[64];
   png_size_t wlen, hlen, total_len;
1652

1653
   png_debug(1, "in png_write_sCAL_s");
1654

1655 1656 1657 1658 1659 1660 1661 1662
   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;
   }
1663

1664 1665 1666
   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 */
1667

1668
   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1669
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
1670 1671
}
#endif
1672 1673
#endif
#endif
1674

A
Andreas Dilger 已提交
1675 1676
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1677
void /* PRIVATE */
A
Andreas Dilger 已提交
1678 1679
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1680 1681
   int unit_type)
{
1682 1683 1684
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1685 1686
   png_byte buf[9];

1687
   png_debug(1, "in png_write_pHYs");
A
Andreas Dilger 已提交
1688 1689
   if (unit_type >= PNG_RESOLUTION_LAST)
      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
G
Guy Schalnat 已提交
1690

A
Andreas Dilger 已提交
1691 1692
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1693
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1694

1695
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1696
}
G
Guy Schalnat 已提交
1697
#endif
G
Guy Schalnat 已提交
1698

G
Guy Schalnat 已提交
1699
#if defined(PNG_WRITE_tIME_SUPPORTED)
1700 1701 1702
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1703
void /* PRIVATE */
G
Guy Schalnat 已提交
1704
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1705
{
1706 1707 1708
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1709 1710
   png_byte buf[7];

1711
   png_debug(1, "in png_write_tIME");
G
Guy Schalnat 已提交
1712 1713 1714 1715 1716 1717 1718 1719
   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 已提交
1720 1721 1722 1723 1724 1725 1726
   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;

1727
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1728
}
G
Guy Schalnat 已提交
1729
#endif
G
Guy Schalnat 已提交
1730 1731

/* initializes the row writing capability of libpng */
1732
void /* PRIVATE */
G
Guy Schalnat 已提交
1733
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1734
{
1735
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1736
#ifdef PNG_USE_LOCAL_ARRAYS
1737
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1738

1739 1740
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1741

1742 1743
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1744

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

1748 1749
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1750
#endif
1751
#endif
1752

A
Andreas Dilger 已提交
1753 1754
   png_size_t buf_size;

1755
   png_debug(1, "in png_write_start_row");
1756
   buf_size = (png_size_t)(PNG_ROWBYTES(
1757
      png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1);
A
Andreas Dilger 已提交
1758

G
Guy Schalnat 已提交
1759
   /* set up row buffer */
1760 1761
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr,
     (png_size_t)buf_size);
A
Andreas Dilger 已提交
1762
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1763

1764
#ifndef PNG_NO_WRITE_FILTER
G
Guy Schalnat 已提交
1765 1766
   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1767
   {
A
Andreas Dilger 已提交
1768
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1769
         (png_size_t)(png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1770
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1771 1772
   }

A
Andreas Dilger 已提交
1773
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1774 1775 1776
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1777 1778
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr,
        (png_size_t)buf_size);
A
Andreas Dilger 已提交
1779
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1780 1781 1782

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
1853 1854
   int ret;

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

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

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

      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2163

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2358

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2566 2567 2568
         b = *pp++;
         c = *cp++;
         a = *lp++;
2569

2570 2571
         p = b - c;
         pc = a - c;
2572 2573

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

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

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

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

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

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

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

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

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

2640 2641 2642
         b = *pp++;
         c = *cp++;
         a = *lp++;
2643 2644

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
2735

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

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

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

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

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

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

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

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