pngwutil.c 81.8 KB
Newer Older
G
Guy Schalnat 已提交
1

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * libpng version 1.2.8rc3 - November 28, 2004
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2004 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 12
#define PNG_INTERNAL
#include "png.h"
13
#ifdef PNG_WRITE_SUPPORTED
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 /* PRIVATE */
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_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_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 /* PRIVATE */
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);
}
A
Andreas Dilger 已提交
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 /* PRIVATE */
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);
}

A
Andreas Dilger 已提交
54
/* Write a PNG chunk all at once.  The type is an array of ASCII characters
55 56 57 58 59 60 61 62
 * 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.
 */
63
void PNGAPI
A
Andreas Dilger 已提交
64
png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
A
Andreas Dilger 已提交
65
   png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
66
{
A
Andreas Dilger 已提交
67
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
A
Andreas Dilger 已提交
68 69
   png_write_chunk_data(png_ptr, data, length);
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
70 71
}

A
Andreas Dilger 已提交
72
/* Write the start of a PNG chunk.  The type is the chunk type.
73 74 75
 * The total_length is the sum of the lengths of all the data you will be
 * passing in png_write_chunk_data().
 */
76
void PNGAPI
A
Andreas Dilger 已提交
77 78
png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
   png_uint_32 length)
G
Guy Schalnat 已提交
79
{
A
Andreas Dilger 已提交
80
   png_byte buf[4];
81
   png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
A
Andreas Dilger 已提交
82

G
Guy Schalnat 已提交
83
   /* write the length */
A
Andreas Dilger 已提交
84 85 86
   png_save_uint_32(buf, length);
   png_write_data(png_ptr, buf, (png_size_t)4);

G
Guy Schalnat 已提交
87
   /* write the chunk name */
A
Andreas Dilger 已提交
88
   png_write_data(png_ptr, chunk_name, (png_size_t)4);
G
Guy Schalnat 已提交
89 90
   /* reset the crc and run it over the chunk name */
   png_reset_crc(png_ptr);
A
Andreas Dilger 已提交
91
   png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
G
Guy Schalnat 已提交
92 93
}

A
Andreas Dilger 已提交
94
/* Write the data of a PNG chunk started with png_write_chunk_start().
95 96 97 98
 * 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().
 */
99
void PNGAPI
A
Andreas Dilger 已提交
100
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
101
{
A
Andreas Dilger 已提交
102 103
   /* write the data, and run the CRC over it */
   if (data != NULL && length > 0)
G
Guy Schalnat 已提交
104 105
   {
      png_calculate_crc(png_ptr, data, length);
G
Guy Schalnat 已提交
106
      png_write_data(png_ptr, data, length);
G
Guy Schalnat 已提交
107 108 109
   }
}

A
Andreas Dilger 已提交
110
/* Finish a chunk started with png_write_chunk_start(). */
111
void PNGAPI
G
Guy Schalnat 已提交
112
png_write_chunk_end(png_structp png_ptr)
G
Guy Schalnat 已提交
113
{
A
Andreas Dilger 已提交
114 115
   png_byte buf[4];

G
Guy Schalnat 已提交
116
   /* write the crc */
A
Andreas Dilger 已提交
117 118 119
   png_save_uint_32(buf, png_ptr->crc);

   png_write_data(png_ptr, buf, (png_size_t)4);
G
Guy Schalnat 已提交
120 121
}

A
Andreas Dilger 已提交
122 123 124 125
/* 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
126 127
 * bytes have already been written.
 */
128
void /* PRIVATE */
G
Guy Schalnat 已提交
129
png_write_sig(png_structp png_ptr)
G
Guy Schalnat 已提交
130
{
131
   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
A
Andreas Dilger 已提交
132
   /* write the rest of the 8 byte signature */
133
   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
A
Andreas Dilger 已提交
134
      (png_size_t)8 - png_ptr->sig_bytes);
135 136
   if(png_ptr->sig_bytes < 3)
      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
G
Guy Schalnat 已提交
137 138
}

139
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/*
 * 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 */
157
static int /* PRIVATE */
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
png_text_compress(png_structp png_ptr,
        png_charp text, png_size_t text_len, int compression,
        compression_state *comp)
{
   int ret;

   comp->num_output_ptr = comp->max_output_ptr = 0;
   comp->output_ptr = NULL;
   comp->input = NULL;

   /* we may just want to pass the text right through */
   if (compression == PNG_TEXT_COMPRESSION_NONE)
   {
       comp->input = text;
       comp->input_len = text_len;
173
       return((int)text_len);
174 175 176 177
   }

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
178
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
      char msg[50];
      sprintf(msg, "Unknown compression type %d", compression);
      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 */
222
      if (!(png_ptr->zstream.avail_out))
223 224 225 226 227 228 229 230 231 232 233 234 235 236
      {
         /* 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,
237 238
                  (png_uint_32)(comp->max_output_ptr *
                  png_sizeof (png_charpp)));
239
               png_memcpy(comp->output_ptr, old_ptr, old_max
240
                  * png_sizeof (png_charp));
241 242 243 244
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
245 246
                  (png_uint_32)(comp->max_output_ptr *
                  png_sizeof (png_charp)));
247 248 249 250 251
         }

         /* save the data */
         comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
            (png_uint_32)png_ptr->zbuf_size);
252 253 254
         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
            png_ptr->zbuf_size);
         comp->num_output_ptr++;
255 256 257 258 259 260 261 262 263 264 265 266 267 268

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

269
      if (ret == Z_OK)
270
      {
271 272
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
273
         {
274 275
            /* check to make sure our output array has room */
            if (comp->num_output_ptr >= comp->max_output_ptr)
276
            {
277 278 279 280 281 282 283 284 285 286 287
               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,
288 289
                     (png_uint_32)(comp->max_output_ptr *
                     png_sizeof (png_charpp)));
290
                  png_memcpy(comp->output_ptr, old_ptr,
291
                     old_max * png_sizeof (png_charp));
292 293 294 295
                  png_free(png_ptr, old_ptr);
               }
               else
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
296 297
                     (png_uint_32)(comp->max_output_ptr *
                     png_sizeof (png_charp)));
