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

G
Guy Schalnat 已提交
11
#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 74 75 76
   if(png_ptr->sig_bytes < 3)
      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);
A
Andreas Dilger 已提交
92 93
   png_write_chunk_data(png_ptr, data, length);
   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 112 113
   png_byte buf[8];
   png_debug2(0, "Writing %s chunk, length = %lu\n", chunk_name,
      (unsigned long)length);

#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 已提交
114

115
   /* write the length and the chunk name */
A
Andreas Dilger 已提交
116
   png_save_uint_32(buf, length);
117 118 119 120 121
   png_memcpy(buf + 4, chunk_name, 4);
   png_write_data(png_ptr, buf, 8);

   /* put the chunk name into png_ptr->chunk_name */
   png_memcpy(png_ptr->chunk_name, chunk_name, 4);
A
Andreas Dilger 已提交
122

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 163 164 165 166 167 168
#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 已提交
169 170
   png_save_uint_32(buf, png_ptr->crc);

171
   png_write_data(png_ptr, buf, 4);
G
Guy Schalnat 已提交
172 173
}

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

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

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
215
#ifndef PNG_NO_STDIO
216
      char msg[50];
217
      png_sprintf(msg, "Unknown compression type %d", compression);
218 219 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
      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 */
259
      if (!(png_ptr->zstream.avail_out))
260 261 262 263 264 265 266 267 268 269 270 271 272 273
      {
         /* 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,
274
                  (png_size_t)(comp->max_output_ptr * sizeof(png_charpp)));
275
               png_memcpy(comp->output_ptr, old_ptr, old_max
276
                  * sizeof(png_charp));
277 278 279 280
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
281
                  (png_size_t)(comp->max_output_ptr * sizeof(png_charp)));
282 283 284
         }

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

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

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

333 334
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
335
               (png_charp)png_malloc(png_ptr, png_ptr->zbuf_size);
336 337 338
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
339

340 341 342 343 344 345 346 347 348 349 350 351
            /* 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");
352 353 354 355 356 357 358 359
      }
   } 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;

360
   return((int)text_len);
361 362 363
}

/* ship the compressed text out via chunk writes */
364
static void /* PRIVATE */
365 366 367 368 369 370 371
png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
{
   int i;

   /* handle the no-compression case */
   if (comp->input)
   {
372 373
       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
                            (png_size_t)comp->input_len);
374 375 376 377 378 379
       return;
   }

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
380 381
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
382
      png_free(png_ptr, comp->output_ptr[i]);
383
      comp->output_ptr[i]=NULL;
384 385 386
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
387
      comp->output_ptr=NULL;
388 389 390 391 392
   /* write anything left in zbuf */
   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
      png_write_chunk_data(png_ptr, png_ptr->zbuf,
         png_ptr->zbuf_size - png_ptr->zstream.avail_out);

393
   /* reset zlib for another zTXt/iTXt or image data */
394
   deflateReset(&png_ptr->zstream);
395
   png_ptr->zstream.data_type = Z_BINARY;
396 397 398
}
#endif

G
Guy Schalnat 已提交
399
/* Write the IHDR chunk, and update the png_struct with the necessary
400 401 402
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
403
void /* PRIVATE */
G
Guy Schalnat 已提交
404
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
405 406 407
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
408 409 410
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
G
Guy Schalnat 已提交
411 412
   png_byte buf[13]; /* buffer to store the IHDR info */

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

A
Andreas Dilger 已提交
457
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
458 459
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
460
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
461 462
   }

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

486
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
487 488
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
489 490
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
491
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
492
   }
