pngwutil.c 82.4 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
{
A
Andreas Dilger 已提交
90
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
A
Andreas Dilger 已提交
91 92
   png_write_chunk_data(png_ptr, data, length);
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
93 94
}

A
Andreas Dilger 已提交
95
/* Write the start of a PNG chunk.  The type is the chunk type.
96 97 98
 * The total_length is the sum of the lengths of all the data you will be
 * passing in png_write_chunk_data().
 */
99
void PNGAPI
A
Andreas Dilger 已提交
100 101
png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
   png_uint_32 length)
G
Guy Schalnat 已提交
102
{
103 104 105 106 107 108 109 110 111 112
   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 已提交
113

114
   /* write the length and the chunk name */
A
Andreas Dilger 已提交
115
   png_save_uint_32(buf, length);
116 117 118 119 120
   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 已提交
121

G
Guy Schalnat 已提交
122 123
   /* reset the crc and run it over the chunk name */
   png_reset_crc(png_ptr);
124 125 126 127 128 129 130 131
   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 已提交
132 133
}

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

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

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

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

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

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

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

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

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

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

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

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

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

358
   return((int)text_len);
359 360 361
}

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

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

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
378 379
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
380
      png_free(png_ptr, comp->output_ptr[i]);
381
      comp->output_ptr[i]=NULL;
382 383 384
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
385
      comp->output_ptr=NULL;
386 387 388 389 390
   /* 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);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

781
   if (profile == NULL)
782 783
      profile_len = 0;

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
   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;
     }

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

   /* 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);
809
   new_name[name_len+1]=0x00;
810 811 812 813 814 815 816 817 818 819 820 821
   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 */
822
void /* PRIVATE */
823
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
824 825 826 827 828 829 830
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sPLT;
#endif
   png_size_t name_len;
   png_charp new_name;
   png_byte entrybuf[10];
831 832
   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
   png_size_t palette_size = entry_size * spalette->nentries;
833
   png_sPLT_entryp ep;
834 835 836
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
837 838

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

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

   /* loop through each palette entry, writing appropriately */
853
#ifndef PNG_NO_POINTER_INDEXING
854 855
   for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
   {
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
      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);
873
   }
874 875 876 877
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
      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);
895 896
   }
#endif
897 898 899 900 901 902

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
973
   png_debug(1, "in png_write_cHRM\n");
974
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
975 976 977 978
   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");
979 980
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
981
#endif
G
Guy Schalnat 已提交
982 983
      return;
   }
984
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
985
   png_save_uint_32(buf, itemp);
986
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
987
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
988

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
1303 1304 1305 1306
   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 已提交
1307
   {
A
Andreas Dilger 已提交
1308
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1309
      {
A
Andreas Dilger 已提交
1310 1311
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1312
      }
A
Andreas Dilger 已提交
1313
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1314 1315
      {
         key_len--;
1316
         kwarn=1;
A
Andreas Dilger 已提交
1317 1318 1319
      }
      else
      {
A
Andreas Dilger 已提交
1320 1321
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1322 1323
      }
   }
A
Andreas Dilger 已提交
1324
   *dp = '\0';
1325 1326
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1327 1328

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

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

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

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

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

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

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

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

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

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

1404 1405 1406 1407 1408 1409
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;
   comp.input_len = 0;

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

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

1423 1424
   text_len = png_strlen(text);

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

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

1431 1432 1433 1434 1435 1436 1437
   /* 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 */
1438
   png_write_chunk_data(png_ptr, (png_bytep)buf, 1);
1439 1440
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1441

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

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

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

1463 1464 1465 1466 1467
   comp.num_output_ptr = 0;
   comp.max_output_ptr = 0;
   comp.output_ptr = NULL;
   comp.input = NULL;

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

1480 1481 1482 1483 1484 1485
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

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

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

1494

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

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

1506 1507 1508 1509 1510 1511 1512
   /*
    * 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);
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523

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

1524 1525 1526
   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);
1527
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1528 1529

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

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

A
Andreas Dilger 已提交
1547 1548 1549
   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 已提交
1550

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

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

A
Andreas Dilger 已提交
1559
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1560
/* write the pCAL chunk (described in the PNG extensions document) */
1561
void /* PRIVATE */
A
Andreas Dilger 已提交
1562 1563 1564
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)
{
1565 1566 1567
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1568
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1569 1570
   png_uint_32p params_len;
   png_byte buf[10];
1571
   png_charp new_purpose;
A
Andreas Dilger 已提交
1572 1573 1574 1575 1576 1577 1578
   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;
1579
   png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
A
Andreas Dilger 已提交
1580
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1581
   png_debug1(3, "pCAL units length = %d\n", (int)units_len);
A
Andreas Dilger 已提交
1582 1583
   total_len = purpose_len + units_len + 10;

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

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

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

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

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

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

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

1634
   buf[0] = (char)unit;
1635

1636 1637 1638 1639 1640 1641
   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);
1642
}
1643 1644
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1645
void /* PRIVATE */
1646
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1647 1648 1649 1650 1651
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
1652 1653
   png_byte buf[64];
   png_size_t wlen, hlen, total_len;
1654

1655
   png_debug(1, "in png_write_sCAL_s\n");
1656

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

1666 1667 1668
   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 */
1669

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

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

A
Andreas Dilger 已提交
1689 1690 1691
   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 已提交
1692

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

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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
1753 1754 1755
   png_size_t buf_size;

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

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

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

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

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
1847 1848
   int ret;

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

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

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

      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
2108 2109
/* This filters the row, chooses which filter to use, if it has not already
 * been specified by the application, and then writes the row out with the
2110 2111
 * chosen filter.
 */
2112
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
A
Andreas Dilger 已提交
2113
#define PNG_HISHIFT 10
2114 2115
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2116
void /* PRIVATE */
G
Guy Schalnat 已提交
2117
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2118
{
G
Guy Schalnat 已提交
2119
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2120
   png_uint_32 mins, bpp;
2121
   png_byte filter_to_do = png_ptr->do_filter;
2122 2123 2124 2125
   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 已提交
2126

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

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

2156

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2351

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2559 2560 2561
         b = *pp++;
         c = *cp++;
         a = *lp++;
2562

2563 2564
         p = b - c;
         pc = a - c;
2565 2566

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

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

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

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

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

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

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

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

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

2633 2634 2635
         b = *pp++;
         c = *cp++;
         a = *lp++;
2636 2637

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
2726

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

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

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

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

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

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

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

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