298 299
            }

300 301 302
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
               (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
303 304 305
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
306

307 308 309 310 311 312 313 314 315 316 317 318
            /* 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");
319 320 321 322 323 324 325 326
      }
   } 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;

327
   return((int)text_len);
328 329 330
}

/* ship the compressed text out via chunk writes */
331
static void /* PRIVATE */
332 333 334 335 336 337 338
png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
{
   int i;

   /* handle the no-compression case */
   if (comp->input)
   {
339 340
       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
                            (png_size_t)comp->input_len);
341 342 343 344 345 346
       return;
   }

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
347 348
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
349
      png_free(png_ptr, comp->output_ptr[i]);
350
      comp->output_ptr[i]=NULL;
351 352 353
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
354
      comp->output_ptr=NULL;
355 356 357 358 359
   /* 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);

360
   /* reset zlib for another zTXt/iTXt or image data */
361
   deflateReset(&png_ptr->zstream);
362
   png_ptr->zstream.data_type = Z_BINARY;
363 364 365
}
#endif

G
Guy Schalnat 已提交
366
/* Write the IHDR chunk, and update the png_struct with the necessary
367 368 369
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
370
void /* PRIVATE */
G
Guy Schalnat 已提交
371
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
372 373 374
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
375 376 377
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
G
Guy Schalnat 已提交
378 379
   png_byte buf[13]; /* buffer to store the IHDR info */

A
Andreas Dilger 已提交
380
   png_debug(1, "in png_write_IHDR\n");
G
Guy Schalnat 已提交
381
   /* Check that we have valid input data from the application info */
G
Guy Schalnat 已提交
382 383
   switch (color_type)
   {
A
Andreas Dilger 已提交
384
      case PNG_COLOR_TYPE_GRAY:
G
Guy Schalnat 已提交
385 386 387 388 389 390 391
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8:
            case 16: png_ptr->channels = 1; break;
A
Andreas Dilger 已提交
392
            default: png_error(png_ptr,"Invalid bit depth for grayscale image");
G
Guy Schalnat 已提交
393
         }
G
Guy Schalnat 已提交
394
         break;
A
Andreas Dilger 已提交
395
      case PNG_COLOR_TYPE_RGB:
G
Guy Schalnat 已提交
396 397
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGB image");
G
Guy Schalnat 已提交
398 399
         png_ptr->channels = 3;
         break;
A
Andreas Dilger 已提交
400
      case PNG_COLOR_TYPE_PALETTE:
G
Guy Schalnat 已提交
401 402 403 404 405 406 407 408 409
         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 已提交
410
      case PNG_COLOR_TYPE_GRAY_ALPHA:
G
Guy Schalnat 已提交
411 412
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
G
Guy Schalnat 已提交
413 414
         png_ptr->channels = 2;
         break;
A
Andreas Dilger 已提交
415
      case PNG_COLOR_TYPE_RGB_ALPHA:
G
Guy Schalnat 已提交
416 417
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGBA image");
G
Guy Schalnat 已提交
418 419
         png_ptr->channels = 4;
         break;
G
Guy Schalnat 已提交
420 421 422 423
      default:
         png_error(png_ptr, "Invalid image color type specified");
   }

A
Andreas Dilger 已提交
424
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
425 426
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
427
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
428 429
   }

430 431 432 433 434 435 436 437 438
   /* 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
    */
439 440 441
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
442
      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
443
      (color_type == PNG_COLOR_TYPE_RGB ||
444
       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
445 446 447
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
448 449
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
450
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
451 452
   }

453
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
454 455
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
456 457
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
458
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
459
   }
460 461 462
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
463 464 465 466 467

   /* 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;
468
#if defined(PNG_MNG_FEATURES_SUPPORTED)
469
   png_ptr->filter_type = (png_byte)filter_type;
470
#endif
471
   png_ptr->compression_type = (png_byte)compression_type;
G
Guy Schalnat 已提交
472 473 474
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
475
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
476
   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
G
Guy Schalnat 已提交
477 478 479
   /* 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 已提交
480 481 482 483 484 485 486 487 488 489
   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 已提交
490 491

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

A
Andreas Dilger 已提交
494
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
495 496 497
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
498
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
499
   {
A
Andreas Dilger 已提交
500 501
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
502
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
503
      else
G
Guy Schalnat 已提交
504
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
505
   }
G
Guy Schalnat 已提交
506
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
507
   {
G
Guy Schalnat 已提交
508
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
509 510 511 512
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
513
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
514
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
515
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
516
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
517
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
518
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
519
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
520
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
521
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
522 523
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
524 525
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
526 527 528
   /* 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 已提交
529

G
Guy Schalnat 已提交
530
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
531 532 533
}

/* write the palette.  We are careful not to trust png_color to be in the
534
 * correct order for PNG, so people can redefine it to any convenient
535 536
 * structure.
 */
537
void /* PRIVATE */
A
Andreas Dilger 已提交
538
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
539
{
540 541 542
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
543
   png_uint_32 i;
G
Guy Schalnat 已提交
544
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
545 546
   png_byte buf[3];

A
Andreas Dilger 已提交
547
   png_debug(1, "in png_write_PLTE\n");
548
   if ((
549
#if defined(PNG_MNG_FEATURES_SUPPORTED)
550
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
551 552
#endif
        num_pal == 0) || num_pal > 256)
553 554
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
555
     {
556 557 558 559 560 561 562 563 564 565 566 567 568 569
        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 已提交
570 571
   }

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

575
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
576
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
577
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
578 579 580 581
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
582
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
583
   }
584 585 586 587 588 589 590 591 592 593 594
#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;
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
   }
#endif
G
Guy Schalnat 已提交
595
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
596
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
597 598 599
}

