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

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * libpng 1.0.9beta10 - January 16, 2001
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2001 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 13
#define PNG_INTERNAL
#include "png.h"

A
Andreas Dilger 已提交
14 15 16 17
/* 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.
 */
18
void /* PRIVATE */
G
Guy Schalnat 已提交
19
png_save_uint_32(png_bytep buf, png_uint_32 i)
G
Guy Schalnat 已提交
20 21 22 23 24 25 26
{
   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 已提交
27 28
#if defined(PNG_WRITE_pCAL_SUPPORTED)
/* The png_save_int_32 function assumes integers are stored in two's
29 30 31
 * complement format.  If this isn't the case, then this routine needs to
 * be modified to write data in two's complement format.
 */
32
void /* PRIVATE */
A
Andreas Dilger 已提交
33
png_save_int_32(png_bytep buf, png_int_32 i)
G
Guy Schalnat 已提交
34 35 36 37 38 39
{
   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 已提交
40
#endif
G
Guy Schalnat 已提交
41

42 43 44 45
/* 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.
 */
46
void /* PRIVATE */
47
png_save_uint_16(png_bytep buf, unsigned int i)
G
Guy Schalnat 已提交
48 49 50 51 52
{
   buf[0] = (png_byte)((i >> 8) & 0xff);
   buf[1] = (png_byte)(i & 0xff);
}

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

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

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

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

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

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

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

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

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

138
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
/*
 * 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 */
156
static int /* PRIVATE */
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
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;
172
       return((int)text_len);
173 174 175 176
   }

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
177
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
178 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 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      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 */
      if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
      {
         /* 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,
                  (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp)));
               png_memcpy(comp->output_ptr, old_ptr,
           old_max * sizeof (png_charp));
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
                  (png_uint_32)(comp->max_output_ptr * sizeof (png_charp)));
         }

         /* save the data */
         comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
            (png_uint_32)png_ptr->zbuf_size);
         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
            png_ptr->zbuf_size);
         comp->num_output_ptr++;

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

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

295 296 297 298 299 300
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
               (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
301

302 303 304 305 306 307 308 309 310 311 312 313
            /* 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");
314 315 316 317 318 319 320 321
      }
   } 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;

322
   return((int)text_len);
323 324 325
}

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

   /* handle the no-compression case */
   if (comp->input)
   {
       png_write_chunk_data(png_ptr, (png_bytep)comp->input, comp->input_len);
       return;
   }

   /* write saved output buffers, if any */
   for (i = 0; i < comp->num_output_ptr; i++)
   {
341 342
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
343
      png_free(png_ptr, comp->output_ptr[i]);
344
      comp->output_ptr[i]=NULL;
345 346 347
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
348
      comp->output_ptr=NULL;
349 350 351 352 353 354 355 356 357 358 359
   /* write anything left in zbuf */
   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
      png_write_chunk_data(png_ptr, png_ptr->zbuf,
         png_ptr->zbuf_size - png_ptr->zstream.avail_out);

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

}
#endif

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

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

A
Andreas Dilger 已提交
418
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
419 420
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
421
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
422 423
   }

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

447
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
448 449
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
450 451
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
452
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
453
   }
454 455 456
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
457 458 459 460 461

   /* 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;
462
   png_ptr->filter_type = (png_byte)filter_type;
G
Guy Schalnat 已提交
463 464 465
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
466
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
A
Andreas Dilger 已提交
467
   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
468 469 470
   /* 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 已提交
471 472 473 474 475 476 477 478 479 480
   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 已提交
481 482

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

A
Andreas Dilger 已提交
485
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
486 487 488
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
489
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
490
   {
A
Andreas Dilger 已提交
491 492
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
493
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
494
      else
G
Guy Schalnat 已提交
495
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
496
   }
G
Guy Schalnat 已提交
497
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
498
   {
G
Guy Schalnat 已提交
499
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
500 501 502 503
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
504
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
505
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
506
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
507
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
508
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
G
Guy Schalnat 已提交
509
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
510
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
511
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
512
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
513 514
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
515 516
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
517

G
Guy Schalnat 已提交
518
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
519 520 521
}

/* write the palette.  We are careful not to trust png_color to be in the
522
 * correct order for PNG, so people can redefine it to any convenient
523 524
 * structure.
 */
525
void /* PRIVATE */
A
Andreas Dilger 已提交
526
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
527
{
528 529 530
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
531
   png_uint_32 i;
G
Guy Schalnat 已提交
532
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
533 534
   png_byte buf[3];

A
Andreas Dilger 已提交
535
   png_debug(1, "in png_write_PLTE\n");
536
   if ((
537 538
#if defined(PNG_MNG_FEATURES_SUPPORTED)
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
539 540 541 542 543 544 545 546 547 548 549 550
#endif
        num_pal == 0) || num_pal > 256)
     {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
         {
           png_error(png_ptr, "Invalid number of colors in palette");
         }
       else
         {
           png_warning(png_ptr, "Invalid number of colors in palette");
           return;
         }
G
Guy Schalnat 已提交
551 552
   }

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

556
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
557
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
558
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
559 560 561 562
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
563
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
564
   }