493 494 495
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
496 497 498 499 500

   /* 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;
501
#if defined(PNG_MNG_FEATURES_SUPPORTED)
502
   png_ptr->filter_type = (png_byte)filter_type;
503
#endif
504
   png_ptr->compression_type = (png_byte)compression_type;
G
Guy Schalnat 已提交
505 506 507
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
508
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
509
   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
G
Guy Schalnat 已提交
510 511 512
   /* 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 已提交
513 514 515 516 517 518 519 520 521 522
   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 已提交
523 524

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

A
Andreas Dilger 已提交
527
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
528 529 530
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
531
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
532
   {
A
Andreas Dilger 已提交
533 534
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
535
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
536
      else
G
Guy Schalnat 已提交
537
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
538
   }
G
Guy Schalnat 已提交
539
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
540
   {
G
Guy Schalnat 已提交
541
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
542 543 544 545
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
546
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
547
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
548
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
549
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
550
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
551
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
552
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
553
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
554
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
555 556
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
557 558
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
559 560 561
   /* 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 已提交
562

G
Guy Schalnat 已提交
563
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
564 565 566
}

/* write the palette.  We are careful not to trust png_color to be in the
567
 * correct order for PNG, so people can redefine it to any convenient
568 569
 * structure.
 */
570
void /* PRIVATE */
A
Andreas Dilger 已提交
571
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
572
{
573 574 575
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
576
   png_uint_32 i;
G
Guy Schalnat 已提交
577
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
578 579
   png_byte buf[3];

A
Andreas Dilger 已提交
580
   png_debug(1, "in png_write_PLTE\n");
581
   if ((
582
#if defined(PNG_MNG_FEATURES_SUPPORTED)
583
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
584 585
#endif
        num_pal == 0) || num_pal > 256)
586 587
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
588
     {
589 590 591 592 593 594 595 596 597 598 599 600 601 602
        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 已提交
603 604
   }

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

608
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
609
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
610
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
611 612 613 614
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
615
      png_write_chunk_data(png_ptr, buf, 3);
G
Guy Schalnat 已提交
616
   }
617 618 619 620 621 622 623 624
#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;
625
      png_write_chunk_data(png_ptr, buf, 3);
626 627
   }
#endif
G
Guy Schalnat 已提交
628
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
629
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
630 631 632
}

/* write an IDAT chunk */
633
void /* PRIVATE */
A
Andreas Dilger 已提交
634
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
635
{
636 637 638
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
639
   png_debug(1, "in png_write_IDAT\n");
640

641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
   /* 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");
   }

680
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
681
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
682 683 684
}

/* write an IEND chunk */
685
void /* PRIVATE */
G
Guy Schalnat 已提交
686
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
687
{
688 689 690
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
691
   png_debug(1, "in png_write_IEND\n");
692
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, 0);
A
Andreas Dilger 已提交
693
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
694 695
}

G
Guy Schalnat 已提交
696
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
697
/* write a gAMA chunk */
698
#ifdef PNG_FLOATING_POINT_SUPPORTED
699
void /* PRIVATE */
A
Andreas Dilger 已提交
700
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
701
{
702 703 704
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
705 706 707
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
708
   png_debug(1, "in png_write_gAMA\n");
709
   /* file_gamma is saved in 1/100,000ths */
710
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
711
   png_save_uint_32(buf, igamma);
712
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, 4);
G
Guy Schalnat 已提交
713
}
G
Guy Schalnat 已提交
714
#endif
715
#ifdef PNG_FIXED_POINT_SUPPORTED
716
void /* PRIVATE */
717
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
718 719 720 721 722 723 724
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
725
   /* file_gamma is saved in 1/100,000ths */
726
   png_save_uint_32(buf, (png_uint_32)file_gamma);
727
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, 4);
728 729 730
}
#endif
#endif
G
Guy Schalnat 已提交
731

732 733
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
734
void /* PRIVATE */
735
png_write_sRGB(png_structp png_ptr, int srgb_intent)
736
{
737 738 739
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
740 741 742
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
743
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
744 745
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
746
   buf[0]=(png_byte)srgb_intent;
747
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, 1);
748 749 750
}
#endif

751 752
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
753
void /* PRIVATE */
754 755 756 757 758 759 760 761 762
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;
763
   int embedded_profile_len = 0;
764 765

   png_debug(1, "in png_write_iCCP\n");
766 767 768 769 770 771 772

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