/* write an IDAT chunk */
600
void /* PRIVATE */
A
Andreas Dilger 已提交
601
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
602
{
603 604 605
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
606
   png_debug(1, "in png_write_IDAT\n");
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
   /* 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");
   }

647
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
648
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
649 650 651
}

/* write an IEND chunk */
652
void /* PRIVATE */
G
Guy Schalnat 已提交
653
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
654
{
655 656 657
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
658
   png_debug(1, "in png_write_IEND\n");
659
   png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
660
     (png_size_t)0);
A
Andreas Dilger 已提交
661
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
662 663
}

G
Guy Schalnat 已提交
664
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
665
/* write a gAMA chunk */
666
#ifdef PNG_FLOATING_POINT_SUPPORTED
667
void /* PRIVATE */
A
Andreas Dilger 已提交
668
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
669
{
670 671 672
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
673 674 675
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
676
   png_debug(1, "in png_write_gAMA\n");
677
   /* file_gamma is saved in 1/100,000ths */
678
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
679
   png_save_uint_32(buf, igamma);
680
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
681
}
G
Guy Schalnat 已提交
682
#endif
683
#ifdef PNG_FIXED_POINT_SUPPORTED
684
void /* PRIVATE */
685
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
686 687 688 689 690 691 692
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
693
   /* file_gamma is saved in 1/100,000ths */
694
   png_save_uint_32(buf, (png_uint_32)file_gamma);
695 696 697 698
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
}
#endif
#endif
G
Guy Schalnat 已提交
699

700 701
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
702
void /* PRIVATE */
703
png_write_sRGB(png_structp png_ptr, int srgb_intent)
704
{
705 706 707
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
708 709 710
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
711
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
712 713
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
714
   buf[0]=(png_byte)srgb_intent;
715
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
716 717 718
}
#endif

719 720
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
721
void /* PRIVATE */
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
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;

   png_debug(1, "in png_write_iCCP\n");
   if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
      &new_name)) == 0)
   {
      png_warning(png_ptr, "Empty keyword in iCCP chunk");
      return;
   }

740
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
741
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
742

743
   if (profile == NULL)
744 745 746
      profile_len = 0;

   if (profile_len)
747
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
748
          PNG_COMPRESSION_TYPE_BASE, &comp);
749 750 751 752

   /* 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);
753
   new_name[name_len+1]=0x00;
754 755 756 757 758 759 760 761 762 763 764 765
   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 */
766
void /* PRIVATE */
767
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
768 769 770 771 772 773 774 775 776
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sPLT;
#endif
   png_size_t name_len;
   png_charp new_name;
   png_byte entrybuf[10];
   int entry_size = (spalette->depth == 8 ? 6 : 10);
   int palette_size = entry_size * spalette->nentries;
777
   png_sPLT_entryp ep;
778 779 780
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
781 782

   png_debug(1, "in png_write_sPLT\n");
783 784
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
785 786 787 788 789 790
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
791
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
792
          (png_uint_32)(name_len + 2 + palette_size));
793
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
794
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
795 796

   /* loop through each palette entry, writing appropriately */
797
#ifndef PNG_NO_POINTER_INDEXING
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
   for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
   {
       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);
       }
816
       png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
817
   }
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
#else
   ep=spalette->entries;
   for (i=0; i>spalette->nentries; i++)
   {
       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);
   }
#endif
841 842 843 844 845 846

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

G
Guy Schalnat 已提交
847
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
848
/* write the sBIT chunk */
849
void /* PRIVATE */
G
Guy Schalnat 已提交
850
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
851
{
852 853 854
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
855
   png_byte buf[4];
A
Andreas Dilger 已提交
856
   png_size_t size;
G
Guy Schalnat 已提交
857

A
Andreas Dilger 已提交
858
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
859
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
860 861
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
862
      png_byte maxbits;
G
Guy Schalnat 已提交
863

864 865
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
866 867
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
868 869 870 871 872
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
873 874 875 876 877 878 879
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
880 881 882 883 884
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
885 886 887 888 889 890
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
891 892 893 894 895
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
896 897 898
      buf[size++] = sbit->alpha;
   }

899
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
900
}
G
Guy Schalnat 已提交
901
#endif
G
Guy Schalnat 已提交
902

G
Guy Schalnat 已提交
903
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
904
/* write the cHRM chunk */
905
#ifdef PNG_FLOATING_POINT_SUPPORTED
906
void /* PRIVATE */
A
Andreas Dilger 已提交
907
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
908 909
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
910
{
911 912 913
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
914
   png_byte buf[32];
915
   png_uint_32 itemp;
G
Guy Schalnat 已提交
916

A
Andreas Dilger 已提交
917
   png_debug(1, "in png_write_cHRM\n");
918
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
919 920 921 922
   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");
923 924
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
925
#endif
G
Guy Schalnat 已提交
926 927
      return;
   }
928
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
929
   png_save_uint_32(buf, itemp);
930
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
931
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
932 933 934 935 936 937 938

   if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
       red_x + red_y > 1.0)
   {
      png_warning(png_ptr, "Invalid cHRM red point specified");
      return;
   }
939
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
940
   png_save_uint_32(buf + 8, itemp);
941
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
942
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
943 944 945 946 947 948 949

   if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
       green_x + green_y > 1.0)
   {
      png_warning(png_ptr, "Invalid cHRM green point specified");
      return;
   }
950
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
951
   png_save_uint_32(buf + 16, itemp);
952
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
953
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
954 955 956 957 958 959 960

   if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
       blue_x + blue_y > 1.0)
   {
      png_warning(png_ptr, "Invalid cHRM blue point specified");
      return;
   }
961
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
962
   png_save_uint_32(buf + 24, itemp);
963
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
964
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
965

966
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
967
}
G
Guy Schalnat 已提交
968
#endif
969
#ifdef PNG_FIXED_POINT_SUPPORTED
970
void /* PRIVATE */
971 972 973 974
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)
975 976 977 978 979 980 981
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
982
   /* each value is saved in 1/100,000ths */