565 566 567 568 569 570 571 572 573 574 575
#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 已提交
576
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
577
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
578 579 580
}

/* write an IDAT chunk */
581
void /* PRIVATE */
A
Andreas Dilger 已提交
582
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
583
{
584 585 586
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
587
   png_debug(1, "in png_write_IDAT\n");
588
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
589
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
590 591 592
}

/* write an IEND chunk */
593
void /* PRIVATE */
G
Guy Schalnat 已提交
594
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
595
{
596 597 598
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
599
   png_debug(1, "in png_write_IEND\n");
600
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
A
Andreas Dilger 已提交
601
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
602 603
}

G
Guy Schalnat 已提交
604
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
605
/* write a gAMA chunk */
606
#ifdef PNG_FLOATING_POINT_SUPPORTED
607
void /* PRIVATE */
A
Andreas Dilger 已提交
608
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
609
{
610 611 612
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
613 614 615
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
616
   png_debug(1, "in png_write_gAMA\n");
617
   /* file_gamma is saved in 1/100,000ths */
618
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
619
   png_save_uint_32(buf, igamma);
620
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
621
}
G
Guy Schalnat 已提交
622
#endif
623
#ifdef PNG_FIXED_POINT_SUPPORTED
624
void /* PRIVATE */
625
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
626 627 628 629 630 631 632
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
633
   /* file_gamma is saved in 1/100,000ths */
634 635 636 637 638
   png_save_uint_32(buf, file_gamma);
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
}
#endif
#endif
G
Guy Schalnat 已提交
639

640 641
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
642
void /* PRIVATE */
643
png_write_sRGB(png_structp png_ptr, int srgb_intent)
644
{
645 646 647
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
648 649 650
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
651
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
652 653
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
654
   buf[0]=(png_byte)srgb_intent;
655
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
656 657 658
}
#endif

659 660
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
661
void /* PRIVATE */
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
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;
   }

680
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
681
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
682

683
   if (profile == NULL)
684 685 686
      profile_len = 0;

   if (profile_len)
687
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
688
          PNG_COMPRESSION_TYPE_BASE, &comp);
689 690 691 692

   /* 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);
693
   new_name[name_len+1]=0x00;
694 695 696 697 698 699 700 701 702 703 704 705
   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 */
706
void /* PRIVATE */
707
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
708 709 710 711 712 713 714 715 716
{
#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;
717
   png_sPLT_entryp ep;
718 719 720
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
721 722

   png_debug(1, "in png_write_sPLT\n");
723 724
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
725 726 727 728 729 730 731
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
   png_write_chunk_start(png_ptr, (png_bytep) png_sPLT,
732
          (png_uint_32)(name_len + 2 + palette_size));
733
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
734
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
735 736

   /* loop through each palette entry, writing appropriately */
737
#ifndef PNG_NO_POINTER_INDEXING
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
   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);
       }
       png_write_chunk_data(png_ptr, entrybuf, entry_size);
   }
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
#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
781 782 783 784 785 786

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

G
Guy Schalnat 已提交
787
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
788
/* write the sBIT chunk */
789
void /* PRIVATE */
G
Guy Schalnat 已提交
790
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
791
{
792 793 794
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
795
   png_byte buf[4];
A
Andreas Dilger 已提交
796
   png_size_t size;
G
Guy Schalnat 已提交
797

A
Andreas Dilger 已提交
798
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
799
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
800 801
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
802
      png_byte maxbits;
G
Guy Schalnat 已提交
803

804 805
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
806 807
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
808 809 810 811 812
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
813 814 815 816 817 818 819
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
820 821 822 823 824
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
825 826 827 828 829 830
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
831 832 833 834 835
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
836 837 838
      buf[size++] = sbit->alpha;
   }

839
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
840
}
G
Guy Schalnat 已提交
841
#endif
G
Guy Schalnat 已提交
842

G
Guy Schalnat 已提交
843
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
844
/* write the cHRM chunk */
845
#ifdef PNG_FLOATING_POINT_SUPPORTED
846
void /* PRIVATE */
A
Andreas Dilger 已提交
847
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
848 849
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
850
{
851 852 853
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
854
   png_byte buf[32];
855
   png_uint_32 itemp;
G
Guy Schalnat 已提交
856

A
Andreas Dilger 已提交
857
   png_debug(1, "in png_write_cHRM\n");
858
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
859 860 861 862
   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");
863 864
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
865
#endif
G
Guy Schalnat 已提交
866 867
      return;
   }