773 774 775 776 777 778 779
   if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
      &new_name)) == 0)
   {
      png_warning(png_ptr, "Empty keyword in iCCP chunk");
      return;
   }

780
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
781
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
782

783
   if (profile == NULL)
784 785
      profile_len = 0;

786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
   if (profile_len > 3)
      embedded_profile_len = ((*(profile  ))<<24) | ((*(profile+1))<<16) |
          ((*(profile+2))<< 8) | ((*(profile+3))    );

   if (profile_len < embedded_profile_len)
     {
        png_warning(png_ptr,
          "Embedded profile length too large in iCCP chunk");
        return;
     }

   if (profile_len > embedded_profile_len)
     {
        png_warning(png_ptr,
          "Truncating profile to actual length in iCCP chunk");
        profile_len = embedded_profile_len;
     }

804
   if (profile_len)
805 806
       profile_len = png_text_compress(png_ptr, profile,
          (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
807 808 809 810

   /* make sure we include the NULL after the name and the compression type */
   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
          (png_uint_32)name_len+profile_len+2);
811
   new_name[name_len+1]=0x00;
812 813 814 815 816 817 818 819 820 821 822 823
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);

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

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

#if defined(PNG_WRITE_sPLT_SUPPORTED)
/* write a sPLT chunk */
824
void /* PRIVATE */
825
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
826 827 828 829 830 831 832
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sPLT;
#endif
   png_size_t name_len;
   png_charp new_name;
   png_byte entrybuf[10];
833 834
   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
   png_size_t palette_size = entry_size * spalette->nentries;
835
   png_sPLT_entryp ep;
836 837 838
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
839 840

   png_debug(1, "in png_write_sPLT\n");
841 842
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
843 844 845 846 847 848
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
849
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
850
      (png_uint_32)(name_len + 2 + palette_size));
851
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
852
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
853 854

   /* loop through each palette entry, writing appropriately */
855
#ifndef PNG_NO_POINTER_INDEXING
856 857
   for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
   {
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
      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);
      }
      png_write_chunk_data(png_ptr, entrybuf, entry_size);
875
   }
876 877 878 879
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
      if (spalette->depth == 8)
      {
          entrybuf[0] = (png_byte)ep[i].red;
          entrybuf[1] = (png_byte)ep[i].green;
          entrybuf[2] = (png_byte)ep[i].blue;
          entrybuf[3] = (png_byte)ep[i].alpha;
          png_save_uint_16(entrybuf + 4, ep[i].frequency);
      }
      else
      {
          png_save_uint_16(entrybuf + 0, ep[i].red);
          png_save_uint_16(entrybuf + 2, ep[i].green);
          png_save_uint_16(entrybuf + 4, ep[i].blue);
          png_save_uint_16(entrybuf + 6, ep[i].alpha);
          png_save_uint_16(entrybuf + 8, ep[i].frequency);
      }
      png_write_chunk_data(png_ptr, entrybuf, entry_size);
897 898
   }
#endif
899 900 901 902 903 904

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

G
Guy Schalnat 已提交
905
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
906
/* write the sBIT chunk */
907
void /* PRIVATE */
G
Guy Schalnat 已提交
908
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
909
{
910 911 912
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
913
   png_byte buf[4];
A
Andreas Dilger 已提交
914
   png_size_t size;
G
Guy Schalnat 已提交
915

A
Andreas Dilger 已提交
916
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
917
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
918 919
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
920
      png_byte maxbits;
G
Guy Schalnat 已提交
921

922 923
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
924 925
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
926 927 928 929 930
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
931 932 933 934 935 936 937
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
938 939 940 941 942
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
943 944 945 946 947 948
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
949 950 951 952 953
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
954 955 956
      buf[size++] = sbit->alpha;
   }

957
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
958
}
G
Guy Schalnat 已提交
959
#endif
G
Guy Schalnat 已提交
960