983 984
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
985
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
986 987
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
988
#endif
989 990
      return;
   }
991 992
   png_save_uint_32(buf, (png_uint_32)white_x);
   png_save_uint_32(buf + 4, (png_uint_32)white_y);
993 994 995

   if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
   {
996
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
997 998
      return;
   }
999 1000
   png_save_uint_32(buf + 8, (png_uint_32)red_x);
   png_save_uint_32(buf + 12, (png_uint_32)red_y);
1001 1002 1003

   if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
   {
1004
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
1005 1006
      return;
   }
1007 1008
   png_save_uint_32(buf + 16, (png_uint_32)green_x);
   png_save_uint_32(buf + 20, (png_uint_32)green_y);
1009 1010 1011

   if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
   {
1012
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
1013 1014
      return;
   }
1015 1016
   png_save_uint_32(buf + 24, (png_uint_32)blue_x);
   png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1017 1018 1019 1020 1021

   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
}
#endif
#endif
G
Guy Schalnat 已提交
1022

G
Guy Schalnat 已提交
1023
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
1024
/* write the tRNS chunk */
1025
void /* PRIVATE */
G
Guy Schalnat 已提交
1026
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
1027 1028
   int num_trans, int color_type)
{
1029 1030 1031
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
1032 1033
   png_byte buf[6];

A
Andreas Dilger 已提交
1034
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
1035 1036
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1037
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1038 1039 1040 1041
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
1042
      /* write the chunk out as it is */
1043
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
1044 1045 1046 1047
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
1048 1049 1050 1051 1052 1053
      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 已提交
1054
      png_save_uint_16(buf, tran->gray);
1055
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1056 1057 1058 1059 1060 1061 1062
   }
   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);
1063 1064 1065 1066 1067 1068
      if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
         {
            png_warning(png_ptr,
              "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
            return;
         }
1069
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1070
   }
G
Guy Schalnat 已提交
1071 1072
   else
   {
1073
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1074
   }
G
Guy Schalnat 已提交
1075
}
G
Guy Schalnat 已提交
1076
#endif
G
Guy Schalnat 已提交
1077

G
Guy Schalnat 已提交
1078
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1079
/* write the background chunk */
1080
void /* PRIVATE */
G
Guy Schalnat 已提交
1081
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1082
{
1083 1084 1085
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1086 1087
   png_byte buf[6];

A
Andreas Dilger 已提交
1088
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
1089 1090
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1091
      if (
1092
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1093 1094
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1095 1096
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1097 1098 1099 1100
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1101
      buf[0] = back->index;
1102
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1103 1104 1105 1106 1107 1108
   }
   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);
1109 1110 1111 1112 1113 1114
      if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
         {
            png_warning(png_ptr,
              "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
            return;
         }
1115
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1116 1117
   }
   else
G
Guy Schalnat 已提交
1118
   {
1119 1120 1121 1122 1123 1124
      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 已提交
1125
      png_save_uint_16(buf, back->gray);
1126
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1127 1128
   }
}
G
Guy Schalnat 已提交
1129
#endif
G
Guy Schalnat 已提交
1130

