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

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * libpng 1.0.9beta5 - December 15, 2000
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998, 1999, 2000 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);
G
Guy Schalnat 已提交
134 135
}

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
175
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
176 177 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
      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);

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

293 294 295 296 297 298
            /* 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++;
299

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

320
   return((int)text_len);
321 322 323
}

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

   /* handle the no-compression case */
   if (comp->input)
   {
       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++)
   {
339 340
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
341
      png_free(png_ptr, comp->output_ptr[i]);
342
      comp->output_ptr[i]=NULL;
343 344 345
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
346
      comp->output_ptr=NULL;
347 348 349 350 351 352 353 354 355 356 357
   /* 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 已提交
358
/* Write the IHDR chunk, and update the png_struct with the necessary
359 360 361
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
362
void /* PRIVATE */
G
Guy Schalnat 已提交
363
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
364 365 366
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
367 368 369
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
G
Guy Schalnat 已提交
370 371
   png_byte buf[13]; /* buffer to store the IHDR info */

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

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

422 423 424 425 426 427
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
428 429
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
430
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
431 432
   }

433
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
434 435
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
436 437
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
438
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
439
   }
440 441 442
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
443 444 445 446 447

   /* 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;
448
   png_ptr->filter_type = (png_byte)filter_type;
G
Guy Schalnat 已提交
449 450 451
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
452
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
A
Andreas Dilger 已提交
453
   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
454 455 456
   /* 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 已提交
457 458 459 460 461 462 463 464 465 466
   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 已提交
467 468

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

A
Andreas Dilger 已提交
471
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
472 473 474
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
475
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
476
   {
A
Andreas Dilger 已提交
477 478
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
479
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
480
      else
G
Guy Schalnat 已提交
481
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
482
   }
G
Guy Schalnat 已提交
483
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
484
   {
G
Guy Schalnat 已提交
485
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
486 487 488 489
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
490
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
491
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
492
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
493
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
494
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
G
Guy Schalnat 已提交
495
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
496
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
497
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
498
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
499 500
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
501 502
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
503

G
Guy Schalnat 已提交
504
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
505 506 507
}

/* write the palette.  We are careful not to trust png_color to be in the
508
 * correct order for PNG, so people can redefine it to any convenient
509 510
 * structure.
 */
511
void /* PRIVATE */
A
Andreas Dilger 已提交
512
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
513
{
514 515 516
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
517
   png_uint_32 i;
G
Guy Schalnat 已提交
518
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
519 520
   png_byte buf[3];

A
Andreas Dilger 已提交
521
   png_debug(1, "in png_write_PLTE\n");
522
   if ((
523 524
#if defined(PNG_MNG_FEATURES_SUPPORTED)
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
525 526 527 528 529 530 531 532 533 534 535 536
#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 已提交
537 538
   }

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

542
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
543
#ifndef PNG_NO_POINTER_INDEXING
A
Andreas Dilger 已提交
544
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
545 546 547 548
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
549
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
550
   }
551 552 553 554 555 556 557 558 559 560 561
#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 已提交
562
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
563
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
564 565 566
}

/* write an IDAT chunk */
567
void /* PRIVATE */
A
Andreas Dilger 已提交
568
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
569
{
570 571 572
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
573
   png_debug(1, "in png_write_IDAT\n");
574
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
575
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
576 577 578
}

/* write an IEND chunk */
579
void /* PRIVATE */
G
Guy Schalnat 已提交
580
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
581
{
582 583 584
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
585
   png_debug(1, "in png_write_IEND\n");
586
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
A
Andreas Dilger 已提交
587
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
588 589
}

G
Guy Schalnat 已提交
590
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
591
/* write a gAMA chunk */
592
#ifdef PNG_FLOATING_POINT_SUPPORTED
593
void /* PRIVATE */
A
Andreas Dilger 已提交
594
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
595
{
596 597 598
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
599 600 601
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
602
   png_debug(1, "in png_write_gAMA\n");
603
   /* file_gamma is saved in 1/100,000ths */
604
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
605
   png_save_uint_32(buf, igamma);
606
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
607
}
G
Guy Schalnat 已提交
608
#endif
609
#ifdef PNG_FIXED_POINT_SUPPORTED
610
void /* PRIVATE */
611
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
612 613 614 615 616 617 618
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
619
   /* file_gamma is saved in 1/100,000ths */