G
Guy Schalnat 已提交
961
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
962
/* write the cHRM chunk */
963
#ifdef PNG_FLOATING_POINT_SUPPORTED
964
void /* PRIVATE */
A
Andreas Dilger 已提交
965
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
966 967
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
968
{
969 970 971
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
972
   png_byte buf[32];
973
   png_uint_32 itemp;
G
Guy Schalnat 已提交
974

A
Andreas Dilger 已提交
975
   png_debug(1, "in png_write_cHRM\n");
976
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
977 978 979 980
   if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
       white_x + white_y > 1.0)
   {
      png_warning(png_ptr, "Invalid cHRM white point specified");
981 982
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
983
#endif
G
Guy Schalnat 已提交
984 985
      return;
   }
986
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
987
   png_save_uint_32(buf, itemp);
988
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
989
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
990

991
   if (red_x < 0 ||  red_y < 0 || red_x + red_y > 1.0)
G
Guy Schalnat 已提交
992 993 994 995
   {
      png_warning(png_ptr, "Invalid cHRM red point specified");
      return;
   }
996
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
997
   png_save_uint_32(buf + 8, itemp);
998
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
999
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
1000

1001
   if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
G
Guy Schalnat 已提交
1002 1003 1004 1005
   {
      png_warning(png_ptr, "Invalid cHRM green point specified");
      return;
   }
1006
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1007
   png_save_uint_32(buf + 16, itemp);
1008
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1009
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
1010

1011
   if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
G
Guy Schalnat 已提交
1012 1013 1014 1015
   {
      png_warning(png_ptr, "Invalid cHRM blue point specified");
      return;
   }
1016
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1017
   png_save_uint_32(buf + 24, itemp);
1018
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
1019
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
1020

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

   png_debug(1, "in png_write_cHRM\n");
1037
   /* each value is saved in 1/100,000ths */
1038 1039
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
1040
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
1041
#if !defined(PNG_NO_CONSOLE_IO)
1042 1043
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",(unsigned long)white_x,
        (unsigned long)white_y);
1044
#endif
1045 1046
      return;
   }
1047 1048
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
1049

1050
   if (red_x + red_y > 100000L)
1051
   {
1052
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
1053 1054
      return;
   }
1055 1056
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1057

1058
   if (green_x + green_y > 100000L)
1059
   {
1060
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
1061 1062
      return;
   }
1063 1064
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1065

1066
   if (blue_x + blue_y > 100000L)
1067
   {
1068
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
1069 1070
      return;
   }
1071 1072
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1073

1074
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, 32);
1075 1076 1077
}
#endif
#endif
G
Guy Schalnat 已提交
1078