G
Guy Schalnat 已提交
1131
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1132
/* write the histogram */
1133
void /* PRIVATE */
1134
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1135
{
1136 1137 1138
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1139
   int i;
G
Guy Schalnat 已提交
1140 1141
   png_byte buf[3];

A
Andreas Dilger 已提交
1142
   png_debug(1, "in png_write_hIST\n");
1143
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1144
   {
A
Andreas Dilger 已提交
1145 1146
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1147 1148 1149 1150
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1151
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1152
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1153
   {
G
Guy Schalnat 已提交
1154
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1155
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1156 1157 1158
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1159
#endif
G
Guy Schalnat 已提交
1160

1161 1162
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1163 1164 1165 1166 1167
/* 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 已提交
1168 1169 1170 1171
 *
 * 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 已提交
1172
 */
1173
png_size_t /* PRIVATE */
1174
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1175
{
A
Andreas Dilger 已提交
1176
   png_size_t key_len;
1177
   png_charp kp, dp;
A
Andreas Dilger 已提交
1178
   int kflag;
1179
   int kwarn=0;
A
Andreas Dilger 已提交
1180

A
Andreas Dilger 已提交
1181 1182 1183 1184
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1185
   {
1186
      png_warning(png_ptr, "zero length keyword");
1187
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1188
   }
A
Andreas Dilger 已提交
1189 1190 1191

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

1192 1193 1194 1195 1196 1197
   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
   if (*new_key == NULL)
   {
      png_warning(png_ptr, "Out of memory while procesing keyword");
      return ((png_size_t)0);
   }
1198

A
Andreas Dilger 已提交
1199 1200
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1201
   {
1202
      if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1203
      {
1204
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
A
Andreas Dilger 已提交
1205
         char msg[40];
A
Andreas Dilger 已提交
1206

1207
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1208
         png_warning(png_ptr, msg);
1209
#else
1210
         png_warning(png_ptr, "invalid character in keyword");
1211
#endif
A
Andreas Dilger 已提交
1212 1213 1214 1215 1216 1217
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1218
   }
A
Andreas Dilger 已提交
1219
   *dp = '\0';
A
Andreas Dilger 已提交
1220

A
Andreas Dilger 已提交
1221 1222 1223
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1224
   {
1225
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1226 1227 1228 1229 1230 1231

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1232 1233 1234
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1235 1236
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1237
   {
1238
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1239 1240 1241 1242 1243 1244

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

A
Andreas Dilger 已提交
1247 1248 1249 1250
   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 已提交
1251
   {
A
Andreas Dilger 已提交
1252
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1253
      {
A
Andreas Dilger 已提交
1254 1255
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1256
      }
A
Andreas Dilger 已提交
1257
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1258 1259
      {
         key_len--;
1260
         kwarn=1;
A
Andreas Dilger 已提交
1261 1262 1263
      }
      else
      {
A
Andreas Dilger 已提交
1264 1265
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1266 1267
      }
   }
A
Andreas Dilger 已提交
1268
   *dp = '\0';
1269 1270
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1271 1272

   if (key_len == 0)
A
Andreas Dilger 已提交
1273
   {
1274 1275
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1276
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1277 1278 1279 1280
   }

   if (key_len > 79)
   {
1281
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1282 1283 1284
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1285

1286
   return (key_len);
A
Andreas Dilger 已提交
1287 1288 1289
}
#endif

G
Guy Schalnat 已提交
1290
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1291
/* write a tEXt chunk */
1292
void /* PRIVATE */
G
Guy Schalnat 已提交
1293
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1294
   png_size_t text_len)
G
Guy Schalnat 已提交
1295
{
1296 1297 1298
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1299
   png_size_t key_len;
1300
   png_charp new_key;
A
Andreas Dilger 已提交
1301 1302 1303 1304

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

A
Andreas Dilger 已提交
1309
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1310
      text_len = 0;
1311 1312
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1313 1314

   /* make sure we include the 0 after the key */
1315
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1316 1317 1318 1319
   /*
    * 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.
1320
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1321
    */
1322
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1323
   if (text_len)
A
Andreas Dilger 已提交
1324
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1325

G
Guy Schalnat 已提交
1326
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1327
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1328
}
G
Guy Schalnat 已提交
1329
#endif
G
Guy Schalnat 已提交
1330

G
Guy Schalnat 已提交
1331
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1332
/* write a compressed text chunk */
1333
void /* PRIVATE */
G
Guy Schalnat 已提交
1334
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1335
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1336
{
1337 1338 1339
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1340
   png_size_t key_len;
G
Guy Schalnat 已提交
1341
   char buf[1];
1342
   png_charp new_key;
1343
   compression_state comp;
G
Guy Schalnat 已提交
1344

A
Andreas Dilger 已提交
1345 1346 1347 1348
   png_debug(1, "in png_write_zTXt\n");

   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
1349
      png_warning(png_ptr, "Empty keyword in zTXt chunk");
G
Guy Schalnat 已提交
1350
      return;
A
Andreas Dilger 已提交
1351
   }
A
Andreas Dilger 已提交
1352

A
Andreas Dilger 已提交
1353 1354 1355 1356 1357 1358 1359
   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
   {
      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
      png_free(png_ptr, new_key);
      return;
   }

1360 1361
   text_len = png_strlen(text);

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

1364
   /* compute the compressed data; do it now for the length */
1365 1366
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1367

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
   /* 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 */
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
   /* write the compressed data */
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1378

1379 1380 1381 1382
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1383

1384 1385
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1386
void /* PRIVATE */
1387
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1388
    png_charp lang, png_charp lang_key, png_charp text)
1389 1390 1391 1392
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1393
   png_size_t lang_len, key_len, lang_key_len, text_len;
1394 1395 1396
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1397

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

1400
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1401
   {
1402
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1403 1404
      return;
   }
1405
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1406
   {
1407
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1408
      new_lang = NULL;
1409
      lang_len = 0;
1410
   }
G
Guy Schalnat 已提交
1411

1412 1413 1414 1415 1416 1417
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1418
      text_len = 0;
1419 1420
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1421

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

1426

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

1430 1431 1432 1433 1434 1435 1436
   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 已提交
1437

1438 1439 1440 1441 1442 1443 1444
   /*
    * 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);
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455

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

1456 1457 1458
   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);
1459
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1460 1461

   png_write_chunk_end(png_ptr);
1462
   png_free(png_ptr, new_key);
1463 1464
   if (new_lang)
     png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1465
}
G
Guy Schalnat 已提交
1466
#endif
G
Guy Schalnat 已提交
1467

A
Andreas Dilger 已提交
1468 1469
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1470
void /* PRIVATE */
1471
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1472 1473
   int unit_type)
{
1474 1475 1476
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1477 1478
   png_byte buf[9];

A
Andreas Dilger 已提交
1479 1480 1481
   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 已提交
1482

1483 1484
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1485
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1486

1487
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1488
}
G
Guy Schalnat 已提交
1489
#endif
G
Guy Schalnat 已提交
1490

A
Andreas Dilger 已提交
1491
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1492
/* write the pCAL chunk (described in the PNG extensions document) */
1493
void /* PRIVATE */
A
Andreas Dilger 已提交
1494 1495 1496
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)
{
1497 1498 1499
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1500
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1501 1502
   png_uint_32p params_len;
   png_byte buf[10];
1503
   png_charp new_purpose;
A
Andreas Dilger 已提交
1504 1505 1506 1507 1508 1509 1510
   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;
1511
   png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
A
Andreas Dilger 已提交
1512
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1513
   png_debug1(3, "pCAL units length = %d\n", (int)units_len);
A
Andreas Dilger 已提交
1514 1515
   total_len = purpose_len + units_len + 10;

1516
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
1517
      *png_sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1518 1519 1520 1521 1522 1523

   /* 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);
1524
      png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
A
Andreas Dilger 已提交
1525 1526 1527
      total_len += (png_size_t)params_len[i];
   }

1528
   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1529
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1530
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
   png_save_int_32(buf, X0);
   png_save_int_32(buf + 4, X1);
   buf[8] = (png_byte)type;
   buf[9] = (png_byte)nparams;
   png_write_chunk_data(png_ptr, buf, (png_size_t)10);
   png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);

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

1546
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1547 1548 1549 1550
   png_write_chunk_end(png_ptr);
}
#endif

1551 1552
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1553
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1554
void /* PRIVATE */
1555
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1556 1557 1558 1559 1560 1561
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];
1562
   png_byte bunit = unit;
1563 1564 1565

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

1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
#if defined(_WIN32_WCE)
/* sprintf() function is not supported on WindowsCE */
   {
      wchar_t wc_buf[32];
      swprintf(wc_buf, TEXT("%12.12e"), width);
      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL);
      swprintf(wc_buf, TEXT("%12.12e"), height);
      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL);
   }
#else
1576 1577
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1578
#endif
1579
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1580

1581
   png_debug1(3, "sCAL total length = %d\n", (int)total_len);
1582
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1583
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1584 1585
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1586 1587 1588

   png_write_chunk_end(png_ptr);
}
1589 1590
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1591
void /* PRIVATE */
1592
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1593 1594 1595 1596 1597 1598 1599
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];
1600
   png_byte bunit = unit;