868
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
869
   png_save_uint_32(buf, itemp);
870
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
871
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
872 873 874 875 876 877 878

   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;
   }
879
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
880
   png_save_uint_32(buf + 8, itemp);
881
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
882
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
883 884 885 886 887 888 889

   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;
   }
890
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
891
   png_save_uint_32(buf + 16, itemp);
892
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
893
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
894 895 896 897 898 899 900

   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;
   }
901
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
902
   png_save_uint_32(buf + 24, itemp);
903
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
904
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
905

906
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
907
}
G
Guy Schalnat 已提交
908
#endif
909
#ifdef PNG_FIXED_POINT_SUPPORTED
910
void /* PRIVATE */
911 912 913 914
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)
915 916 917 918 919 920 921
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
922
   /* each value is saved in 1/100,000ths */
923 924
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
925
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
926 927
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
928
#endif
929 930 931 932 933 934 935
      return;
   }
   png_save_uint_32(buf, white_x);
   png_save_uint_32(buf + 4, white_y);

   if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
   {
936
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
937 938 939 940 941 942 943
      return;
   }
   png_save_uint_32(buf + 8, red_x);
   png_save_uint_32(buf + 12, red_y);

   if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
   {
944
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
945 946 947 948 949 950 951
      return;
   }
   png_save_uint_32(buf + 16, green_x);
   png_save_uint_32(buf + 20, green_y);

   if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
   {
952
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
953 954 955 956 957 958 959 960 961
      return;
   }
   png_save_uint_32(buf + 24, blue_x);
   png_save_uint_32(buf + 28, blue_y);

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

G
Guy Schalnat 已提交
963
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
964
/* write the tRNS chunk */
965
void /* PRIVATE */
G
Guy Schalnat 已提交
966
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
967 968
   int num_trans, int color_type)
{
969 970 971
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
972 973
   png_byte buf[6];

A
Andreas Dilger 已提交
974
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
975 976
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
977
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
978 979 980 981
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
982
      /* write the chunk out as it is */
983
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
984 985 986 987 988
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
      png_save_uint_16(buf, tran->gray);
989
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
990 991 992 993 994 995 996
   }
   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);
997
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
998
   }
G
Guy Schalnat 已提交
999 1000
   else
   {
1001
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1002
   }
G
Guy Schalnat 已提交
1003
}
G
Guy Schalnat 已提交
1004
#endif
G
Guy Schalnat 已提交
1005

G
Guy Schalnat 已提交
1006
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1007
/* write the background chunk */
1008
void /* PRIVATE */
G
Guy Schalnat 已提交
1009
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1010
{
1011 1012 1013
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1014 1015
   png_byte buf[6];

A
Andreas Dilger 已提交
1016
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
1017 1018
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1019
      if (
1020 1021 1022
#if defined(PNG_MNG_FEATURES_SUPPORTED)
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1023 1024
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1025 1026 1027 1028
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1029
      buf[0] = back->index;
1030
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1031 1032 1033 1034 1035 1036
   }
   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);
1037
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1038 1039
   }
   else
G
Guy Schalnat 已提交
1040
   {
G
Guy Schalnat 已提交
1041
      png_save_uint_16(buf, back->gray);
1042
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1043 1044
   }
}
G
Guy Schalnat 已提交
1045
#endif
G
Guy Schalnat 已提交
1046