G
Guy Schalnat 已提交
1079
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
1080
/* write the tRNS chunk */
1081
void /* PRIVATE */
G
Guy Schalnat 已提交
1082
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
1083 1084
   int num_trans, int color_type)
{
1085 1086 1087
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
1088 1089
   png_byte buf[6];

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

G
Guy Schalnat 已提交
1135
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1136
/* write the background chunk */
1137
void /* PRIVATE */
G
Guy Schalnat 已提交
1138
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1139
{
1140 1141 1142
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1143 1144
   png_byte buf[6];

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

G
Guy Schalnat 已提交
1188
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1189
/* write the histogram */
1190
void /* PRIVATE */
1191
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1192
{
1193 1194 1195
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1196
   int i;
G
Guy Schalnat 已提交
1197 1198
   png_byte buf[3];

A
Andreas Dilger 已提交
1199
   png_debug(1, "in png_write_hIST\n");
1200
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1201
   {
A
Andreas Dilger 已提交
1202 1203
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1204 1205 1206 1207
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1208 1209
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST,
      (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1210
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1211
   {
G
Guy Schalnat 已提交
1212
      png_save_uint_16(buf, hist[i]);
1213
      png_write_chunk_data(png_ptr, buf, 2);
G
Guy Schalnat 已提交
1214 1215 1216
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1217
#endif
G
Guy Schalnat 已提交
1218

1219 1220
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1221 1222 1223 1224 1225
/* 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 已提交
1226 1227 1228 1229
 *
 * 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 已提交
1230
 */
1231
png_size_t /* PRIVATE */
1232
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1233
{
A
Andreas Dilger 已提交
1234
   png_size_t key_len;
1235
   png_charp kp, dp;
A
Andreas Dilger 已提交
1236
   int kflag;
1237
   int kwarn=0;
A
Andreas Dilger 已提交
1238

A
Andreas Dilger 已提交
1239 1240 1241 1242
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1243
   {
1244
      png_warning(png_ptr, "zero length keyword");
1245
      return 0;
A
Andreas Dilger 已提交
1246
   }
A
Andreas Dilger 已提交
1247 1248 1249

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

1250
   *new_key = (png_charp)png_malloc_warn(png_ptr, key_len + 2);
1251 1252 1253
   if (*new_key == NULL)
   {
      png_warning(png_ptr, "Out of memory while procesing keyword");
1254
      return 0;
1255
   }
1256

A
Andreas Dilger 已提交
1257 1258
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1259
   {
1260
      if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1261
      {
1262
#ifndef PNG_NO_STDIO
A
Andreas Dilger 已提交
1263
         char msg[40];
A
Andreas Dilger 已提交
1264

1265
         png_sprintf(msg, "invalid keyword character 0x%02X", *kp);
1266
         png_warning(png_ptr, msg);
1267
#else
1268
         png_warning(png_ptr, "invalid character in keyword");
1269
#endif
A
Andreas Dilger 已提交
1270 1271 1272 1273 1274 1275
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1276
   }
A
Andreas Dilger 已提交
1277
   *dp = '\0';
A
Andreas Dilger 已提交
1278

A
Andreas Dilger 已提交
1279 1280 1281
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1282
   {
1283
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1284 1285 1286 1287 1288 1289

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1290 1291 1292
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1293 1294
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1295
   {
1296
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1297 1298 1299 1300 1301 1302

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

A
Andreas Dilger 已提交
1305 1306 1307 1308
   png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);

   /* Remove multiple internal spaces. */
   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
A
Andreas Dilger 已提交
1309
   {
A
Andreas Dilger 已提交
1310
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1311
      {
A
Andreas Dilger 已提交
1312 1313
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1314
      }
A
Andreas Dilger 已提交
1315
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1316 1317
      {
         key_len--;
1318
         kwarn=1;
A
Andreas Dilger 已提交
1319 1320 1321
      }
      else
      {
A
Andreas Dilger 已提交
1322 1323
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1324 1325
      }
   }
A
Andreas Dilger 已提交
1326
   *dp = '\0';
1327 1328
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1329 1330

   if (key_len == 0)
A
Andreas Dilger 已提交
1331
   {
1332 1333
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1334
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1335 1336 1337 1338
   }

   if (key_len > 79)
   {
1339
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1340 1341 1342
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1343

1344
   return (key_len);
A
Andreas Dilger 已提交
1345 1346 1347
}
#endif

G
Guy Schalnat 已提交
1348
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1349
/* write a tEXt chunk */
1350
void /* PRIVATE */
G
Guy Schalnat 已提交
1351
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1352
   png_size_t text_len)
G
Guy Schalnat 已提交
1353
{
1354 1355 1356
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1357
   png_size_t key_len;
1358
   png_charp new_key;
A
Andreas Dilger 已提交
1359 1360 1361 1362

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

A
Andreas Dilger 已提交
1367
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1368
      text_len = 0;
1369 1370
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1371 1372

   /* make sure we include the 0 after the key */
1373 1374
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt,
      (png_uint_32)key_len+text_len+1);
1375 1376 1377 1378
   /*
    * 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.
1379
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1380
    */
1381
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1382
   if (text_len)
A
Andreas Dilger 已提交
1383
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1384

G
Guy Schalnat 已提交
1385
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1386
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1387
}
G
Guy Schalnat 已提交
1388
#endif
G
Guy Schalnat 已提交
1389

G
Guy Schalnat 已提交
1390
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1391
/* write a compressed text chunk */
1392
void /* PRIVATE */
G
Guy Schalnat 已提交
1393
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1394
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1395
{
1396 1397 1398
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1399
   png_size_t key_len;
G
Guy Schalnat 已提交
1400
   char buf[1];
1401
   png_charp new_key;
1402
   compression_state comp;
G
Guy Schalnat 已提交
1403

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

1406 1407 1408 1409 1410 1411
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

A
Andreas Dilger 已提交
1412 1413
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1414
      png_warning(png_ptr, "Empty keyword in zTXt chunk");
G
Guy Schalnat 已提交
1415
      return;
A
Andreas Dilger 已提交
1416
   }
A
Andreas Dilger 已提交
1417

A
Andreas Dilger 已提交
1418 1419
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
1420
      png_write_tEXt(png_ptr, new_key, text, 0);
A
Andreas Dilger 已提交
1421 1422 1423 1424
      png_free(png_ptr, new_key);
      return;
   }

1425 1426
   text_len = png_strlen(text);

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

1429
   /* compute the compressed data; do it now for the length */
1430 1431
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1432

1433 1434 1435 1436 1437 1438 1439
   /* write start of chunk */
   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
      (key_len+text_len+2));
   /* write key */
   png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
   buf[0] = (png_byte)compression;
   /* write compression */
1440
   png_write_chunk_data(png_ptr, (png_bytep)buf, 1);
1441 1442
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1443

1444 1445 1446 1447
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1448

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

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

1465 1466 1467 1468 1469
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

1470
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1471
   {
1472
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1473 1474
      return;
   }
1475
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1476
   {
1477
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1478
      new_lang = NULL;
1479
      lang_len = 0;
1480
   }
G
Guy Schalnat 已提交
1481

1482 1483 1484 1485 1486 1487
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1488
      text_len = 0;
1489 1490
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1491

1492
   /* compute the compressed data; do it now for the length */
1493 1494
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1495

1496

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

1500 1501 1502 1503 1504 1505 1506
   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 已提交
1507

1508 1509 1510 1511 1512 1513 1514
   /*
    * We leave it to the application to meet PNG-1.0 requirements on the
    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
    */
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525

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

1526 1527 1528
   cbuf[0] = 0;
   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
1529
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1530 1531

   png_write_chunk_end(png_ptr);
1532
   png_free(png_ptr, new_key);
1533 1534
   if (new_lang)
     png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1535
}
G
Guy Schalnat 已提交
1536
#endif
G
Guy Schalnat 已提交
1537

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

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

1553 1554
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1555
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1556

1557
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, 9);
G
Guy Schalnat 已提交
1558
}
G
Guy Schalnat 已提交
1559
#endif
G
Guy Schalnat 已提交
1560

A
Andreas Dilger 已提交
1561
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1562
/* write the pCAL chunk (described in the PNG extensions document) */
1563
void /* PRIVATE */
A
Andreas Dilger 已提交
1564 1565 1566
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)
{
1567 1568 1569
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1570
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1571 1572
   png_uint_32p params_len;
   png_byte buf[10];
1573
   png_charp new_purpose;
A
Andreas Dilger 已提交
1574 1575 1576 1577 1578 1579 1580
   int i;

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

   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
1581
   png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
A
Andreas Dilger 已提交
1582
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1583
   png_debug1(3, "pCAL units length = %d\n", (int)units_len);
A
Andreas Dilger 已提交
1584 1585
   total_len = purpose_len + units_len + 10;

1586 1587
   params_len = (png_uint_32p)png_malloc(png_ptr,
      (png_size_t)(nparams * sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1588 1589 1590 1591 1592 1593

   /* 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);
1594 1595
      png_debug2(3, "pCAL parameter %d length = %lu\n", i,
        (unsigned long) params_len[i]);
A
Andreas Dilger 已提交
1596 1597 1598
      total_len += (png_size_t)params_len[i];
   }

1599
   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1600
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1601
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1602 1603 1604 1605
   png_save_int_32(buf, X0);
   png_save_int_32(buf + 4, X1);
   buf[8] = (png_byte)type;
   buf[9] = (png_byte)nparams;
1606 1607
   png_write_chunk_data(png_ptr, buf, 10);
   png_write_chunk_data(png_ptr, (png_bytep)units, units_len);
A
Andreas Dilger 已提交
1608 1609 1610 1611 1612 1613 1614 1615 1616

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

1617
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1618 1619 1620 1621
   png_write_chunk_end(png_ptr);
}
#endif

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

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

1636
   buf[0] = (char)unit;
1637

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

1657
   png_debug(1, "in png_write_sCAL_s\n");
1658

1659 1660 1661 1662 1663 1664 1665 1666
   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;
   }
1667

1668 1669 1670
   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 */
1671

1672 1673
   png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
1674 1675
}
#endif
1676 1677
#endif
#endif
1678

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

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

A
Andreas Dilger 已提交
1695 1696
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1697
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1698

1699
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, 9);
G
Guy Schalnat 已提交
1700
}
G
Guy Schalnat 已提交
1701
#endif
G
Guy Schalnat 已提交
1702

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

A
Andreas Dilger 已提交
1715
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1716 1717 1718 1719 1720 1721 1722 1723
   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 已提交
1724 1725 1726 1727 1728 1729 1730
   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;

1731
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, 7);
G
Guy Schalnat 已提交
1732
}
G
Guy Schalnat 已提交
1733
#endif
G
Guy Schalnat 已提交
1734 1735

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