620 621 622 623 624
   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 已提交
625

626 627
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
628
void /* PRIVATE */
629
png_write_sRGB(png_structp png_ptr, int srgb_intent)
630
{
631 632 633
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
634 635 636
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
637
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
638 639
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
640
   buf[0]=(png_byte)srgb_intent;
641
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
642 643 644
}
#endif

645 646
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
647
void /* PRIVATE */
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
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;
   }

666
   if (compression_type)
667
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
668

669
   if (profile == NULL)
670 671 672
      profile_len = 0;

   if (profile_len)
673
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
674
          PNG_TEXT_COMPRESSION_zTXt, &comp);
675 676 677 678

   /* 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);
679
   new_name[name_len+1]=0x00;
680 681 682 683 684 685 686 687 688 689 690 691
   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 */
692
void /* PRIVATE */
693
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
694 695 696 697 698 699 700 701 702
{
#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;
703
   png_sPLT_entryp ep;
704 705 706
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
707 708

   png_debug(1, "in png_write_sPLT\n");
709 710
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
711 712 713 714 715 716 717
   {
      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,
718
          (png_uint_32)(name_len + 2 + palette_size));
719
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
720
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
721 722

   /* loop through each palette entry, writing appropriately */
723
#ifndef PNG_NO_POINTER_INDEXING
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
   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);
   }
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
#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
767 768 769 770 771 772

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

G
Guy Schalnat 已提交
773
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
774
/* write the sBIT chunk */
775
void /* PRIVATE */
G
Guy Schalnat 已提交
776
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
777
{
778 779 780
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
781
   png_byte buf[4];
A
Andreas Dilger 已提交
782
   png_size_t size;
G
Guy Schalnat 已提交
783

A
Andreas Dilger 已提交
784
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
785
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
786 787
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
788
      png_byte maxbits;
G
Guy Schalnat 已提交
789

790 791
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
792 793
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
794 795 796 797 798
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
799 800 801 802 803 804 805
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
806 807 808 809 810
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
811 812 813 814 815 816
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
817 818 819 820 821
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
822 823 824
      buf[size++] = sbit->alpha;
   }

825
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
826
}
G
Guy Schalnat 已提交
827
#endif
G
Guy Schalnat 已提交
828

G
Guy Schalnat 已提交
829
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
830
/* write the cHRM chunk */
831
#ifdef PNG_FLOATING_POINT_SUPPORTED
832
void /* PRIVATE */
A
Andreas Dilger 已提交
833
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
834 835
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
836
{
837 838 839
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
840
   png_byte buf[32];
841
   png_uint_32 itemp;
G
Guy Schalnat 已提交
842

A
Andreas Dilger 已提交
843
   png_debug(1, "in png_write_cHRM\n");
844
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
845 846 847 848
   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");
849 850
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
851
#endif
G
Guy Schalnat 已提交
852 853
      return;
   }
854
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
855
   png_save_uint_32(buf, itemp);
856
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
857
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
858 859 860 861 862 863 864

   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;
   }
865
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
866
   png_save_uint_32(buf + 8, itemp);
867
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
868
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
869 870 871 872 873 874 875

   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;
   }
876
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
877
   png_save_uint_32(buf + 16, itemp);
878
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
879
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
880 881 882 883 884 885 886

   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;
   }
887
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
888
   png_save_uint_32(buf + 24, itemp);
889
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
890
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
891

892
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
893
}
G
Guy Schalnat 已提交
894
#endif
895
#ifdef PNG_FIXED_POINT_SUPPORTED
896
void /* PRIVATE */
897 898 899 900
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)
901 902 903 904 905 906 907
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
908
   /* each value is saved in 1/100,000ths */