G
Guy Schalnat 已提交
1047
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1048
/* write the histogram */
1049
void /* PRIVATE */
1050
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1051
{
1052 1053 1054
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1055
   int i;
G
Guy Schalnat 已提交
1056 1057
   png_byte buf[3];

A
Andreas Dilger 已提交
1058
   png_debug(1, "in png_write_hIST\n");
1059
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1060
   {
A
Andreas Dilger 已提交
1061 1062
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1063 1064 1065 1066
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1067
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1068
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1069
   {
G
Guy Schalnat 已提交
1070
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1071
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1072 1073 1074
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1075
#endif
G
Guy Schalnat 已提交
1076

1077 1078
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1079 1080 1081 1082 1083
/* 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 已提交
1084 1085 1086 1087
 *
 * 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 已提交
1088
 */
1089
png_size_t /* PRIVATE */
1090
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1091
{
A
Andreas Dilger 已提交
1092
   png_size_t key_len;
1093
   png_charp kp, dp;
A
Andreas Dilger 已提交
1094
   int kflag;
1095
   int kwarn=0;
A
Andreas Dilger 已提交
1096

A
Andreas Dilger 已提交
1097 1098 1099 1100
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1101
   {
1102
      png_warning(png_ptr, "zero length keyword");
1103
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1104
   }
A
Andreas Dilger 已提交
1105 1106 1107

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

1108
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
A
Andreas Dilger 已提交
1109 1110 1111

   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1112
   {
1113
      if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1114
      {
1115
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
A
Andreas Dilger 已提交
1116
         char msg[40];
A
Andreas Dilger 已提交
1117

1118
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1119
         png_warning(png_ptr, msg);
1120
#else
1121
         png_warning(png_ptr, "invalid character in keyword");
1122
#endif
A
Andreas Dilger 已提交
1123 1124 1125 1126 1127 1128
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1129
   }
A
Andreas Dilger 已提交
1130
   *dp = '\0';
A
Andreas Dilger 已提交
1131

A
Andreas Dilger 已提交
1132 1133 1134
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1135
   {
1136
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1137 1138 1139 1140 1141 1142

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1143 1144 1145
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1146 1147
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1148
   {
1149
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1150 1151 1152 1153 1154 1155

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

A
Andreas Dilger 已提交
1158 1159 1160 1161
   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 已提交
1162
   {
A
Andreas Dilger 已提交
1163
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1164
      {
A
Andreas Dilger 已提交
1165 1166
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1167
      }
A
Andreas Dilger 已提交
1168
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1169 1170
      {
         key_len--;
1171
         kwarn=1;
A
Andreas Dilger 已提交
1172 1173 1174
      }
      else
      {
A
Andreas Dilger 已提交
1175 1176
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1177 1178
      }
   }
A
Andreas Dilger 已提交
1179
   *dp = '\0';
1180 1181
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1182 1183

   if (key_len == 0)
A
Andreas Dilger 已提交
1184
   {
1185 1186
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1187
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1188 1189 1190 1191
   }

   if (key_len > 79)
   {
1192
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1193 1194 1195
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1196

1197
   return (key_len);
A
Andreas Dilger 已提交
1198 1199 1200
}
#endif

G
Guy Schalnat 已提交
1201
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1202
/* write a tEXt chunk */
1203
void /* PRIVATE */
G
Guy Schalnat 已提交
1204
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1205
   png_size_t text_len)
G
Guy Schalnat 已提交
1206
{
1207 1208 1209
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1210
   png_size_t key_len;
1211
   png_charp new_key;
A
Andreas Dilger 已提交
1212 1213 1214 1215

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

A
Andreas Dilger 已提交
1220
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1221
      text_len = 0;
1222 1223
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1224 1225

   /* make sure we include the 0 after the key */
1226
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1227 1228 1229 1230
   /*
    * 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.
1231
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1232
    */
1233
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1234
   if (text_len)
A
Andreas Dilger 已提交
1235
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1236

G
Guy Schalnat 已提交
1237
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1238
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1239
}
G
Guy Schalnat 已提交
1240
#endif
G
Guy Schalnat 已提交
1241

G
Guy Schalnat 已提交
1242
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1243
/* write a compressed text chunk */
1244
void /* PRIVATE */
G
Guy Schalnat 已提交
1245
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1246
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1247
{
1248 1249 1250
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1251
   png_size_t key_len;
G
Guy Schalnat 已提交
1252
   char buf[1];
1253
   png_charp new_key;
1254
   compression_state comp;
G
Guy Schalnat 已提交
1255

A
Andreas Dilger 已提交
1256 1257 1258 1259
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1264 1265 1266 1267 1268 1269 1270
   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;
   }

1271 1272
   text_len = png_strlen(text);

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

1275
   /* compute the compressed data; do it now for the length */
1276 1277
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1278

1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
   /* 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 已提交
1289

1290 1291 1292 1293
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1294

1295 1296
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1297
void /* PRIVATE */
1298
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1299
    png_charp lang, png_charp lang_key, png_charp text)
1300 1301 1302 1303
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1304
   png_size_t lang_len, key_len, lang_key_len, text_len;
1305 1306 1307
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1308

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

1311
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1312
   {
1313
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1314 1315
      return;
   }
1316 1317
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang,
      &new_lang))==0)
1318
   {
1319
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1320 1321
      return;
   }
1322 1323
   lang_key_len = png_strlen(lang_key);
   text_len = png_strlen(text);
G
Guy Schalnat 已提交
1324

1325 1326
   if (text == NULL || *text == '\0')
      text_len = 0;
G
Guy Schalnat 已提交
1327

1328
   /* compute the compressed data; do it now for the length */
1329 1330
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1331

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

1335 1336 1337 1338 1339 1340 1341
   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 已提交
1342

1343 1344 1345 1346 1347 1348 1349
   /*
    * 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);
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360

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

1361
   png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
1362
   png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
1363
   png_write_chunk_data(png_ptr, '\0', 1);
G
Guy Schalnat 已提交
1364

1365
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1366 1367

   png_write_chunk_end(png_ptr);
1368 1369
   png_free(png_ptr, new_key);
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1370
}
G
Guy Schalnat 已提交
1371
#endif
G
Guy Schalnat 已提交
1372

A
Andreas Dilger 已提交
1373 1374
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1375
void /* PRIVATE */
A
Andreas Dilger 已提交
1376 1377
png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
   png_uint_32 y_offset,
G
Guy Schalnat 已提交
1378 1379
   int unit_type)
{
1380 1381 1382
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1383 1384
   png_byte buf[9];

A
Andreas Dilger 已提交
1385 1386 1387
   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 已提交
1388

A
Andreas Dilger 已提交
1389 1390
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1391
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1392

1393
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1394
}
G
Guy Schalnat 已提交
1395
#endif
G
Guy Schalnat 已提交
1396

A
Andreas Dilger 已提交
1397
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1398
/* write the pCAL chunk (described in the PNG extensions document) */
1399
void /* PRIVATE */
A
Andreas Dilger 已提交
1400 1401 1402
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)
{
1403 1404 1405
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1406
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1407 1408
   png_uint_32p params_len;
   png_byte buf[10];
1409
   png_charp new_purpose;
A
Andreas Dilger 已提交
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
   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;
   png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
   png_debug1(3, "pCAL units length = %d\n", units_len);
   total_len = purpose_len + units_len + 10;

1422 1423
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1424 1425 1426 1427 1428 1429

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

   png_debug1(3, "pCAL total length = %d\n", total_len);
1435
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1436
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
   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]);
   }