1742 1743
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1744

1745 1746
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1747

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

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

A
Andreas Dilger 已提交
1755 1756 1757
   png_size_t buf_size;

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

G
Guy Schalnat 已提交
1761
   /* set up row buffer */
1762
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
A
Andreas Dilger 已提交
1763
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1764 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_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
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, buf_size);
A
Andreas Dilger 已提交
1778
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1779 1780 1781

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
1849 1850
   int ret;

A
Andreas Dilger 已提交
1851
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1852 1853
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1854

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

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

      }

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
1960
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1961
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1962 1963 1964 1965 1966
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
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
{
G
Guy Schalnat 已提交
2121
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2122
   png_uint_32 mins, bpp;
2123
   png_byte filter_to_do = png_ptr->do_filter;
2124 2125 2126 2127
   png_uint_32 row_bytes = row_info->rowbytes;
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   int num_p_filters = (int)png_ptr->num_prev_filters;
#endif
G
Guy Schalnat 已提交
2128

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

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

2158

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2353

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

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

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

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2391 2392 2393

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
2502
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2503 2504 2505

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

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

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

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

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

2561 2562 2563
         b = *pp++;
         c = *cp++;
         a = *lp++;
2564

2565 2566
         p = b - c;
         pc = a - c;
2567 2568

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

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

2580
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2581 2582 2583 2584 2585
      }
      best_row = png_ptr->paeth_row;
   }

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

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

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

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

G
Guy Schalnat 已提交
2628 2629
         sum += (v < 128) ? v : 256 - v;
      }
2630

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

2635 2636 2637
         b = *pp++;
         c = *cp++;
         a = *lp++;
2638 2639

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

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

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

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

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

2681
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2682
         {
2683
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2684
            {
2685
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2686
                  PNG_WEIGHT_SHIFT;
2687
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703
                  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 已提交
2704 2705 2706 2707
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2708 2709
   }

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

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

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

G
Guy Schalnat 已提交
2728

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

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

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

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

G
Guy Schalnat 已提交
2766
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2767
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2768 2769 2770 2771 2772 2773 2774 2775
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2776 2777
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2778

G
Guy Schalnat 已提交
2779 2780 2781 2782 2783 2784 2785
#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 已提交
2786
   }
2787
#endif
G
Guy Schalnat 已提交
2788
}
2789
#endif /* PNG_WRITE_SUPPORTED */