1601

1602
   png_debug(1, "in png_write_sCAL_s\n");
1603

1604 1605
   png_strcpy(wbuf,(const char *)width);
   png_strcpy(hbuf,(const char *)height);
1606
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1607 1608 1609

   png_debug1(3, "sCAL total length = %d\n", total_len);
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1610
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1611 1612
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1613 1614 1615 1616

   png_write_chunk_end(png_ptr);
}
#endif
1617 1618
#endif
#endif
1619

A
Andreas Dilger 已提交
1620 1621
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1622
void /* PRIVATE */
A
Andreas Dilger 已提交
1623 1624
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1625 1626
   int unit_type)
{
1627 1628 1629
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1630 1631
   png_byte buf[9];

A
Andreas Dilger 已提交
1632 1633 1634
   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 已提交
1635

A
Andreas Dilger 已提交
1636 1637
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1638
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1639

1640
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1641
}
G
Guy Schalnat 已提交
1642
#endif
G
Guy Schalnat 已提交
1643

G
Guy Schalnat 已提交
1644
#if defined(PNG_WRITE_tIME_SUPPORTED)
1645 1646 1647
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1648
void /* PRIVATE */
G
Guy Schalnat 已提交
1649
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1650
{
1651 1652 1653
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1654 1655
   png_byte buf[7];

A
Andreas Dilger 已提交
1656
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1657 1658 1659 1660 1661 1662 1663 1664
   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 已提交
1665 1666 1667 1668 1669 1670 1671
   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;

1672
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1673
}
G
Guy Schalnat 已提交
1674
#endif
G
Guy Schalnat 已提交
1675 1676

/* initializes the row writing capability of libpng */
1677
void /* PRIVATE */
G
Guy Schalnat 已提交
1678
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1679
{
1680
#ifdef PNG_USE_LOCAL_ARRAYS
1681
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1682

1683 1684
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1685

1686 1687
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1688

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

1692 1693
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1694
#endif
1695

A
Andreas Dilger 已提交
1696 1697 1698
   png_size_t buf_size;

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

G
Guy Schalnat 已提交
1702
   /* set up row buffer */
1703
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1704
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1705 1706 1707

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1708
   {
A
Andreas Dilger 已提交
1709
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1710
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1711
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1712 1713
   }

A
Andreas Dilger 已提交
1714
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1715 1716 1717
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1718
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1719
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1720 1721 1722

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1723
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1724
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1725
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1726 1727 1728 1729
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1730 1731
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1732
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1733 1734 1735 1736
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1737
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1738
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1739
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1740
      }
G
Guy Schalnat 已提交
1741 1742
   }