909 910
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
911
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
912 913
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
914
#endif
915 916 917 918 919 920 921
      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)
   {
922
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
923 924 925 926 927 928 929
      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)
   {
930
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
931 932 933 934 935 936 937
      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)
   {
938
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
939 940 941 942 943 944 945 946 947
      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 已提交
948

G
Guy Schalnat 已提交
949
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
950
/* write the tRNS chunk */
951
void /* PRIVATE */
G
Guy Schalnat 已提交
952
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
953 954
   int num_trans, int color_type)
{
955 956 957
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
958 959
   png_byte buf[6];

A
Andreas Dilger 已提交
960
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
961 962
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
963
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
964 965 966 967
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
968
      /* write the chunk out as it is */
969
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
970 971 972 973 974
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
      png_save_uint_16(buf, tran->gray);
975
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
976 977 978 979 980 981 982
   }
   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);
983
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
984
   }
G
Guy Schalnat 已提交
985 986
   else
   {
987
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
988
   }
G
Guy Schalnat 已提交
989
}
G
Guy Schalnat 已提交
990
#endif
G
Guy Schalnat 已提交
991

G
Guy Schalnat 已提交
992
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
993
/* write the background chunk */
994
void /* PRIVATE */
G
Guy Schalnat 已提交
995
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
996
{
997 998 999
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1000 1001
   png_byte buf[6];

A
Andreas Dilger 已提交
1002
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
1003 1004
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1005
      if (
1006 1007 1008
#if defined(PNG_MNG_FEATURES_SUPPORTED)
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1009 1010
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1011 1012 1013 1014
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1015
      buf[0] = back->index;
1016
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1017 1018 1019 1020 1021 1022
   }
   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);
1023
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1024 1025
   }
   else
G
Guy Schalnat 已提交
1026
   {
G
Guy Schalnat 已提交
1027
      png_save_uint_16(buf, back->gray);
1028
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1029 1030
   }
}
G
Guy Schalnat 已提交
1031
#endif
G
Guy Schalnat 已提交
1032

G
Guy Schalnat 已提交
1033
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1034
/* write the histogram */
1035
void /* PRIVATE */
1036
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1037
{
1038 1039 1040
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1041
   int i;
G
Guy Schalnat 已提交
1042 1043
   png_byte buf[3];

A
Andreas Dilger 已提交
1044
   png_debug(1, "in png_write_hIST\n");
1045
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1046
   {
A
Andreas Dilger 已提交
1047 1048
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1049 1050 1051 1052
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1053
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1054
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1055
   {
G
Guy Schalnat 已提交
1056
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1057
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1058 1059 1060
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1061
#endif
G
Guy Schalnat 已提交
1062

1063 1064
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1065 1066 1067 1068 1069
/* 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 已提交
1070 1071 1072 1073
 *
 * 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 已提交
1074
 */
1075
png_size_t /* PRIVATE */
1076
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1077
{
A
Andreas Dilger 已提交
1078
   png_size_t key_len;
1079
   png_charp kp, dp;
A
Andreas Dilger 已提交
1080
   int kflag;
1081
   int kwarn=0;
A
Andreas Dilger 已提交
1082

A
Andreas Dilger 已提交
1083 1084 1085 1086
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1087
   {
1088
      png_warning(png_ptr, "zero length keyword");
1089
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1090
   }
A
Andreas Dilger 已提交
1091 1092 1093

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

1094
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
A
Andreas Dilger 已提交
1095 1096 1097

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

1104
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1105
         png_warning(png_ptr, msg);
1106
#else
1107
         png_warning(png_ptr, "invalid character in keyword");
1108
#endif
A
Andreas Dilger 已提交
1109 1110 1111 1112 1113 1114
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1115
   }
A
Andreas Dilger 已提交
1116
   *dp = '\0';
A
Andreas Dilger 已提交
1117

A
Andreas Dilger 已提交
1118 1119 1120
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1121
   {
1122
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1123 1124 1125 1126 1127 1128

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1129 1130 1131
   }

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

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

A
Andreas Dilger 已提交
1144 1145 1146 1147
   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 已提交
1148
   {
A
Andreas Dilger 已提交
1149
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1150
      {
A
Andreas Dilger 已提交
1151 1152
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1153
      }
A
Andreas Dilger 已提交
1154
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1155 1156
      {
         key_len--;
1157
         kwarn=1;
A
Andreas Dilger 已提交
1158 1159 1160
      }
      else
      {
A
Andreas Dilger 已提交
1161 1162
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1163 1164
      }
   }
A
Andreas Dilger 已提交
1165
   *dp = '\0';
1166 1167
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1168 1169

   if (key_len == 0)
A
Andreas Dilger 已提交
1170
   {
1171 1172
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1173
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1174 1175 1176 1177
   }

   if (key_len > 79)
   {
1178
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1179 1180 1181
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1182

1183
   return (key_len);
A
Andreas Dilger 已提交
1184 1185 1186
}
#endif

G
Guy Schalnat 已提交
1187
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1188
/* write a tEXt chunk */
1189
void /* PRIVATE */
G
Guy Schalnat 已提交
1190
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1191
   png_size_t text_len)
G
Guy Schalnat 已提交
1192
{
1193 1194 1195
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1196
   png_size_t key_len;
1197
   png_charp new_key;
A
Andreas Dilger 已提交
1198 1199 1200 1201

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

A
Andreas Dilger 已提交
1206
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1207
      text_len = 0;
1208 1209
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1210 1211

   /* make sure we include the 0 after the key */
1212
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1213 1214 1215 1216
   /*
    * 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.
1217
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1218
    */
1219
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1220
   if (text_len)
A
Andreas Dilger 已提交
1221
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1222

G
Guy Schalnat 已提交
1223
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1224
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1225
}
G
Guy Schalnat 已提交
1226
#endif
G
Guy Schalnat 已提交
1227

G
Guy Schalnat 已提交
1228
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1229
/* write a compressed text chunk */
1230
void /* PRIVATE */
G
Guy Schalnat 已提交
1231
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1232
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1233
{
1234 1235 1236
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1237
   png_size_t key_len;
G
Guy Schalnat 已提交
1238
   char buf[1];
1239
   png_charp new_key;
1240
   compression_state comp;
G
Guy Schalnat 已提交
1241

A
Andreas Dilger 已提交
1242 1243 1244 1245
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1250 1251 1252 1253 1254 1255 1256
   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;
   }

1257 1258
   text_len = png_strlen(text);

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

1261
   /* compute the compressed data; do it now for the length */
1262 1263
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1264

1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
   /* 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 已提交
1275

1276 1277 1278 1279
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1280

1281 1282
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1283
void /* PRIVATE */
1284
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1285
    png_charp lang, png_charp lang_key, png_charp text)
1286 1287 1288 1289
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1290
   png_size_t lang_len, key_len, lang_key_len, text_len;
1291 1292 1293
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1294

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

1297
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1298
   {
1299
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1300 1301
      return;
   }
1302 1303
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang,
      &new_lang))==0)