1452
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1453 1454 1455 1456
   png_write_chunk_end(png_ptr);
}
#endif

1457 1458
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1459
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1460
void /* PRIVATE */
1461
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1462 1463 1464 1465 1466 1467 1468 1469 1470
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

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

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
#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
1481 1482
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1483
#endif
1484
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1485 1486 1487

   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);
1488
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1489 1490 1491 1492 1493
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf));

   png_write_chunk_end(png_ptr);
}
1494 1495
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1496
void /* PRIVATE */
1497
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1498 1499 1500 1501 1502 1503 1504 1505
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1506
   png_debug(1, "in png_write_sCAL_s\n");
1507

1508 1509
   strcpy(wbuf,(const char *)width);
   strcpy(hbuf,(const char *)height);
1510
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1511 1512 1513

   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);
1514
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1515 1516 1517 1518 1519 1520
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf));

   png_write_chunk_end(png_ptr);
}
#endif
1521 1522
#endif
#endif
1523

A
Andreas Dilger 已提交
1524 1525
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1526
void /* PRIVATE */
A
Andreas Dilger 已提交
1527 1528
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1529 1530
   int unit_type)
{
1531 1532 1533
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1534 1535
   png_byte buf[9];

A
Andreas Dilger 已提交
1536 1537 1538
   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 已提交
1539

A
Andreas Dilger 已提交
1540 1541
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1542
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1543

1544
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1545
}
G
Guy Schalnat 已提交
1546
#endif
G
Guy Schalnat 已提交
1547

G
Guy Schalnat 已提交
1548
#if defined(PNG_WRITE_tIME_SUPPORTED)
1549 1550 1551
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1552
void /* PRIVATE */
G
Guy Schalnat 已提交
1553
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1554
{
1555 1556 1557
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1558 1559
   png_byte buf[7];

A
Andreas Dilger 已提交
1560
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1561 1562 1563 1564 1565 1566 1567 1568
   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 已提交
1569 1570 1571 1572 1573 1574 1575
   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;

1576
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1577
}
G
Guy Schalnat 已提交
1578
#endif
G
Guy Schalnat 已提交
1579 1580

/* initializes the row writing capability of libpng */
1581
void /* PRIVATE */
G
Guy Schalnat 已提交
1582
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1583
{
1584
#ifdef PNG_USE_LOCAL_ARRAYS
1585
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1586

1587 1588
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1589

1590 1591
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1592

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

1596 1597
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1598
#endif
1599

A
Andreas Dilger 已提交
1600 1601 1602 1603 1604 1605
   png_size_t buf_size;

   png_debug(1, "in png_write_start_row\n");
   buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
                            png_ptr->usr_bit_depth + 7) >> 3) + 1);

G
Guy Schalnat 已提交
1606
   /* set up row buffer */
1607
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1608
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1609 1610 1611

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1612
   {
A
Andreas Dilger 已提交
1613
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1614
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1615
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1616 1617
   }

A
Andreas Dilger 已提交
1618
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1619 1620 1621
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1622
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1623
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1624 1625 1626

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1627
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1628
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1629
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1630 1631 1632 1633
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1634 1635
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1636
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1637 1638 1639 1640
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1641
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1642
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1643
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1644
      }
G
Guy Schalnat 已提交
1645 1646
   }