1743
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1744
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1745
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1746 1747 1748 1749 1750
   {
      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 已提交
1751 1752
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1753 1754 1755 1756 1757 1758 1759 1760
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1761
#endif
G
Guy Schalnat 已提交
1762
   {
G
Guy Schalnat 已提交
1763 1764 1765
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1766 1767
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1768 1769
}

A
Andreas Dilger 已提交
1770
/* Internal use only.  Called when finished processing a row of data. */
1771
void /* PRIVATE */
G
Guy Schalnat 已提交
1772
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1773
{
1774
#ifdef PNG_USE_LOCAL_ARRAYS
1775
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1776

1777 1778
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1779

1780 1781
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1782

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

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

G
Guy Schalnat 已提交
1790 1791
   int ret;

A
Andreas Dilger 已提交
1792
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1793 1794
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1795

G
Guy Schalnat 已提交
1796
   /* see if we are done */
G
Guy Schalnat 已提交
1797
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1798
      return;
G
Guy Schalnat 已提交
1799

1800
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
   /* 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 已提交
1817
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1818 1819 1820 1821 1822 1823 1824
               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 已提交
1825 1826
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1827 1828 1829 1830
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1831
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1832
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1833
      {
A
Andreas Dilger 已提交
1834
         if (png_ptr->prev_row != NULL)
1835
            png_memset(png_ptr->prev_row, 0,
1836 1837
               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
               png_ptr->usr_bit_depth,png_ptr->width))+1);
G
Guy Schalnat 已提交
1838
         return;
G
Guy Schalnat 已提交
1839
      }
G
Guy Schalnat 已提交
1840
   }
1841
#endif
G
Guy Schalnat 已提交
1842 1843 1844 1845 1846 1847

   /* 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 已提交
1848
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1849
      /* check for an error */
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860
      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 已提交
1861
      {
A
Andreas Dilger 已提交
1862
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1863
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1864
         else
G
Guy Schalnat 已提交
1865
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1866 1867 1868 1869
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1870
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1871 1872
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1873
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1874 1875
   }

A
Andreas Dilger 已提交
1876
   deflateReset(&png_ptr->zstream);
1877
   png_ptr->zstream.data_type = Z_BINARY;
G
Guy Schalnat 已提交
1878 1879
}

G
Guy Schalnat 已提交
1880
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1881 1882 1883 1884 1885 1886 1887
/* 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.
 */
1888
void /* PRIVATE */
G
Guy Schalnat 已提交
1889
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1890
{
1891
#ifdef PNG_USE_LOCAL_ARRAYS
1892
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1893

1894 1895
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1896

1897 1898
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1899
#endif
1900

A
Andreas Dilger 已提交
1901
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1902
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1903 1904 1905 1906 1907
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1908
   {
1909
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1910
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1911
      {
G
Guy Schalnat 已提交
1912 1913
         case 1:
         {
G
Guy Schalnat 已提交
1914 1915
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1916 1917 1918
            int shift;
            int d;
            int value;
1919 1920
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1921 1922 1923 1924

            dp = row;
            d = 0;
            shift = 7;
1925
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1926 1927 1928
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1929
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1930 1931 1932 1933 1934
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1935
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1936 1937 1938 1939 1940 1941 1942
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1943
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1944 1945 1946
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1947
         {
G
Guy Schalnat 已提交
1948 1949
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1950 1951 1952
            int shift;
            int d;
            int value;
1953 1954
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1955 1956 1957 1958

            dp = row;
            shift = 6;
            d = 0;
1959
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1960 1961 1962
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1963
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1964 1965 1966 1967 1968
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1969
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1970 1971 1972 1973 1974 1975
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1976
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1977 1978 1979 1980
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1981 1982
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1983
            int shift;
G
Guy Schalnat 已提交
1984 1985
            int d;
            int value;
1986 1987
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1988 1989 1990 1991

            dp = row;
            shift = 4;
            d = 0;
1992
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1993 1994 1995
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
1996
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
1997 1998 1999 2000
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
2001 2002
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
2003 2004 2005 2006 2007 2008
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
2009
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
2010 2011 2012 2013
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
2014 2015
            png_bytep sp;
            png_bytep dp;
2016 2017
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
2018
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
2019

G
Guy Schalnat 已提交
2020
            /* start at the beginning */
G
Guy Schalnat 已提交
2021 2022 2023 2024 2025
            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 */
2026
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2027 2028 2029
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
2030
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
2031 2032
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
2033
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
2034 2035 2036
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
2037
            break;
G
Guy Schalnat 已提交
2038 2039 2040 2041 2042 2043 2044
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
2045 2046
         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
            row_info->width);
G
Guy Schalnat 已提交
2047 2048
   }
}
G
Guy Schalnat 已提交
2049
#endif
G
Guy Schalnat 已提交
2050

A
Andreas Dilger 已提交
2051 2052
/* 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
2053 2054
 * chosen filter.
 */
2055
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
A
Andreas Dilger 已提交
2056
#define PNG_HISHIFT 10
2057 2058
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2059
void /* PRIVATE */
G
Guy Schalnat 已提交
2060
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2061
{
G
Guy Schalnat 已提交
2062
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2063
   png_uint_32 mins, bpp;
2064
   png_byte filter_to_do = png_ptr->do_filter;
2065 2066 2067 2068
   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 已提交
2069

A
Andreas Dilger 已提交
2070
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
2071
   /* find out how many bytes offset each pixel is */
2072
   bpp = (row_info->pixel_depth + 7) >> 3;
G
Guy Schalnat 已提交
2073 2074 2075

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
2076 2077 2078 2079
   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
2080
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2081
    * as the "minimum sum of absolute differences" heuristic.  Other
2082
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2083
    * (experimental and can in theory improve compression), and the "zlib
2084 2085 2086
    * 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 已提交
2087
    * computationally expensive).
2088 2089 2090 2091 2092 2093 2094 2095 2096
    *
    * 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 已提交
2097
    */
G
Guy Schalnat 已提交
2098

2099

G
Guy Schalnat 已提交
2100
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2101 2102
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2103
   if ((filter_to_do & PNG_FILTER_NONE) &&
2104
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2105
   {
G
Guy Schalnat 已提交
2106 2107
      png_bytep rp;
      png_uint_32 sum = 0;
2108
      png_uint_32 i;
A
Andreas Dilger 已提交
2109
      int v;
G
Guy Schalnat 已提交
2110

2111
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2112 2113 2114 2115
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2116 2117 2118 2119 2120

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2121
         int j;
A
Andreas Dilger 已提交
2122 2123 2124 2125
         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 */
2126
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2127
         {
2128
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2129
            {
2130
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2131
                  PNG_WEIGHT_SHIFT;
2132
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
                  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 已提交
2152 2153
      mins = sum;
   }
G
Guy Schalnat 已提交
2154

G
Guy Schalnat 已提交
2155
   /* sub filter */
2156 2157 2158 2159
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2160
      png_uint_32 i;
2161 2162 2163 2164 2165
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2166
      for (lp = row_buf + 1; i < row_bytes;
2167 2168 2169 2170 2171 2172 2173 2174
         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 已提交
2175 2176
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2177
      png_uint_32 sum = 0, lmins = mins;
2178
      png_uint_32 i;
A
Andreas Dilger 已提交
2179 2180 2181
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2182
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2183 2184 2185 2186 2187
       * 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)
      {
2188
         int j;
A
Andreas Dilger 已提交
2189 2190 2191 2192
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2193
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2194
         {
2195
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2196
            {
2197
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2198
                  PNG_WEIGHT_SHIFT;
2199
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214
                  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 已提交
2215

G
Guy Schalnat 已提交
2216 2217 2218 2219
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2220

G
Guy Schalnat 已提交
2221 2222
         sum += (v < 128) ? v : 256 - v;
      }
2223
      for (lp = row_buf + 1; i < row_bytes;
2224
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2225 2226 2227 2228
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2229 2230 2231 2232 2233 2234 2235 2236

         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)
      {
2237
         int j;
A
Andreas Dilger 已提交
2238 2239 2240 2241
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2242
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2243
         {
2244
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2245
            {
2246
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2247
                  PNG_WEIGHT_SHIFT;
2248
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
                  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 已提交
2262
      }
A
Andreas Dilger 已提交
2263 2264
#endif

G
Guy Schalnat 已提交
2265 2266 2267 2268 2269
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2270 2271
   }

G
Guy Schalnat 已提交
2272
   /* up filter */
2273 2274 2275
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2276
      png_uint_32 i;
2277 2278

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2279
           pp = prev_row + 1; i < row_bytes;
2280 2281 2282 2283 2284 2285 2286 2287
           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 已提交
2288 2289
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2290
      png_uint_32 sum = 0, lmins = mins;
2291
      png_uint_32 i;
A
Andreas Dilger 已提交
2292 2293
      int v;

2294

A
Andreas Dilger 已提交
2295 2296 2297
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2298
         int j;
A
Andreas Dilger 已提交
2299 2300 2301 2302
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2326
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2327
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2328
      {
2329
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2330 2331

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

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2335
      }
A
Andreas Dilger 已提交
2336 2337 2338 2339

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2340
         int j;
A
Andreas Dilger 已提交
2341 2342 2343 2344
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2345
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2346
         {
2347
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2348
            {
2349
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2350
                  PNG_WEIGHT_SHIFT;
2351
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367
                  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 已提交
2368 2369 2370 2371 2372 2373 2374 2375
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2376 2377 2378
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2379
      png_uint_32 i;
2380
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2381
           pp = prev_row + 1; i < bpp; i++)
2382
      {
2383
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2384
      }
2385
      for (lp = row_buf + 1; i < row_bytes; i++)
2386
      {
2387 2388
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2389 2390 2391 2392 2393
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2394
   {
G
Guy Schalnat 已提交
2395
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2396
      png_uint_32 sum = 0, lmins = mins;
2397
      png_uint_32 i;
A
Andreas Dilger 已提交
2398 2399 2400 2401 2402
      int v;

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

2408
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2409
         {
2410
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2411
            {
2412
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2413
                  PNG_WEIGHT_SHIFT;
2414
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429
                  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 已提交
2430

G
Guy Schalnat 已提交
2431
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2432
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2433
      {
2434
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2435

G
Guy Schalnat 已提交
2436 2437
         sum += (v < 128) ? v : 256 - v;
      }
2438
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2439
      {
2440
         v = *dp++ =
2441
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2442

G
Guy Schalnat 已提交
2443
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2444 2445 2446

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2447
      }
A
Andreas Dilger 已提交
2448 2449 2450 2451

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2452
         int j;
A
Andreas Dilger 已提交
2453 2454 2455 2456
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2457
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2458
         {
2459
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2460
            {
2461
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2462
                  PNG_WEIGHT_SHIFT;
2463
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479
                  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 已提交
2480 2481 2482 2483 2484 2485
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2486

A
Andreas Dilger 已提交
2487
   /* Paeth filter */
2488 2489 2490
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2491
      png_uint_32 i;
2492
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2493
           pp = prev_row + 1; i < bpp; i++)
2494
      {
2495
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2496 2497
      }

2498
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2499 2500 2501
      {
         int a, b, c, pa, pb, pc, p;

2502 2503 2504
         b = *pp++;
         c = *cp++;
         a = *lp++;
2505

2506 2507
         p = b - c;
         pc = a - c;
2508 2509

#ifdef PNG_USE_ABS
2510 2511 2512
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2513
#else
2514 2515 2516
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2517 2518 2519 2520
#endif

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

2521
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2522 2523 2524 2525 2526
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2527 2528
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2529
      png_uint_32 sum = 0, lmins = mins;
2530
      png_uint_32 i;
A
Andreas Dilger 已提交
2531 2532 2533 2534 2535
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2536
         int j;
A
Andreas Dilger 已提交
2537 2538 2539 2540
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2541
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2542
         {
2543
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2544
            {
2545
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2546
                  PNG_WEIGHT_SHIFT;
2547
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562
                  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 已提交
2563

G
Guy Schalnat 已提交
2564
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2565
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2566
      {
2567
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2568

G
Guy Schalnat 已提交
2569 2570
         sum += (v < 128) ? v : 256 - v;
      }
2571

2572
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2573 2574
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2575

2576 2577 2578
         b = *pp++;
         c = *cp++;
         a = *lp++;
2579 2580

#ifndef PNG_SLOW_PAETH
2581 2582
         p = b - c;
         pc = a - c;
2583
#ifdef PNG_USE_ABS
2584 2585 2586
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2587
#else
2588 2589 2590
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2591 2592 2593
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2594
         p = a + b - c;
2595 2596 2597
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2598 2599 2600 2601 2602 2603
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2604
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2605

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

G
Guy Schalnat 已提交
2608
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2609 2610 2611

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2612
      }
A
Andreas Dilger 已提交
2613 2614 2615 2616

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2617
         int j;
A
Andreas Dilger 已提交
2618 2619 2620 2621
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2622
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2623
         {
2624
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2625
            {
2626
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2627
                  PNG_WEIGHT_SHIFT;
2628
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
                  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 已提交
2645 2646 2647 2648
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2649 2650
   }

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

G
Guy Schalnat 已提交
2653
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2654 2655 2656 2657 2658

#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)
   {
2659 2660
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2661
      {
2662
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2663
      }
2664
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2665 2666
   }
#endif
G
Guy Schalnat 已提交
2667
}
G
Guy Schalnat 已提交
2668

G
Guy Schalnat 已提交
2669

A
Andreas Dilger 已提交
2670
/* Do the actual writing of a previously filtered row. */
2671
void /* PRIVATE */
G
Guy Schalnat 已提交
2672 2673
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2674 2675
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2676
   /* set up the zlib input buffer */
2677

A
Andreas Dilger 已提交
2678 2679
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2680 2681
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2682
   {
G
Guy Schalnat 已提交
2683
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2684

G
Guy Schalnat 已提交
2685
      /* compress the data */
A
Andreas Dilger 已提交
2686
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2687 2688 2689
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2690
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2691
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2692 2693 2694
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2695

G
Guy Schalnat 已提交
2696
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2697
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2698 2699 2700
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2701 2702
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2703 2704
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2705
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2706

G
Guy Schalnat 已提交
2707
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2708
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2709 2710 2711 2712 2713 2714 2715 2716
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2717 2718
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2719

G
Guy Schalnat 已提交
2720 2721 2722 2723 2724 2725 2726
#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 已提交
2727
   }
2728
#endif
G
Guy Schalnat 已提交
2729
}
2730
#endif /* PNG_WRITE_SUPPORTED */