1304
   {
1305
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1306 1307
      return;
   }
1308 1309
   lang_key_len = png_strlen(lang_key);
   text_len = png_strlen(text);
G
Guy Schalnat 已提交
1310

1311 1312
   if (text == NULL || *text == '\0')
      text_len = 0;
G
Guy Schalnat 已提交
1313

1314
   /* compute the compressed data; do it now for the length */
1315 1316
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1317

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

1321 1322 1323 1324 1325 1326 1327
   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 已提交
1328

1329 1330 1331 1332 1333 1334 1335
   /*
    * 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);
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346

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

1347
   png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
1348
   png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
1349
   png_write_chunk_data(png_ptr, '\0', 1);
G
Guy Schalnat 已提交
1350

1351
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1352 1353

   png_write_chunk_end(png_ptr);
1354 1355
   png_free(png_ptr, new_key);
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1356
}
G
Guy Schalnat 已提交
1357
#endif
G
Guy Schalnat 已提交
1358

A
Andreas Dilger 已提交
1359 1360
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1361
void /* PRIVATE */
A
Andreas Dilger 已提交
1362 1363
png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
   png_uint_32 y_offset,
G
Guy Schalnat 已提交
1364 1365
   int unit_type)
{
1366 1367 1368
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1369 1370
   png_byte buf[9];

A
Andreas Dilger 已提交
1371 1372 1373
   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 已提交
1374

A
Andreas Dilger 已提交
1375 1376
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1377
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1378

1379
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1380
}
G
Guy Schalnat 已提交
1381
#endif
G
Guy Schalnat 已提交
1382