1647
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1648
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1649
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1650 1651 1652 1653 1654
   {
      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 已提交
1655 1656
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1657 1658 1659 1660 1661 1662 1663 1664
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1665
#endif
G
Guy Schalnat 已提交
1666
   {
G
Guy Schalnat 已提交
1667 1668 1669
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1670 1671
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1672 1673
}

A
Andreas Dilger 已提交
1674
/* Internal use only.  Called when finished processing a row of data. */
1675
void /* PRIVATE */
G
Guy Schalnat 已提交
1676
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1677
{
1678
#ifdef PNG_USE_LOCAL_ARRAYS
1679
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1680

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

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

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

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

G
Guy Schalnat 已提交
1694 1695
   int ret;

A
Andreas Dilger 已提交
1696
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1697 1698
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1699

G
Guy Schalnat 已提交
1700
   /* see if we are done */
G
Guy Schalnat 已提交
1701
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1702
      return;
G
Guy Schalnat 已提交
1703

1704
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
   /* 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 已提交
1721
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1722 1723 1724 1725 1726 1727 1728
               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 已提交
1729 1730
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1731 1732 1733 1734
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1735
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1736
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1737
      {
A
Andreas Dilger 已提交
1738
         if (png_ptr->prev_row != NULL)
1739
            png_memset(png_ptr->prev_row, 0,
A
Andreas Dilger 已提交
1740
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1741 1742
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1743
         return;
G
Guy Schalnat 已提交
1744
      }
G
Guy Schalnat 已提交
1745
   }
1746
#endif
G
Guy Schalnat 已提交
1747 1748 1749 1750 1751 1752

   /* 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 已提交
1753
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1754
      /* check for an error */
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
      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 已提交
1766
      {
A
Andreas Dilger 已提交
1767
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1768
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1769
         else
G
Guy Schalnat 已提交
1770
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1771 1772 1773 1774
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1775
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1776 1777
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1778
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1779 1780
   }

A
Andreas Dilger 已提交
1781
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1782 1783
}

G
Guy Schalnat 已提交
1784
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1785 1786 1787 1788 1789 1790 1791
/* 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.
 */
1792
void /* PRIVATE */
G
Guy Schalnat 已提交
1793
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1794
{
1795
#ifdef PNG_USE_LOCAL_ARRAYS
1796
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1797

1798 1799
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1800

1801 1802
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1803
#endif
1804

A
Andreas Dilger 已提交
1805
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1806
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1807 1808 1809 1810 1811
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1812
   {
1813
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1814
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1815
      {
G
Guy Schalnat 已提交
1816 1817
         case 1:
         {
G
Guy Schalnat 已提交
1818 1819
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1820 1821 1822
            int shift;
            int d;
            int value;
1823 1824
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1825 1826 1827 1828

            dp = row;
            d = 0;
            shift = 7;
1829
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1830 1831 1832
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1833
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1834 1835 1836 1837 1838
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1839
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1840 1841 1842 1843 1844 1845 1846
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1847
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1848 1849 1850
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1851
         {
G
Guy Schalnat 已提交
1852 1853
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1854 1855 1856
            int shift;
            int d;
            int value;
1857 1858
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1859 1860 1861 1862

            dp = row;
            shift = 6;
            d = 0;
1863
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1864 1865 1866
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1867
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1868 1869 1870 1871 1872
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1873
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1874 1875 1876 1877 1878 1879
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1880
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1881 1882 1883 1884
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1885 1886
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1887
            int shift;
G
Guy Schalnat 已提交
1888 1889
            int d;
            int value;
1890 1891
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1892 1893 1894 1895

            dp = row;
            shift = 4;
            d = 0;
1896
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1897 1898 1899
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
1900
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
1901 1902 1903 1904
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1905 1906
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1907 1908 1909 1910 1911 1912
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1913
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1914 1915 1916 1917
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
1918 1919
            png_bytep sp;
            png_bytep dp;
1920 1921
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
1922
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
1923

G
Guy Schalnat 已提交
1924
            /* start at the beginning */
G
Guy Schalnat 已提交
1925 1926 1927 1928 1929
            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 */
1930
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1931 1932 1933
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
1934
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
1935 1936
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
1937
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
1938 1939 1940
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
1941
            break;
G
Guy Schalnat 已提交
1942 1943 1944 1945 1946 1947 1948
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
1949 1950
         row_info->rowbytes = ((row_info->width *
            row_info->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
1951 1952
   }
}
G
Guy Schalnat 已提交
1953
#endif
G
Guy Schalnat 已提交
1954

A
Andreas Dilger 已提交
1955 1956
/* 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
1957 1958
 * chosen filter.
 */
1959
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
A
Andreas Dilger 已提交
1960
#define PNG_HISHIFT 10
1961 1962
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
1963
void /* PRIVATE */
G
Guy Schalnat 已提交
1964
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
1965
{
G
Guy Schalnat 已提交
1966
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
1967
   png_uint_32 mins, bpp;
1968
   png_byte filter_to_do = png_ptr->do_filter;
1969 1970 1971 1972
   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 已提交
1973

A
Andreas Dilger 已提交
1974
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
1975 1976
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
1977 1978 1979

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
1980 1981 1982 1983
   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
1984
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
1985
    * as the "minimum sum of absolute differences" heuristic.  Other
1986
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
1987
    * (experimental and can in theory improve compression), and the "zlib
1988 1989 1990
    * 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 已提交
1991
    * computationally expensive).
1992 1993 1994 1995 1996 1997 1998 1999 2000
    *
    * 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 已提交
2001
    */
G
Guy Schalnat 已提交
2002

2003

G
Guy Schalnat 已提交
2004
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2005 2006
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2007
   if ((filter_to_do & PNG_FILTER_NONE) &&
2008
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2009
   {
G
Guy Schalnat 已提交
2010 2011
      png_bytep rp;
      png_uint_32 sum = 0;
2012
      png_uint_32 i;
A
Andreas Dilger 已提交
2013
      int v;
G
Guy Schalnat 已提交
2014

2015
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2016 2017 2018 2019
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2020 2021 2022 2023 2024

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2025
         int j;
A
Andreas Dilger 已提交
2026 2027 2028 2029
         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 */
2030
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2031
         {
2032
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2033
            {
2034
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2035
                  PNG_WEIGHT_SHIFT;
2036
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
                  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 已提交
2056 2057
      mins = sum;
   }
G
Guy Schalnat 已提交
2058

G
Guy Schalnat 已提交
2059
   /* sub filter */
2060 2061 2062 2063
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2064
      png_uint_32 i;
2065 2066 2067 2068 2069
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2070
      for (lp = row_buf + 1; i < row_bytes;
2071 2072 2073 2074 2075 2076 2077 2078
         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 已提交
2079 2080
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2081
      png_uint_32 sum = 0, lmins = mins;
2082
      png_uint_32 i;
A
Andreas Dilger 已提交
2083 2084 2085
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2086
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2087 2088 2089 2090 2091
       * 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)
      {
2092
         int j;
A
Andreas Dilger 已提交
2093 2094 2095 2096
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2097
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2098
         {
2099
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2100
            {
2101
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2102
                  PNG_WEIGHT_SHIFT;
2103
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
                  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 已提交
2119

G
Guy Schalnat 已提交
2120 2121 2122 2123
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2124

G
Guy Schalnat 已提交
2125 2126
         sum += (v < 128) ? v : 256 - v;
      }
2127 2128
      for (lp = row_buf + 1; i < row_info->rowbytes;
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2129 2130 2131 2132
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2133 2134 2135 2136 2137 2138 2139 2140

         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)
      {
2141
         int j;
A
Andreas Dilger 已提交
2142 2143 2144 2145
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2146
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2147
         {
2148
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2149
            {
2150
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2151
                  PNG_WEIGHT_SHIFT;
2152
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
                  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 已提交
2166
      }
A
Andreas Dilger 已提交
2167 2168
#endif

G
Guy Schalnat 已提交
2169 2170 2171 2172 2173
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2174 2175
   }

G
Guy Schalnat 已提交
2176
   /* up filter */
2177 2178 2179
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2180
      png_uint_32 i;
2181 2182

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2183
           pp = prev_row + 1; i < row_bytes;
2184 2185 2186 2187 2188 2189 2190 2191
           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 已提交
2192 2193
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2194
      png_uint_32 sum = 0, lmins = mins;
2195
      png_uint_32 i;
A
Andreas Dilger 已提交
2196 2197
      int v;

2198

A
Andreas Dilger 已提交
2199 2200 2201
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2202
         int j;
A
Andreas Dilger 已提交
2203 2204 2205 2206
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2207
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2208
         {
2209
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2210
            {
2211
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2212
                  PNG_WEIGHT_SHIFT;
2213
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228
                  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 已提交
2229

G
Guy Schalnat 已提交
2230
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2231
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2232
      {
2233
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2234 2235

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2236 2237 2238

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2239
      }
A
Andreas Dilger 已提交
2240 2241 2242 2243

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2244
         int j;
A
Andreas Dilger 已提交
2245 2246 2247 2248
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2249
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2250
         {
2251
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2252
            {
2253
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2254
                  PNG_WEIGHT_SHIFT;
2255
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
                  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 已提交
2272 2273 2274 2275 2276 2277 2278 2279
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2280 2281 2282
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2283
      png_uint_32 i;
2284
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2285
           pp = prev_row + 1; i < bpp; i++)
2286
      {
2287
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2288
      }
2289
      for (lp = row_buf + 1; i < row_bytes; i++)
2290
      {
2291 2292
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2293 2294 2295 2296 2297
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2298
   {
G
Guy Schalnat 已提交
2299
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2300
      png_uint_32 sum = 0, lmins = mins;
2301
      png_uint_32 i;
A
Andreas Dilger 已提交
2302 2303 2304 2305 2306
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2307
         int j;
A
Andreas Dilger 已提交
2308 2309 2310 2311
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2312
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2313
         {
2314
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2315
            {
2316
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2317
                  PNG_WEIGHT_SHIFT;
2318
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
                  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 已提交
2334

G
Guy Schalnat 已提交
2335
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2336
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2337
      {
2338
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2339

G
Guy Schalnat 已提交
2340 2341
         sum += (v < 128) ? v : 256 - v;
      }
2342
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2343
      {
2344
         v = *dp++ =
2345
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2346

G
Guy Schalnat 已提交
2347
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2348 2349 2350

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2351
      }
A
Andreas Dilger 已提交
2352 2353 2354 2355

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2356
         int j;
A
Andreas Dilger 已提交
2357 2358 2359 2360
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2361
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2362
         {
2363
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2364
            {
2365
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2366
                  PNG_WEIGHT_SHIFT;
2367
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383
                  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 已提交
2384 2385 2386 2387 2388 2389
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2390

A
Andreas Dilger 已提交
2391
   /* Paeth filter */
2392 2393 2394
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2395
      png_uint_32 i;
2396
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2397
           pp = prev_row + 1; i < bpp; i++)
2398
      {
2399
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2400 2401
      }

2402
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2403 2404 2405
      {
         int a, b, c, pa, pb, pc, p;

2406 2407 2408
         b = *pp++;
         c = *cp++;
         a = *lp++;
2409

2410 2411
         p = b - c;
         pc = a - c;
2412 2413

#ifdef PNG_USE_ABS
2414 2415 2416
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2417
#else
2418 2419 2420
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2421 2422 2423 2424
#endif

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

2425
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2426 2427 2428 2429 2430
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2431 2432
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2433
      png_uint_32 sum = 0, lmins = mins;
2434
      png_uint_32 i;
A
Andreas Dilger 已提交
2435 2436 2437 2438 2439
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2440
         int j;
A
Andreas Dilger 已提交
2441 2442 2443 2444
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2445
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2446
         {
2447
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2448
            {
2449
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2450
                  PNG_WEIGHT_SHIFT;
2451
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466
                  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 已提交
2467

G
Guy Schalnat 已提交
2468
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2469
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2470
      {
2471
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2472

G
Guy Schalnat 已提交
2473 2474
         sum += (v < 128) ? v : 256 - v;
      }
2475

2476
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2477 2478
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2479

2480 2481 2482
         b = *pp++;
         c = *cp++;
         a = *lp++;
2483 2484

#ifndef PNG_SLOW_PAETH
2485 2486
         p = b - c;
         pc = a - c;
2487
#ifdef PNG_USE_ABS
2488 2489 2490
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2491
#else
2492 2493 2494
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2495 2496 2497
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2498
         p = a + b - c;
2499 2500 2501
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2502 2503 2504 2505 2506 2507
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2508
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2509

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

G
Guy Schalnat 已提交
2512
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2513 2514 2515

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2516
      }
A
Andreas Dilger 已提交
2517 2518 2519 2520

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2521
         int j;
A
Andreas Dilger 已提交
2522 2523 2524 2525
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

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

G
Guy Schalnat 已提交
2557
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2558 2559 2560 2561 2562

#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)
   {
2563 2564
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2565
      {
2566
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2567
      }
2568
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2569 2570
   }
#endif
G
Guy Schalnat 已提交
2571
}
G
Guy Schalnat 已提交
2572

G
Guy Schalnat 已提交
2573

A
Andreas Dilger 已提交
2574
/* Do the actual writing of a previously filtered row. */
2575
void /* PRIVATE */
G
Guy Schalnat 已提交
2576 2577
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2578 2579
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2580
   /* set up the zlib input buffer */
2581

A
Andreas Dilger 已提交
2582 2583
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2584 2585
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2586
   {
G
Guy Schalnat 已提交
2587
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2588

G
Guy Schalnat 已提交
2589
      /* compress the data */
A
Andreas Dilger 已提交
2590
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2591 2592 2593
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2594
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2595
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2596 2597 2598
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2599

G
Guy Schalnat 已提交
2600
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2601
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2602 2603 2604
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2605 2606
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2607 2608
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2609
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2610

G
Guy Schalnat 已提交
2611
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2612
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2613 2614 2615 2616 2617 2618 2619 2620
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2621 2622
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2623

G
Guy Schalnat 已提交
2624 2625 2626 2627 2628 2629 2630
#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 已提交
2631
   }
2632
#endif
G
Guy Schalnat 已提交
2633
}