pngwutil.c 81.5 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.8beta3 - November 3, 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 360 361 362 363 364 365
   /* 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);

   /* reset zlib for another zTXt/iTXt or the image data */
   deflateReset(&png_ptr->zstream);

}
#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;
G
Guy Schalnat 已提交
526

G
Guy Schalnat 已提交
527
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
528 529 530
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

737
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
738
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
739

740
   if (profile == NULL)
741 742 743
      profile_len = 0;

   if (profile_len)
744
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
745
          PNG_COMPRESSION_TYPE_BASE, &comp);
746 747 748 749

   /* 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);
750
   new_name[name_len+1]=0x00;
751 752 753 754 755 756 757 758 759 760 761 762
   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 */
763
void /* PRIVATE */
764
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
765 766 767 768 769 770 771 772 773
{
#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;
774
   png_sPLT_entryp ep;
775 776 777
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
778 779

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

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

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

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

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

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

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

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

896
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
897
}
G
Guy Schalnat 已提交
898
#endif
G
Guy Schalnat 已提交
899

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

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

   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;
   }
936
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
937
   png_save_uint_32(buf + 8, itemp);
938
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
939
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
940 941 942 943 944 945 946

   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;
   }
947
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
948
   png_save_uint_32(buf + 16, itemp);
949
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
950
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
951 952 953 954 955 956 957

   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;
   }
958
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
959
   png_save_uint_32(buf + 24, itemp);
960
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
961
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
962

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
1178 1179 1180 1181
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

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

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

1189 1190 1191 1192 1193 1194
   *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);
   }
1195

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

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

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

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1229 1230 1231
   }

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

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

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

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

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

1283
   return (key_len);
A
Andreas Dilger 已提交
1284 1285 1286
}
#endif

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

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

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

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

G
Guy Schalnat 已提交
1323
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1324
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1325
}
G
Guy Schalnat 已提交
1326
#endif
G
Guy Schalnat 已提交
1327

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

A
Andreas Dilger 已提交
1342 1343 1344 1345
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1350 1351 1352 1353 1354 1355 1356
   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;
   }

1357 1358
   text_len = png_strlen(text);

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

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

1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
   /* 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 已提交
1375

1376 1377 1378 1379
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1380

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

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

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

1409 1410 1411 1412 1413 1414
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1415
      text_len = 0;
1416 1417
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1418

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

1423

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

1427 1428 1429 1430 1431 1432 1433
   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 已提交
1434

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

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

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

   png_write_chunk_end(png_ptr);
1459
   png_free(png_ptr, new_key);
1460 1461
   if (new_lang)
     png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1462
}
G
Guy Schalnat 已提交
1463
#endif
G
Guy Schalnat 已提交
1464

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

A
Andreas Dilger 已提交
1476 1477 1478
   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 已提交
1479

1480 1481
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1482
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1483

1484
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1485
}
G
Guy Schalnat 已提交
1486
#endif
G
Guy Schalnat 已提交
1487

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

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

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

1525
   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1526
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1527
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
   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]);
   }

1543
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1544 1545 1546 1547
   png_write_chunk_end(png_ptr);
}
#endif

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

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

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
#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
1573 1574
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1575
#endif
1576
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1577

1578
   png_debug1(3, "sCAL total length = %d\n", (int)total_len);
1579
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1580
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1581 1582
   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));
1583 1584 1585

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

1599
   png_debug(1, "in png_write_sCAL_s\n");
1600

1601 1602
   png_strcpy(wbuf,(const char *)width);
   png_strcpy(hbuf,(const char *)height);
1603
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1604 1605 1606

   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);
1607
   png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1608 1609
   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));
1610 1611 1612 1613

   png_write_chunk_end(png_ptr);
}
#endif
1614 1615
#endif
#endif
1616

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

A
Andreas Dilger 已提交
1629 1630 1631
   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 已提交
1632

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

1637
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1638
}
G
Guy Schalnat 已提交
1639
#endif
G
Guy Schalnat 已提交
1640

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

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

1669
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1670
}
G
Guy Schalnat 已提交
1671
#endif
G
Guy Schalnat 已提交
1672 1673

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

1680 1681
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1682

1683 1684
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1685

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

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

A
Andreas Dilger 已提交
1693 1694 1695
   png_size_t buf_size;

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

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

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

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

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

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

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

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

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

1774 1775
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1776

1777 1778
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1779

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

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

G
Guy Schalnat 已提交
1787 1788
   int ret;

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

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

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

      }

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

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

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

A
Andreas Dilger 已提交
1873
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1874 1875
}

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

1890 1891
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1892

1893 1894
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1895
#endif
1896

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

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

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1931
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1932 1933 1934 1935 1936 1937 1938
                  d = 0;
               }
               else
                  shift--;

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

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

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

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

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

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

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

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

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

2095

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

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

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

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

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

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

G
Guy Schalnat 已提交
2212 2213 2214 2215
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2216

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

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2225 2226 2227 2228 2229 2230 2231 2232

         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)
      {
2233
         int j;
A
Andreas Dilger 已提交
2234 2235 2236 2237
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2261 2262 2263 2264 2265
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2266 2267
   }

G
Guy Schalnat 已提交
2268
   /* up filter */
2269 2270 2271
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2272
      png_uint_32 i;
2273 2274

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

2290

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

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

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

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2328 2329 2330

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2331
      }
A
Andreas Dilger 已提交
2332 2333 2334 2335

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
2439
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2440 2441 2442

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2443
      }
A
Andreas Dilger 已提交
2444 2445 2446 2447

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

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

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

2494
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2495 2496 2497
      {
         int a, b, c, pa, pb, pc, p;

2498 2499 2500
         b = *pp++;
         c = *cp++;
         a = *lp++;
2501

2502 2503
         p = b - c;
         pc = a - c;
2504 2505

#ifdef PNG_USE_ABS
2506 2507 2508
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2509
#else
2510 2511 2512
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2513 2514 2515 2516
#endif

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

2517
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2518 2519 2520 2521 2522
      }
      best_row = png_ptr->paeth_row;
   }

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

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

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

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

G
Guy Schalnat 已提交
2565 2566
         sum += (v < 128) ? v : 256 - v;
      }
2567

2568
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2569 2570
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2571

2572 2573 2574
         b = *pp++;
         c = *cp++;
         a = *lp++;
2575 2576

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

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

G
Guy Schalnat 已提交
2604
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2605 2606 2607

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2608
      }
A
Andreas Dilger 已提交
2609 2610 2611 2612

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

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

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

G
Guy Schalnat 已提交
2649
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2650 2651 2652 2653 2654

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

G
Guy Schalnat 已提交
2665

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

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

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

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

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

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

G
Guy Schalnat 已提交
2713 2714
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2715

G
Guy Schalnat 已提交
2716 2717 2718 2719 2720 2721 2722
#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 已提交
2723
   }
2724
#endif
G
Guy Schalnat 已提交
2725
}
2726
#endif /* PNG_WRITE_SUPPORTED */