A
Andreas Dilger 已提交
1383
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1384
/* write the pCAL chunk (described in the PNG extensions document) */
1385
void /* PRIVATE */
A
Andreas Dilger 已提交
1386 1387 1388
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)
{
1389 1390 1391
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1392
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1393 1394
   png_uint_32p params_len;
   png_byte buf[10];
1395
   png_charp new_purpose;
A
Andreas Dilger 已提交
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
   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;

1408 1409
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1410 1411 1412 1413 1414 1415

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

   png_debug1(3, "pCAL total length = %d\n", total_len);
1421
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1422
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
   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]);
   }

1438
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1439 1440 1441 1442
   png_write_chunk_end(png_ptr);
}
#endif

1443 1444
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1445
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1446
void /* PRIVATE */
1447
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1448 1449 1450 1451 1452 1453 1454 1455 1456
{
#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");

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
#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
1467 1468
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1469
#endif
1470
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1471 1472 1473

   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);
1474
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1475 1476 1477 1478 1479
   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);
}
1480 1481
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1482
void /* PRIVATE */
1483
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1484 1485 1486 1487 1488 1489 1490 1491
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1492
   png_debug(1, "in png_write_sCAL_s\n");
1493

1494 1495
   strcpy(wbuf,(const char *)width);
   strcpy(hbuf,(const char *)height);
1496
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1497 1498 1499

   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);
1500
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1501 1502 1503 1504 1505 1506
   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
1507 1508
#endif
#endif
1509

A
Andreas Dilger 已提交
1510 1511
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1512
void /* PRIVATE */
A
Andreas Dilger 已提交
1513 1514
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1515 1516
   int unit_type)
{
1517 1518 1519
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1520 1521
   png_byte buf[9];

A
Andreas Dilger 已提交
1522 1523 1524
   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 已提交
1525

A
Andreas Dilger 已提交
1526 1527
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1528
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1529

1530
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1531
}
G
Guy Schalnat 已提交
1532
#endif
G
Guy Schalnat 已提交
1533

G
Guy Schalnat 已提交
1534
#if defined(PNG_WRITE_tIME_SUPPORTED)
1535 1536 1537
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1538
void /* PRIVATE */
G
Guy Schalnat 已提交
1539
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1540
{
1541 1542 1543
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1544 1545
   png_byte buf[7];

A
Andreas Dilger 已提交
1546
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1547 1548 1549 1550 1551 1552 1553 1554
   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 已提交
1555 1556 1557 1558 1559 1560 1561
   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;

1562
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1563
}
G
Guy Schalnat 已提交
1564
#endif
G
Guy Schalnat 已提交
1565 1566

/* initializes the row writing capability of libpng */
1567
void /* PRIVATE */
G
Guy Schalnat 已提交
1568
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1569
{
1570
#ifdef PNG_USE_LOCAL_ARRAYS
1571
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1572

1573 1574
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1575

1576 1577
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1578

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

1582 1583
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1584
#endif
1585

A
Andreas Dilger 已提交
1586 1587 1588 1589 1590 1591
   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 已提交
1592
   /* set up row buffer */
1593
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1594
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1595 1596 1597

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1598
   {
A
Andreas Dilger 已提交
1599
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1600
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1601
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1602 1603
   }

A
Andreas Dilger 已提交
1604
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1605 1606 1607
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1608
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1609
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1610 1611 1612

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1613
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1614
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1615
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1616 1617 1618 1619
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1620 1621
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1622
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1623 1624 1625 1626
      }

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

1633
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1634
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1635
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1636 1637 1638 1639 1640
   {
      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 已提交
1641 1642
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1643 1644 1645 1646 1647 1648 1649 1650
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1651
#endif
G
Guy Schalnat 已提交
1652
   {
G
Guy Schalnat 已提交
1653 1654 1655
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1656 1657
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1658 1659
}

A
Andreas Dilger 已提交
1660
/* Internal use only.  Called when finished processing a row of data. */
1661
void /* PRIVATE */
G
Guy Schalnat 已提交
1662
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1663
{
1664
#ifdef PNG_USE_LOCAL_ARRAYS
1665
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1666

1667 1668
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1669

1670 1671
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1672

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

1676 1677
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1678
#endif
1679

G
Guy Schalnat 已提交
1680 1681
   int ret;

A
Andreas Dilger 已提交
1682
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1683 1684
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1685

G
Guy Schalnat 已提交
1686
   /* see if we are done */
G
Guy Schalnat 已提交
1687
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1688
      return;
G
Guy Schalnat 已提交
1689

1690
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
   /* 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 已提交
1707
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1708 1709 1710 1711 1712 1713 1714
               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 已提交
1715 1716
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1717 1718 1719 1720
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1721
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1722
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1723
      {
A
Andreas Dilger 已提交
1724
         if (png_ptr->prev_row != NULL)
1725
            png_memset(png_ptr->prev_row, 0,
A
Andreas Dilger 已提交
1726
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1727 1728
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1729
         return;
G
Guy Schalnat 已提交
1730
      }
G
Guy Schalnat 已提交
1731
   }
1732
#endif
G
Guy Schalnat 已提交
1733 1734 1735 1736 1737 1738

   /* 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 已提交
1739
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1740
      /* check for an error */
1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
      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 已提交
1752
      {
A
Andreas Dilger 已提交
1753
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1754
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1755
         else
G
Guy Schalnat 已提交
1756
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1757 1758 1759 1760
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1761
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1762 1763
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1764
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1765 1766
   }

A
Andreas Dilger 已提交
1767
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1768 1769
}

G
Guy Schalnat 已提交
1770
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1771 1772 1773 1774 1775 1776 1777
/* 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.
 */
1778
void /* PRIVATE */
G
Guy Schalnat 已提交
1779
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1780
{
1781
#ifdef PNG_USE_LOCAL_ARRAYS
1782
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1783

1784 1785
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1786

1787 1788
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1789
#endif
1790

A
Andreas Dilger 已提交
1791
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1792
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1793 1794 1795 1796 1797
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1798
   {
1799
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1800
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1801
      {
G
Guy Schalnat 已提交
1802 1803
         case 1:
         {
G
Guy Schalnat 已提交
1804 1805
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1806 1807 1808
            int shift;
            int d;
            int value;
1809 1810
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1811 1812 1813 1814

            dp = row;
            d = 0;
            shift = 7;
1815
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1816 1817 1818
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1819
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1820 1821 1822 1823 1824
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1825
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1826 1827 1828 1829 1830 1831 1832
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1833
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1834 1835 1836
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1837
         {
G
Guy Schalnat 已提交
1838 1839
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1840 1841 1842
            int shift;
            int d;
            int value;
1843 1844
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1845 1846 1847 1848

            dp = row;
            shift = 6;
            d = 0;
1849
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1850 1851 1852
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1853
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1854 1855 1856 1857 1858
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1859
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1860 1861 1862 1863 1864 1865
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1866
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1867 1868 1869 1870
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1871 1872
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1873
            int shift;
G
Guy Schalnat 已提交
1874 1875
            int d;
            int value;
1876 1877
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1878 1879 1880 1881

            dp = row;
            shift = 4;
            d = 0;
1882
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1883 1884 1885
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
1886
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
1887 1888 1889 1890
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1891 1892
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1893 1894 1895 1896 1897 1898
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1899
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1900 1901 1902 1903
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
1904 1905
            png_bytep sp;
            png_bytep dp;
1906 1907
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
1908
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
1909

G
Guy Schalnat 已提交
1910
            /* start at the beginning */
G
Guy Schalnat 已提交
1911 1912 1913 1914 1915
            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 */
1916
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1917 1918 1919
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
1920
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
1921 1922
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
1923
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
1924 1925 1926
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
1927
            break;
G
Guy Schalnat 已提交
1928 1929 1930 1931 1932 1933 1934
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
1935 1936
         row_info->rowbytes = ((row_info->width *
            row_info->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
1937 1938
   }
}
G
Guy Schalnat 已提交
1939
#endif
G
Guy Schalnat 已提交
1940

A
Andreas Dilger 已提交
1941 1942
/* 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
1943 1944
 * chosen filter.
 */
1945
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
A
Andreas Dilger 已提交
1946
#define PNG_HISHIFT 10
1947 1948
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
1949
void /* PRIVATE */
G
Guy Schalnat 已提交
1950
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
1951
{
G
Guy Schalnat 已提交
1952
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
1953
   png_uint_32 mins, bpp;
1954
   png_byte filter_to_do = png_ptr->do_filter;
1955 1956 1957 1958
   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 已提交
1959

A
Andreas Dilger 已提交
1960
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
1961 1962
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
1963 1964 1965

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
1966 1967 1968 1969
   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
1970
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
1971
    * as the "minimum sum of absolute differences" heuristic.  Other
1972
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
1973
    * (experimental and can in theory improve compression), and the "zlib
1974 1975 1976
    * 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 已提交
1977
    * computationally expensive).
1978 1979 1980 1981 1982 1983 1984 1985 1986
    *
    * 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 已提交
1987
    */
G
Guy Schalnat 已提交
1988

1989

G
Guy Schalnat 已提交
1990
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
1991 1992
    * that has been chosen, as it doesn't actually do anything to the data.
    */
1993
   if ((filter_to_do & PNG_FILTER_NONE) &&
1994
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
1995
   {
G
Guy Schalnat 已提交
1996 1997
      png_bytep rp;
      png_uint_32 sum = 0;
1998
      png_uint_32 i;
A
Andreas Dilger 已提交
1999
      int v;
G
Guy Schalnat 已提交
2000

2001
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2002 2003 2004 2005
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2006 2007 2008 2009 2010

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2011
         int j;
A
Andreas Dilger 已提交
2012 2013 2014 2015
         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 */
2016
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2017
         {
2018
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2019
            {
2020
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2021
                  PNG_WEIGHT_SHIFT;
2022
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
                  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 已提交
2042 2043
      mins = sum;
   }
G
Guy Schalnat 已提交
2044

G
Guy Schalnat 已提交
2045
   /* sub filter */
2046 2047 2048 2049
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2050
      png_uint_32 i;
2051 2052 2053 2054 2055
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2056
      for (lp = row_buf + 1; i < row_bytes;
2057 2058 2059 2060 2061 2062 2063 2064
         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 已提交
2065 2066
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2067
      png_uint_32 sum = 0, lmins = mins;
2068
      png_uint_32 i;
A
Andreas Dilger 已提交
2069 2070 2071
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2072
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2073 2074 2075 2076 2077
       * 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)
      {
2078
         int j;
A
Andreas Dilger 已提交
2079 2080 2081 2082
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2083
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2084
         {
2085
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2086
            {
2087
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2088
                  PNG_WEIGHT_SHIFT;
2089
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104
                  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 已提交
2105

G
Guy Schalnat 已提交
2106 2107 2108 2109
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2110

G
Guy Schalnat 已提交
2111 2112
         sum += (v < 128) ? v : 256 - v;
      }
2113 2114
      for (lp = row_buf + 1; i < row_info->rowbytes;
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2115 2116 2117 2118
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2119 2120 2121 2122 2123 2124 2125 2126

         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)
      {
2127
         int j;
A
Andreas Dilger 已提交
2128 2129 2130 2131
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2132
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2133
         {
2134
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2135
            {
2136
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2137
                  PNG_WEIGHT_SHIFT;
2138
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
                  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 已提交
2152
      }
A
Andreas Dilger 已提交
2153 2154
#endif

G
Guy Schalnat 已提交
2155 2156 2157 2158 2159
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2160 2161
   }

G
Guy Schalnat 已提交
2162
   /* up filter */
2163 2164 2165
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2166
      png_uint_32 i;
2167 2168

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2169
           pp = prev_row + 1; i < row_bytes;
2170 2171 2172 2173 2174 2175 2176 2177
           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 已提交
2178 2179
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2180
      png_uint_32 sum = 0, lmins = mins;
2181
      png_uint_32 i;
A
Andreas Dilger 已提交
2182 2183
      int v;

2184

A
Andreas Dilger 已提交
2185 2186 2187
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2188
         int j;
A
Andreas Dilger 已提交
2189 2190 2191 2192
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_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 已提交
2215

G
Guy Schalnat 已提交
2216
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2217
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2218
      {
2219
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2220 2221

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2222 2223 2224

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2225
      }
A
Andreas Dilger 已提交
2226 2227 2228 2229

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2230
         int j;
A
Andreas Dilger 已提交
2231 2232 2233 2234
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2235
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2236
         {
2237
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2238
            {
2239
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2240
                  PNG_WEIGHT_SHIFT;
2241
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
                  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 已提交
2258 2259 2260 2261 2262 2263 2264 2265
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2266 2267 2268
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2269
      png_uint_32 i;
2270
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2271
           pp = prev_row + 1; i < bpp; i++)
2272
      {
2273
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2274
      }
2275
      for (lp = row_buf + 1; i < row_bytes; i++)
2276
      {
2277 2278
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2279 2280 2281 2282 2283
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2284
   {
G
Guy Schalnat 已提交
2285
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2286
      png_uint_32 sum = 0, lmins = mins;
2287
      png_uint_32 i;
A
Andreas Dilger 已提交
2288 2289 2290 2291 2292
      int v;

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

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

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

G
Guy Schalnat 已提交
2326 2327
         sum += (v < 128) ? v : 256 - v;
      }
2328
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2329
      {
2330
         v = *dp++ =
2331
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2332

G
Guy Schalnat 已提交
2333
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2334 2335 2336

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

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

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

A
Andreas Dilger 已提交
2377
   /* Paeth filter */
2378 2379 2380
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2381
      png_uint_32 i;
2382
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2383
           pp = prev_row + 1; i < bpp; i++)
2384
      {
2385
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2386 2387
      }

2388
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2389 2390 2391
      {
         int a, b, c, pa, pb, pc, p;

2392 2393 2394
         b = *pp++;
         c = *cp++;
         a = *lp++;
2395

2396 2397
         p = b - c;
         pc = a - c;
2398 2399

#ifdef PNG_USE_ABS
2400 2401 2402
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2403
#else
2404 2405 2406
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2407 2408 2409 2410
#endif

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

2411
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2412 2413 2414 2415 2416
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2417 2418
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2419
      png_uint_32 sum = 0, lmins = mins;
2420
      png_uint_32 i;
A
Andreas Dilger 已提交
2421 2422 2423 2424 2425
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2426
         int j;
A
Andreas Dilger 已提交
2427 2428 2429 2430
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2431
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2432
         {
2433
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2434
            {
2435
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2436
                  PNG_WEIGHT_SHIFT;
2437
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452
                  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 已提交
2453

G
Guy Schalnat 已提交
2454
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2455
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2456
      {
2457
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2458

G
Guy Schalnat 已提交
2459 2460
         sum += (v < 128) ? v : 256 - v;
      }
2461

2462
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2463 2464
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2465

2466 2467 2468
         b = *pp++;
         c = *cp++;
         a = *lp++;
2469 2470

#ifndef PNG_SLOW_PAETH
2471 2472
         p = b - c;
         pc = a - c;
2473
#ifdef PNG_USE_ABS
2474 2475 2476
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2477
#else
2478 2479 2480
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2481 2482 2483
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2484
         p = a + b - c;
2485 2486 2487
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2488 2489 2490 2491 2492 2493
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2494
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2495

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

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

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

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

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

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

G
Guy Schalnat 已提交
2543
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2544 2545 2546 2547 2548

#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)
   {
2549 2550
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2551
      {
2552
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2553
      }
2554
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2555 2556
   }
#endif
G
Guy Schalnat 已提交
2557
}
G
Guy Schalnat 已提交
2558

G
Guy Schalnat 已提交
2559

A
Andreas Dilger 已提交
2560
/* Do the actual writing of a previously filtered row. */
2561
void /* PRIVATE */
G
Guy Schalnat 已提交
2562 2563
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2564 2565
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2566
   /* set up the zlib input buffer */
2567

A
Andreas Dilger 已提交
2568 2569
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2570 2571
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2572
   {
G
Guy Schalnat 已提交
2573
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2574

G
Guy Schalnat 已提交
2575
      /* compress the data */
A
Andreas Dilger 已提交
2576
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2577 2578 2579
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2580
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2581
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2582 2583 2584
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2585

G
Guy Schalnat 已提交
2586
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2587
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2588 2589 2590
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2591 2592
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2593 2594
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2595
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2596

G
Guy Schalnat 已提交
2597
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2598
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2599 2600 2601 2602 2603 2604 2605 2606
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2607 2608
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2609

G
Guy Schalnat 已提交
2610 2611 2612 2613 2614 2615 2616
#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 已提交
2617
   }
2618
#endif
G
Guy Schalnat 已提交
2619
}