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

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * libpng 1.0.11beta3 - April 15, 2001
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2001 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9
 */
A
Andreas Dilger 已提交
10

G
Guy Schalnat 已提交
11 12
#define PNG_INTERNAL
#include "png.h"
13
#ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
14

A
Andreas Dilger 已提交
15 16 17 18
/* Place a 32-bit number into a buffer in PNG byte order.  We work
 * with unsigned numbers for convenience, although one supported
 * ancillary chunk uses signed (two's complement) numbers.
 */
19
void /* PRIVATE */
G
Guy Schalnat 已提交
20
png_save_uint_32(png_bytep buf, png_uint_32 i)
G
Guy Schalnat 已提交
21 22 23 24 25 26 27
{
   buf[0] = (png_byte)((i >> 24) & 0xff);
   buf[1] = (png_byte)((i >> 16) & 0xff);
   buf[2] = (png_byte)((i >> 8) & 0xff);
   buf[3] = (png_byte)(i & 0xff);
}

A
Andreas Dilger 已提交
28 29
#if defined(PNG_WRITE_pCAL_SUPPORTED)
/* The png_save_int_32 function assumes integers are stored in two's
30 31 32
 * complement format.  If this isn't the case, then this routine needs to
 * be modified to write data in two's complement format.
 */
33
void /* PRIVATE */
A
Andreas Dilger 已提交
34
png_save_int_32(png_bytep buf, png_int_32 i)
G
Guy Schalnat 已提交
35 36 37 38 39 40
{
   buf[0] = (png_byte)((i >> 24) & 0xff);
   buf[1] = (png_byte)((i >> 16) & 0xff);
   buf[2] = (png_byte)((i >> 8) & 0xff);
   buf[3] = (png_byte)(i & 0xff);
}
A
Andreas Dilger 已提交
41
#endif
G
Guy Schalnat 已提交
42

43 44 45 46
/* Place a 16-bit number into a buffer in PNG byte order.
 * The parameter is declared unsigned int, not png_uint_16,
 * just to avoid potential problems on pre-ANSI C compilers.
 */
47
void /* PRIVATE */
48
png_save_uint_16(png_bytep buf, unsigned int i)
G
Guy Schalnat 已提交
49 50 51 52 53
{
   buf[0] = (png_byte)((i >> 8) & 0xff);
   buf[1] = (png_byte)(i & 0xff);
}

A
Andreas Dilger 已提交
54
/* Write a PNG chunk all at once.  The type is an array of ASCII characters
55 56 57 58 59 60 61 62
 * representing the chunk name.  The array must be at least 4 bytes in
 * length, and does not need to be null terminated.  To be safe, pass the
 * pre-defined chunk names here, and if you need a new one, define it
 * where the others are defined.  The length is the length of the data.
 * All the data must be present.  If that is not possible, use the
 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
 * functions instead.
 */
63
void PNGAPI
A
Andreas Dilger 已提交
64
png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
A
Andreas Dilger 已提交
65
   png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
66
{
A
Andreas Dilger 已提交
67
   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
A
Andreas Dilger 已提交
68 69
   png_write_chunk_data(png_ptr, data, length);
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
70 71
}

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

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

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

A
Andreas Dilger 已提交
94
/* Write the data of a PNG chunk started with png_write_chunk_start().
95 96 97 98
 * Note that multiple calls to this function are allowed, and that the
 * sum of the lengths from these calls *must* add up to the total_length
 * given to png_write_chunk_start().
 */
99
void PNGAPI
A
Andreas Dilger 已提交
100
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
101
{
A
Andreas Dilger 已提交
102 103
   /* write the data, and run the CRC over it */
   if (data != NULL && length > 0)
G
Guy Schalnat 已提交
104 105
   {
      png_calculate_crc(png_ptr, data, length);
G
Guy Schalnat 已提交
106
      png_write_data(png_ptr, data, length);
G
Guy Schalnat 已提交
107 108 109
   }
}

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

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

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

A
Andreas Dilger 已提交
122 123 124 125
/* Simple function to write the signature.  If we have already written
 * the magic bytes of the signature, or more likely, the PNG stream is
 * being embedded into another stream and doesn't need its own signature,
 * we should call png_set_sig_bytes() to tell libpng how many of the
126 127
 * bytes have already been written.
 */
128
void /* PRIVATE */
G
Guy Schalnat 已提交
129
png_write_sig(png_structp png_ptr)
G
Guy Schalnat 已提交
130
{
131
   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
A
Andreas Dilger 已提交
132
   /* write the rest of the 8 byte signature */
133
   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
A
Andreas Dilger 已提交
134
      (png_size_t)8 - png_ptr->sig_bytes);
135 136
   if(png_ptr->sig_bytes < 3)
      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
G
Guy Schalnat 已提交
137 138
}

139
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/*
 * This pair of functions encapsulates the operation of (a) compressing a
 * text string, and (b) issuing it later as a series of chunk data writes.
 * The compression_state structure is shared context for these functions
 * set up by the caller in order to make the whole mess thread-safe.
 */

typedef struct
{
    char *input;   /* the uncompressed input data */
    int input_len;   /* its length */
    int num_output_ptr; /* number of output pointers used */
    int max_output_ptr; /* size of output_ptr */
    png_charpp output_ptr; /* array of pointers to output */
} compression_state;

/* compress given text into storage in the png_ptr structure */
157
static int /* PRIVATE */
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
png_text_compress(png_structp png_ptr,
        png_charp text, png_size_t text_len, int compression,
        compression_state *comp)
{
   int ret;

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

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
178
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
      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)));
238 239 240 241 242 243 244
               if (comp->output_ptr == (png_charpp)NULL)
               {
                  png_warning (png_ptr, "Cannot allocate compression buffer");
                  comp->output_ptr=old_ptr;
               }
               png_memcpy(comp->output_ptr, old_ptr, old_max
                  * sizeof (png_charp));
245 246 247 248 249
               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)));
250 251 252 253
               if (comp->output_ptr == (png_charpp)NULL)
               {
                  png_warning (png_ptr, "Cannot allocate compression buffer");
               }
254 255 256 257 258
         }

         /* save the data */
         comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
            (png_uint_32)png_ptr->zbuf_size);
259 260 261 262 263 264 265 266
         if (comp->output_ptr[comp->num_output_ptr] == (png_charp)NULL)
            png_warning (png_ptr, "Cannot allocate compression buffer");
         else
         {
            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
               png_ptr->zbuf_size);
            comp->num_output_ptr++;
         }
267 268 269 270 271 272 273 274 275 276 277 278 279 280

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

281
      if (ret == Z_OK)
282
      {
283 284
         /* check to see if we need more room */
         if (!(png_ptr->zstream.avail_out))
285
         {
286 287
            /* check to make sure our output array has room */
            if (comp->num_output_ptr >= comp->max_output_ptr)
288
            {
289 290 291 292 293 294 295 296 297 298 299 300
               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)));
301 302 303
                  if (comp->output_ptr != (png_charpp)NULL)
                    png_memcpy(comp->output_ptr, old_ptr,
                       old_max * sizeof (png_charp));
304 305 306 307 308
                  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)));
309 310
            }

311 312 313
            /* save off the data */
            comp->output_ptr[comp->num_output_ptr] =
               (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
314 315 316 317 318 319 320 321
            if (comp->output_ptr[comp->num_output_ptr] == (png_charp)NULL)
               png_warning (png_ptr, "Cannot allocate compression buffer");
            else
            {
               png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
                  png_ptr->zbuf_size);
               comp->num_output_ptr++;
            }
322

323 324 325 326 327 328 329 330 331 332 333 334
            /* 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");
335 336 337 338 339 340 341 342
      }
   } 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;

343
   return((int)text_len);
344 345 346
}

/* ship the compressed text out via chunk writes */
347
static void /* PRIVATE */
348 349 350 351 352 353 354 355 356 357 358 359 360 361
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++)
   {
362 363
      png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
         png_ptr->zbuf_size);
364
      png_free(png_ptr, comp->output_ptr[i]);
365
      comp->output_ptr[i]=NULL;
366 367 368
   }
   if (comp->max_output_ptr != 0)
      png_free(png_ptr, comp->output_ptr);
369
      comp->output_ptr=NULL;
370 371 372 373 374 375 376 377 378 379 380
   /* 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 已提交
381
/* Write the IHDR chunk, and update the png_struct with the necessary
382 383 384
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
385
void /* PRIVATE */
G
Guy Schalnat 已提交
386
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
387 388 389
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
390 391 392
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IHDR;
#endif
G
Guy Schalnat 已提交
393 394
   png_byte buf[13]; /* buffer to store the IHDR info */

A
Andreas Dilger 已提交
395
   png_debug(1, "in png_write_IHDR\n");
G
Guy Schalnat 已提交
396
   /* Check that we have valid input data from the application info */
G
Guy Schalnat 已提交
397 398
   switch (color_type)
   {
A
Andreas Dilger 已提交
399
      case PNG_COLOR_TYPE_GRAY:
G
Guy Schalnat 已提交
400 401 402 403 404 405 406
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8:
            case 16: png_ptr->channels = 1; break;
A
Andreas Dilger 已提交
407
            default: png_error(png_ptr,"Invalid bit depth for grayscale image");
G
Guy Schalnat 已提交
408
         }
G
Guy Schalnat 已提交
409
         break;
A
Andreas Dilger 已提交
410
      case PNG_COLOR_TYPE_RGB:
G
Guy Schalnat 已提交
411 412
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGB image");
G
Guy Schalnat 已提交
413 414
         png_ptr->channels = 3;
         break;
A
Andreas Dilger 已提交
415
      case PNG_COLOR_TYPE_PALETTE:
G
Guy Schalnat 已提交
416 417 418 419 420 421 422 423 424
         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 已提交
425
      case PNG_COLOR_TYPE_GRAY_ALPHA:
G
Guy Schalnat 已提交
426 427
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
G
Guy Schalnat 已提交
428 429
         png_ptr->channels = 2;
         break;
A
Andreas Dilger 已提交
430
      case PNG_COLOR_TYPE_RGB_ALPHA:
G
Guy Schalnat 已提交
431 432
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGBA image");
G
Guy Schalnat 已提交
433 434
         png_ptr->channels = 4;
         break;
G
Guy Schalnat 已提交
435 436 437 438
      default:
         png_error(png_ptr, "Invalid image color type specified");
   }

A
Andreas Dilger 已提交
439
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
440 441
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
442
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
443 444
   }

445 446 447 448 449 450 451 452 453
   /* Write filter_method 64 (intrapixel differencing) only if
    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    * 2. Libpng did not write a PNG signature (this filter_method is only
    *    used in PNG datastreams that are embedded in MNG datastreams) and
    * 3. The application called png_permit_mng_features with a mask that
    *    included PNG_FLAG_MNG_FILTER_64 and
    * 4. The filter_method is 64 and
    * 5. The color_type is RGB or RGBA
    */
454 455 456
   if (
#if defined(PNG_MNG_FEATURES_SUPPORTED)
      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
457 458 459
      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
      (color_type == PNG_COLOR_TYPE_RGB || 
       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
460 461 462
      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
      filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
463 464
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
465
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
466 467
   }

468
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
469 470
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
471 472
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
473
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
474
   }
475 476 477
#else
   interlace_type=PNG_INTERLACE_NONE;
#endif
G
Guy Schalnat 已提交
478 479 480 481 482

   /* 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;
483
   png_ptr->filter_type = (png_byte)filter_type;
G
Guy Schalnat 已提交
484 485 486
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
487
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
A
Andreas Dilger 已提交
488
   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
489 490 491
   /* 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 已提交
492 493 494 495 496 497 498 499 500 501
   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 已提交
502 503

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

A
Andreas Dilger 已提交
506
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
507 508 509
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
510
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
511
   {
A
Andreas Dilger 已提交
512 513
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
514
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
515
      else
G
Guy Schalnat 已提交
516
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
517
   }
G
Guy Schalnat 已提交
518
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
519
   {
G
Guy Schalnat 已提交
520
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
521 522 523 524
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
525
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
526
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
527
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
528
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
529
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
G
Guy Schalnat 已提交
530
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
531
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
532
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
533
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
534 535
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
536 537
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
538

G
Guy Schalnat 已提交
539
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
540 541 542
}

/* write the palette.  We are careful not to trust png_color to be in the
543
 * correct order for PNG, so people can redefine it to any convenient
544 545
 * structure.
 */
546
void /* PRIVATE */
A
Andreas Dilger 已提交
547
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
548
{
549 550 551
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_PLTE;
#endif
A
Andreas Dilger 已提交
552
   png_uint_32 i;
G
Guy Schalnat 已提交
553
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
554 555
   png_byte buf[3];

A
Andreas Dilger 已提交
556
   png_debug(1, "in png_write_PLTE\n");
557
   if ((
558 559
#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
    defined (PNG_WRITE_EMPTY_PLTE_SUPPORTED)
560
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
561 562 563 564 565 566 567 568 569 570 571 572
#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 已提交
573 574
   }

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

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

/* write an IDAT chunk */
603
void /* PRIVATE */
A
Andreas Dilger 已提交
604
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
605
{
606 607 608
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
609
   png_debug(1, "in png_write_IDAT\n");
610
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
611
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
612 613 614
}

/* write an IEND chunk */
615
void /* PRIVATE */
G
Guy Schalnat 已提交
616
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
617
{
618 619 620
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
621
   png_debug(1, "in png_write_IEND\n");
622
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
A
Andreas Dilger 已提交
623
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
624 625
}

G
Guy Schalnat 已提交
626
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
627
/* write a gAMA chunk */
628
#ifdef PNG_FLOATING_POINT_SUPPORTED
629
void /* PRIVATE */
A
Andreas Dilger 已提交
630
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
631
{
632 633 634
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
635 636 637
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
638
   png_debug(1, "in png_write_gAMA\n");
639
   /* file_gamma is saved in 1/100,000ths */
640
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
641
   png_save_uint_32(buf, igamma);
642
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
643
}
G
Guy Schalnat 已提交
644
#endif
645
#ifdef PNG_FIXED_POINT_SUPPORTED
646
void /* PRIVATE */
647
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
648 649 650 651 652 653 654
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
655
   /* file_gamma is saved in 1/100,000ths */
656 657 658 659 660
   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 已提交
661

662 663
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
664
void /* PRIVATE */
665
png_write_sRGB(png_structp png_ptr, int srgb_intent)
666
{
667 668 669
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
670 671 672
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
673
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
674 675
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
676
   buf[0]=(png_byte)srgb_intent;
677
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
678 679 680
}
#endif

681 682
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
683
void /* PRIVATE */
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
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;
   }

702
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
703
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
704

705
   if (profile == NULL)
706 707 708
      profile_len = 0;

   if (profile_len)
709
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
710
          PNG_COMPRESSION_TYPE_BASE, &comp);
711 712 713 714

   /* 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);
715
   new_name[name_len+1]=0x00;
716 717 718 719 720 721 722 723 724 725 726 727
   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 */
728
void /* PRIVATE */
729
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
730 731 732 733 734 735 736 737 738
{
#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;
739
   png_sPLT_entryp ep;
740 741 742
#ifdef PNG_NO_POINTER_INDEXING
   int i;
#endif
743 744

   png_debug(1, "in png_write_sPLT\n");
745 746
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
747 748 749 750 751 752
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
753
   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
754
          (png_uint_32)(name_len + 2 + palette_size));
755
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
756
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
757 758

   /* loop through each palette entry, writing appropriately */
759
#ifndef PNG_NO_POINTER_INDEXING
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
   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);
   }
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
#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
803 804 805 806 807 808

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

G
Guy Schalnat 已提交
809
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
810
/* write the sBIT chunk */
811
void /* PRIVATE */
G
Guy Schalnat 已提交
812
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
813
{
814 815 816
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
817
   png_byte buf[4];
A
Andreas Dilger 已提交
818
   png_size_t size;
G
Guy Schalnat 已提交
819

A
Andreas Dilger 已提交
820
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
821
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
822 823
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
824
      png_byte maxbits;
G
Guy Schalnat 已提交
825

826 827
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
828 829
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
830 831 832 833 834
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
835 836 837 838 839 840 841
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
842 843 844 845 846
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
847 848 849 850 851 852
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
853 854 855 856 857
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
858 859 860
      buf[size++] = sbit->alpha;
   }

861
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
862
}
G
Guy Schalnat 已提交
863
#endif
G
Guy Schalnat 已提交
864

G
Guy Schalnat 已提交
865
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
866
/* write the cHRM chunk */
867
#ifdef PNG_FLOATING_POINT_SUPPORTED
868
void /* PRIVATE */
A
Andreas Dilger 已提交
869
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
870 871
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
872
{
873 874 875
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
876
   png_byte buf[32];
877
   png_uint_32 itemp;
G
Guy Schalnat 已提交
878

A
Andreas Dilger 已提交
879
   png_debug(1, "in png_write_cHRM\n");
880
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
881 882 883 884
   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");
885 886
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
887
#endif
G
Guy Schalnat 已提交
888 889
      return;
   }
890
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
891
   png_save_uint_32(buf, itemp);
892
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
893
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
894 895 896 897 898 899 900

   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;
   }
901
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
902
   png_save_uint_32(buf + 8, itemp);
903
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
904
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
905 906 907 908 909 910 911

   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;
   }
912
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
913
   png_save_uint_32(buf + 16, itemp);
914
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
915
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
916 917 918 919 920 921 922

   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;
   }
923
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
924
   png_save_uint_32(buf + 24, itemp);
925
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
926
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
927

928
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
929
}
G
Guy Schalnat 已提交
930
#endif
931
#ifdef PNG_FIXED_POINT_SUPPORTED
932
void /* PRIVATE */
933 934 935 936
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)
937 938 939 940 941 942 943
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
944
   /* each value is saved in 1/100,000ths */
945 946
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
947
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
948 949
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
950
#endif
951 952 953 954 955 956 957
      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)
   {
958
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
959 960 961 962 963 964 965
      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)
   {
966
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
967 968 969 970 971 972 973
      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)
   {
974
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
975 976 977 978 979 980 981 982 983
      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 已提交
984

G
Guy Schalnat 已提交
985
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
986
/* write the tRNS chunk */
987
void /* PRIVATE */
G
Guy Schalnat 已提交
988
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
989 990
   int num_trans, int color_type)
{
991 992 993
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
994 995
   png_byte buf[6];

A
Andreas Dilger 已提交
996
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
997 998
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
999
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1000 1001 1002 1003
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
1004
      /* write the chunk out as it is */
1005
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
1006 1007 1008 1009 1010
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
      png_save_uint_16(buf, tran->gray);
1011
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1012 1013 1014 1015 1016 1017 1018
   }
   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);
1019
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1020
   }
G
Guy Schalnat 已提交
1021 1022
   else
   {
1023
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
1024
   }
G
Guy Schalnat 已提交
1025
}
G
Guy Schalnat 已提交
1026
#endif
G
Guy Schalnat 已提交
1027

G
Guy Schalnat 已提交
1028
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
1029
/* write the background chunk */
1030
void /* PRIVATE */
G
Guy Schalnat 已提交
1031
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
1032
{
1033 1034 1035
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
1036 1037
   png_byte buf[6];

A
Andreas Dilger 已提交
1038
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
1039 1040
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
1041
      if (
1042 1043
#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
    defined (PNG_WRITE_EMPTY_PLTE_SUPPORTED)
1044 1045
          (png_ptr->num_palette ||
          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1046 1047
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
1048 1049 1050 1051
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
1052
      buf[0] = back->index;
1053
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
1054 1055 1056 1057 1058 1059
   }
   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);
1060
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
1061 1062
   }
   else
G
Guy Schalnat 已提交
1063
   {
G
Guy Schalnat 已提交
1064
      png_save_uint_16(buf, back->gray);
1065
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1066 1067
   }
}
G
Guy Schalnat 已提交
1068
#endif
G
Guy Schalnat 已提交
1069

G
Guy Schalnat 已提交
1070
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1071
/* write the histogram */
1072
void /* PRIVATE */
1073
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1074
{
1075 1076 1077
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1078
   int i;
G
Guy Schalnat 已提交
1079 1080
   png_byte buf[3];

A
Andreas Dilger 已提交
1081
   png_debug(1, "in png_write_hIST\n");
1082
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1083
   {
A
Andreas Dilger 已提交
1084 1085
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1086 1087 1088 1089
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1090
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1091
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1092
   {
G
Guy Schalnat 已提交
1093
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1094
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1095 1096 1097
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1098
#endif
G
Guy Schalnat 已提交
1099

1100 1101
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1102 1103 1104 1105 1106
/* 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 已提交
1107 1108 1109 1110
 *
 * 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 已提交
1111
 */
1112
png_size_t /* PRIVATE */
1113
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1114
{
A
Andreas Dilger 已提交
1115
   png_size_t key_len;
1116
   png_charp kp, dp;
A
Andreas Dilger 已提交
1117
   int kflag;
1118
   int kwarn=0;
A
Andreas Dilger 已提交
1119

A
Andreas Dilger 已提交
1120 1121 1122 1123
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1124
   {
1125
      png_warning(png_ptr, "zero length keyword");
1126
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1127
   }
A
Andreas Dilger 已提交
1128 1129 1130

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

1131
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
1132 1133 1134 1135 1136 1137
 
   if (*new_key == (png_charp)NULL)
   {
      png_warning(png_ptr, "Could not allocate new key; keyword not checked");
      return key_len;
   }
A
Andreas Dilger 已提交
1138 1139 1140

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

1147
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1148
         png_warning(png_ptr, msg);
1149
#else
1150
         png_warning(png_ptr, "invalid character in keyword");
1151
#endif
A
Andreas Dilger 已提交
1152 1153 1154 1155 1156 1157
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1158
   }
A
Andreas Dilger 已提交
1159
   *dp = '\0';
A
Andreas Dilger 已提交
1160

A
Andreas Dilger 已提交
1161 1162 1163
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1164
   {
1165
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1166 1167 1168 1169 1170 1171

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1172 1173 1174
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1175 1176
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1177
   {
1178
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1179 1180 1181 1182 1183 1184

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

A
Andreas Dilger 已提交
1187 1188 1189 1190
   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 已提交
1191
   {
A
Andreas Dilger 已提交
1192
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1193
      {
A
Andreas Dilger 已提交
1194 1195
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1196
      }
A
Andreas Dilger 已提交
1197
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1198 1199
      {
         key_len--;
1200
         kwarn=1;
A
Andreas Dilger 已提交
1201 1202 1203
      }
      else
      {
A
Andreas Dilger 已提交
1204 1205
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1206 1207
      }
   }
A
Andreas Dilger 已提交
1208
   *dp = '\0';
1209 1210
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1211 1212

   if (key_len == 0)
A
Andreas Dilger 已提交
1213
   {
1214 1215
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1216
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1217 1218 1219 1220
   }

   if (key_len > 79)
   {
1221
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1222 1223 1224
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1225

1226
   return (key_len);
A
Andreas Dilger 已提交
1227 1228 1229
}
#endif

G
Guy Schalnat 已提交
1230
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1231
/* write a tEXt chunk */
1232
void /* PRIVATE */
G
Guy Schalnat 已提交
1233
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1234
   png_size_t text_len)
G
Guy Schalnat 已提交
1235
{
1236 1237 1238
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1239
   png_size_t key_len;
1240
   png_charp new_key;
A
Andreas Dilger 已提交
1241 1242 1243 1244

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

A
Andreas Dilger 已提交
1249
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1250
      text_len = 0;
1251 1252
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1253 1254

   /* make sure we include the 0 after the key */
1255
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1256 1257 1258 1259
   /*
    * 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.
1260
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1261
    */
1262
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1263
   if (text_len)
A
Andreas Dilger 已提交
1264
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1265

G
Guy Schalnat 已提交
1266
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1267
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1268
}
G
Guy Schalnat 已提交
1269
#endif
G
Guy Schalnat 已提交
1270

G
Guy Schalnat 已提交
1271
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1272
/* write a compressed text chunk */
1273
void /* PRIVATE */
G
Guy Schalnat 已提交
1274
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1275
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1276
{
1277 1278 1279
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1280
   png_size_t key_len;
G
Guy Schalnat 已提交
1281
   char buf[1];
1282
   png_charp new_key;
1283
   compression_state comp;
G
Guy Schalnat 已提交
1284

A
Andreas Dilger 已提交
1285 1286 1287 1288
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1293 1294 1295 1296 1297 1298 1299
   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;
   }

1300 1301
   text_len = png_strlen(text);

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

1304
   /* compute the compressed data; do it now for the length */
1305 1306
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1307

1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
   /* 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 已提交
1318

1319 1320 1321 1322
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1323

1324 1325
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1326
void /* PRIVATE */
1327
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1328
    png_charp lang, png_charp lang_key, png_charp text)
1329 1330 1331 1332
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1333
   png_size_t lang_len, key_len, lang_key_len, text_len;
1334 1335 1336
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1337

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

1340
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1341
   {
1342
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1343 1344
      return;
   }
1345 1346
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang,
      &new_lang))==0)
1347
   {
1348
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1349 1350
      return;
   }
1351 1352
   lang_key_len = png_strlen(lang_key);
   text_len = png_strlen(text);
G
Guy Schalnat 已提交
1353

1354 1355
   if (text == NULL || *text == '\0')
      text_len = 0;
G
Guy Schalnat 已提交
1356

1357
   /* compute the compressed data; do it now for the length */
1358 1359
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1360

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

1364 1365 1366 1367 1368 1369 1370
   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 已提交
1371

1372 1373 1374 1375 1376 1377 1378
   /*
    * 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);
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389

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

1390
   png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
1391
   png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
1392
   png_write_chunk_data(png_ptr, '\0', 1);
G
Guy Schalnat 已提交
1393

1394
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1395 1396

   png_write_chunk_end(png_ptr);
1397 1398
   png_free(png_ptr, new_key);
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1399
}
G
Guy Schalnat 已提交
1400
#endif
G
Guy Schalnat 已提交
1401

A
Andreas Dilger 已提交
1402 1403
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1404
void /* PRIVATE */
A
Andreas Dilger 已提交
1405 1406
png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
   png_uint_32 y_offset,
G
Guy Schalnat 已提交
1407 1408
   int unit_type)
{
1409 1410 1411
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1412 1413
   png_byte buf[9];

A
Andreas Dilger 已提交
1414 1415 1416
   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 已提交
1417

A
Andreas Dilger 已提交
1418 1419
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1420
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1421

1422
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1423
}
G
Guy Schalnat 已提交
1424
#endif
G
Guy Schalnat 已提交
1425

A
Andreas Dilger 已提交
1426
#if defined(PNG_WRITE_pCAL_SUPPORTED)
1427
/* write the pCAL chunk (described in the PNG extensions document) */
1428
void /* PRIVATE */
A
Andreas Dilger 已提交
1429 1430 1431
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)
{
1432 1433 1434
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1435
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1436 1437
   png_uint_32p params_len;
   png_byte buf[10];
1438
   png_charp new_purpose;
A
Andreas Dilger 已提交
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
   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;

1451 1452
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1453

1454 1455 1456 1457 1458 1459
   if (params_len == (png_uint_32p)NULL)
   {
      png_warning (png_ptr, "Could not allocate params for pCAL");
      return;
   }

A
Andreas Dilger 已提交
1460 1461 1462 1463 1464
   /* 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);
1465
      png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
A
Andreas Dilger 已提交
1466 1467 1468 1469
      total_len += (png_size_t)params_len[i];
   }

   png_debug1(3, "pCAL total length = %d\n", total_len);
1470
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1471
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
   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]);
   }

1487
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1488 1489 1490 1491
   png_write_chunk_end(png_ptr);
}
#endif

1492 1493
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1494
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1495
void /* PRIVATE */
1496
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1497 1498 1499 1500 1501 1502 1503 1504 1505
{
#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");

1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
#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
1516 1517
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1518
#endif
1519
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1520 1521 1522

   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);
1523
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1524 1525
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1526 1527 1528

   png_write_chunk_end(png_ptr);
}
1529 1530
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1531
void /* PRIVATE */
1532
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1533 1534 1535 1536 1537 1538 1539 1540
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1541
   png_debug(1, "in png_write_sCAL_s\n");
1542

1543 1544
   png_strcpy(wbuf,(const char *)width);
   png_strcpy(hbuf,(const char *)height);
1545
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1546 1547 1548

   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);
1549
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1550 1551
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1552 1553 1554 1555

   png_write_chunk_end(png_ptr);
}
#endif
1556 1557
#endif
#endif
1558

A
Andreas Dilger 已提交
1559 1560
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1561
void /* PRIVATE */
A
Andreas Dilger 已提交
1562 1563
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1564 1565
   int unit_type)
{
1566 1567 1568
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1569 1570
   png_byte buf[9];

A
Andreas Dilger 已提交
1571 1572 1573
   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 已提交
1574

A
Andreas Dilger 已提交
1575 1576
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1577
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1578

1579
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1580
}
G
Guy Schalnat 已提交
1581
#endif
G
Guy Schalnat 已提交
1582

G
Guy Schalnat 已提交
1583
#if defined(PNG_WRITE_tIME_SUPPORTED)
1584 1585 1586
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1587
void /* PRIVATE */
G
Guy Schalnat 已提交
1588
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1589
{
1590 1591 1592
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1593 1594
   png_byte buf[7];

A
Andreas Dilger 已提交
1595
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1596 1597 1598 1599 1600 1601 1602 1603
   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 已提交
1604 1605 1606 1607 1608 1609 1610
   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;

1611
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1612
}
G
Guy Schalnat 已提交
1613
#endif
G
Guy Schalnat 已提交
1614 1615

/* initializes the row writing capability of libpng */
1616
void /* PRIVATE */
G
Guy Schalnat 已提交
1617
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1618
{
1619
#ifdef PNG_USE_LOCAL_ARRAYS
1620
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1621

1622 1623
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1624

1625 1626
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1627

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

1631 1632
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1633
#endif
1634

A
Andreas Dilger 已提交
1635 1636 1637 1638 1639 1640
   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 已提交
1641
   /* set up row buffer */
1642
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
1643 1644
   if (png_ptr->row_buf == (png_bytep)NULL)
      png_error(png_ptr, "Could not allocate row buffer");
A
Andreas Dilger 已提交
1645
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1646 1647 1648

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1649
   {
A
Andreas Dilger 已提交
1650
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1651
         (png_ptr->rowbytes + 1));
1652 1653
      if (png_ptr->sub_row == (png_bytep)NULL)
         png_error(png_ptr, "Could not allocate sub row buffer");
A
Andreas Dilger 已提交
1654
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1655 1656
   }

A
Andreas Dilger 已提交
1657
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1658 1659 1660
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1661
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1662
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1663 1664 1665

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1666
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1667
            (png_ptr->rowbytes + 1));
1668 1669
         if (png_ptr->up_row == (png_bytep)NULL)
            png_error(png_ptr, "Could not allocate up row buffer");
A
Andreas Dilger 已提交
1670
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1671 1672 1673 1674
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1675 1676
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
1677 1678
         if (png_ptr->avg_row == (png_bytep)NULL)
            png_error(png_ptr, "Could not allocate avg row buffer");
A
Andreas Dilger 已提交
1679
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1680 1681 1682 1683
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1684
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1685
            (png_ptr->rowbytes + 1));
1686 1687
         if (png_ptr->paeth_row == (png_bytep)NULL)
            png_error(png_ptr, "Could not allocate paeth row buffer");
A
Andreas Dilger 已提交
1688
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1689
      }
G
Guy Schalnat 已提交
1690 1691
   }

1692
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1693
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1694
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1695 1696 1697 1698 1699
   {
      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 已提交
1700 1701
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1702 1703 1704 1705 1706 1707 1708 1709
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1710
#endif
G
Guy Schalnat 已提交
1711
   {
G
Guy Schalnat 已提交
1712 1713 1714
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1715 1716
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1717 1718
}

A
Andreas Dilger 已提交
1719
/* Internal use only.  Called when finished processing a row of data. */
1720
void /* PRIVATE */
G
Guy Schalnat 已提交
1721
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1722
{
1723
#ifdef PNG_USE_LOCAL_ARRAYS
1724
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1725

1726 1727
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1728

1729 1730
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1731

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

1735 1736
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1737
#endif
1738

G
Guy Schalnat 已提交
1739 1740
   int ret;

A
Andreas Dilger 已提交
1741
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1742 1743
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1744

G
Guy Schalnat 已提交
1745
   /* see if we are done */
G
Guy Schalnat 已提交
1746
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1747
      return;
G
Guy Schalnat 已提交
1748

1749
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
   /* 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 已提交
1766
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1767 1768 1769 1770 1771 1772 1773
               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 已提交
1774 1775
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1776 1777 1778 1779
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1780
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1781
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1782
      {
A
Andreas Dilger 已提交
1783
         if (png_ptr->prev_row != NULL)
1784
            png_memset(png_ptr->prev_row, 0,
A
Andreas Dilger 已提交
1785
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1786 1787
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1788
         return;
G
Guy Schalnat 已提交
1789
      }
G
Guy Schalnat 已提交
1790
   }
1791
#endif
G
Guy Schalnat 已提交
1792 1793 1794 1795 1796 1797

   /* 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 已提交
1798
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1799
      /* check for an error */
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810
      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 已提交
1811
      {
A
Andreas Dilger 已提交
1812
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1813
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1814
         else
G
Guy Schalnat 已提交
1815
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1816 1817 1818 1819
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1820
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1821 1822
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1823
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1824 1825
   }

A
Andreas Dilger 已提交
1826
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1827 1828
}

G
Guy Schalnat 已提交
1829
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1830 1831 1832 1833 1834 1835 1836
/* 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.
 */
1837
void /* PRIVATE */
G
Guy Schalnat 已提交
1838
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1839
{
1840
#ifdef PNG_USE_LOCAL_ARRAYS
1841
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1842

1843 1844
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1845

1846 1847
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1848
#endif
1849

A
Andreas Dilger 已提交
1850
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1851
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1852 1853 1854 1855 1856
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1857
   {
1858
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1859
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1860
      {
G
Guy Schalnat 已提交
1861 1862
         case 1:
         {
G
Guy Schalnat 已提交
1863 1864
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1865 1866 1867
            int shift;
            int d;
            int value;
1868 1869
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1870 1871 1872 1873

            dp = row;
            d = 0;
            shift = 7;
1874
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1875 1876 1877
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1878
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1879 1880 1881 1882 1883
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1884
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1885 1886 1887 1888 1889 1890 1891
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1892
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1893 1894 1895
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1896
         {
G
Guy Schalnat 已提交
1897 1898
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1899 1900 1901
            int shift;
            int d;
            int value;
1902 1903
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1904 1905 1906 1907

            dp = row;
            shift = 6;
            d = 0;
1908
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1909 1910 1911
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1912
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1913 1914 1915 1916 1917
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1918
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1919 1920 1921 1922 1923 1924
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1925
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1926 1927 1928 1929
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1930 1931
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1932
            int shift;
G
Guy Schalnat 已提交
1933 1934
            int d;
            int value;
1935 1936
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1937 1938 1939 1940

            dp = row;
            shift = 4;
            d = 0;
1941
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1942 1943 1944
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
1945
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
1946 1947 1948 1949
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1950 1951
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1952 1953 1954 1955 1956 1957
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1958
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1959 1960 1961 1962
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
1963 1964
            png_bytep sp;
            png_bytep dp;
1965 1966
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
1967
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
1968

G
Guy Schalnat 已提交
1969
            /* start at the beginning */
G
Guy Schalnat 已提交
1970 1971 1972 1973 1974
            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 */
1975
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1976 1977 1978
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
1979
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
1980 1981
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
1982
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
1983 1984 1985
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
1986
            break;
G
Guy Schalnat 已提交
1987 1988 1989 1990 1991 1992 1993
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
1994 1995
         row_info->rowbytes = ((row_info->width *
            row_info->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
1996 1997
   }
}
G
Guy Schalnat 已提交
1998
#endif
G
Guy Schalnat 已提交
1999

A
Andreas Dilger 已提交
2000 2001
/* 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
2002 2003
 * chosen filter.
 */
2004
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
A
Andreas Dilger 已提交
2005
#define PNG_HISHIFT 10
2006 2007
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2008
void /* PRIVATE */
G
Guy Schalnat 已提交
2009
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2010
{
G
Guy Schalnat 已提交
2011
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2012
   png_uint_32 mins, bpp;
2013
   png_byte filter_to_do = png_ptr->do_filter;
2014 2015 2016 2017
   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 已提交
2018

A
Andreas Dilger 已提交
2019
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
2020 2021
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
2022 2023 2024

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
2025 2026 2027 2028
   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
2029
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2030
    * as the "minimum sum of absolute differences" heuristic.  Other
2031
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2032
    * (experimental and can in theory improve compression), and the "zlib
2033 2034 2035
    * 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 已提交
2036
    * computationally expensive).
2037 2038 2039 2040 2041 2042 2043 2044 2045
    *
    * 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 已提交
2046
    */
G
Guy Schalnat 已提交
2047

2048

G
Guy Schalnat 已提交
2049
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2050 2051
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2052
   if ((filter_to_do & PNG_FILTER_NONE) &&
2053
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2054
   {
G
Guy Schalnat 已提交
2055 2056
      png_bytep rp;
      png_uint_32 sum = 0;
2057
      png_uint_32 i;
A
Andreas Dilger 已提交
2058
      int v;
G
Guy Schalnat 已提交
2059

2060
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2061 2062 2063 2064
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2065 2066 2067 2068 2069

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2070
         int j;
A
Andreas Dilger 已提交
2071 2072 2073 2074
         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 */
2075
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2076
         {
2077
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2078
            {
2079
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2080
                  PNG_WEIGHT_SHIFT;
2081
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
                  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 已提交
2101 2102
      mins = sum;
   }
G
Guy Schalnat 已提交
2103

G
Guy Schalnat 已提交
2104
   /* sub filter */
2105 2106 2107 2108
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2109
      png_uint_32 i;
2110 2111 2112 2113 2114
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2115
      for (lp = row_buf + 1; i < row_bytes;
2116 2117 2118 2119 2120 2121 2122 2123
         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 已提交
2124 2125
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2126
      png_uint_32 sum = 0, lmins = mins;
2127
      png_uint_32 i;
A
Andreas Dilger 已提交
2128 2129 2130
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2131
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2132 2133 2134 2135 2136
       * 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)
      {
2137
         int j;
A
Andreas Dilger 已提交
2138 2139 2140 2141
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2142
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2143
         {
2144
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2145
            {
2146
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2147
                  PNG_WEIGHT_SHIFT;
2148
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
                  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 已提交
2164

G
Guy Schalnat 已提交
2165 2166 2167 2168
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2169

G
Guy Schalnat 已提交
2170 2171
         sum += (v < 128) ? v : 256 - v;
      }
2172 2173
      for (lp = row_buf + 1; i < row_info->rowbytes;
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2174 2175 2176 2177
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2178 2179 2180 2181 2182 2183 2184 2185

         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)
      {
2186
         int j;
A
Andreas Dilger 已提交
2187 2188 2189 2190
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2214 2215 2216 2217 2218
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2219 2220
   }

G
Guy Schalnat 已提交
2221
   /* up filter */
2222 2223 2224
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2225
      png_uint_32 i;
2226 2227

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2228
           pp = prev_row + 1; i < row_bytes;
2229 2230 2231 2232 2233 2234 2235 2236
           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 已提交
2237 2238
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2239
      png_uint_32 sum = 0, lmins = mins;
2240
      png_uint_32 i;
A
Andreas Dilger 已提交
2241 2242
      int v;

2243

A
Andreas Dilger 已提交
2244 2245 2246
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2247
         int j;
A
Andreas Dilger 已提交
2248 2249 2250 2251
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2275
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2276
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2277
      {
2278
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2279 2280

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2281 2282 2283

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2284
      }
A
Andreas Dilger 已提交
2285 2286 2287 2288

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2289
         int j;
A
Andreas Dilger 已提交
2290 2291 2292 2293
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2294
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2295
         {
2296
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2297
            {
2298
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2299
                  PNG_WEIGHT_SHIFT;
2300
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316
                  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 已提交
2317 2318 2319 2320 2321 2322 2323 2324
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2325 2326 2327
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2328
      png_uint_32 i;
2329
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2330
           pp = prev_row + 1; i < bpp; i++)
2331
      {
2332
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2333
      }
2334
      for (lp = row_buf + 1; i < row_bytes; i++)
2335
      {
2336 2337
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2338 2339 2340 2341 2342
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2343
   {
G
Guy Schalnat 已提交
2344
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2345
      png_uint_32 sum = 0, lmins = mins;
2346
      png_uint_32 i;
A
Andreas Dilger 已提交
2347 2348 2349 2350 2351
      int v;

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

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

G
Guy Schalnat 已提交
2380
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2381
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2382
      {
2383
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2384

G
Guy Schalnat 已提交
2385 2386
         sum += (v < 128) ? v : 256 - v;
      }
2387
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2388
      {
2389
         v = *dp++ =
2390
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2391

G
Guy Schalnat 已提交
2392
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2393 2394 2395

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2396
      }
A
Andreas Dilger 已提交
2397 2398 2399 2400

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

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

A
Andreas Dilger 已提交
2436
   /* Paeth filter */
2437 2438 2439
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2440
      png_uint_32 i;
2441
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2442
           pp = prev_row + 1; i < bpp; i++)
2443
      {
2444
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2445 2446
      }

2447
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2448 2449 2450
      {
         int a, b, c, pa, pb, pc, p;

2451 2452 2453
         b = *pp++;
         c = *cp++;
         a = *lp++;
2454

2455 2456
         p = b - c;
         pc = a - c;
2457 2458

#ifdef PNG_USE_ABS
2459 2460 2461
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2462
#else
2463 2464 2465
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2466 2467 2468 2469
#endif

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

2470
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2471 2472 2473 2474 2475
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2476 2477
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2478
      png_uint_32 sum = 0, lmins = mins;
2479
      png_uint_32 i;
A
Andreas Dilger 已提交
2480 2481 2482 2483 2484
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2485
         int j;
A
Andreas Dilger 已提交
2486 2487 2488 2489
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2490
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2491
         {
2492
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2493
            {
2494
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2495
                  PNG_WEIGHT_SHIFT;
2496
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
                  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 已提交
2512

G
Guy Schalnat 已提交
2513
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2514
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2515
      {
2516
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2517

G
Guy Schalnat 已提交
2518 2519
         sum += (v < 128) ? v : 256 - v;
      }
2520

2521
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2522 2523
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2524

2525 2526 2527
         b = *pp++;
         c = *cp++;
         a = *lp++;
2528 2529

#ifndef PNG_SLOW_PAETH
2530 2531
         p = b - c;
         pc = a - c;
2532
#ifdef PNG_USE_ABS
2533 2534 2535
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2536
#else
2537 2538 2539
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2540 2541 2542
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2543
         p = a + b - c;
2544 2545 2546
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2547 2548 2549 2550 2551 2552
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2553
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2554

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

G
Guy Schalnat 已提交
2557
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2558 2559 2560

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2561
      }
A
Andreas Dilger 已提交
2562 2563 2564 2565

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2566
         int j;
A
Andreas Dilger 已提交
2567 2568 2569 2570
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2571
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2572
         {
2573
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2574
            {
2575
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2576
                  PNG_WEIGHT_SHIFT;
2577
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593
                  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 已提交
2594 2595 2596 2597
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2598 2599
   }

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

G
Guy Schalnat 已提交
2602
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2603 2604 2605 2606 2607

#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)
   {
2608 2609
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2610
      {
2611
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2612
      }
2613
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2614 2615
   }
#endif
G
Guy Schalnat 已提交
2616
}
G
Guy Schalnat 已提交
2617

G
Guy Schalnat 已提交
2618

A
Andreas Dilger 已提交
2619
/* Do the actual writing of a previously filtered row. */
2620
void /* PRIVATE */
G
Guy Schalnat 已提交
2621 2622
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2623 2624
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2625
   /* set up the zlib input buffer */
2626

A
Andreas Dilger 已提交
2627 2628
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2629 2630
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2631
   {
G
Guy Schalnat 已提交
2632
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2633

G
Guy Schalnat 已提交
2634
      /* compress the data */
A
Andreas Dilger 已提交
2635
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2636 2637 2638
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2639
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2640
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2641 2642 2643
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2644

G
Guy Schalnat 已提交
2645
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2646
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2647 2648 2649
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2650 2651
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2652 2653
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2654
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2655

G
Guy Schalnat 已提交
2656
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2657
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2658 2659 2660 2661 2662 2663 2664 2665
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2666 2667
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2668

G
Guy Schalnat 已提交
2669 2670 2671 2672 2673 2674 2675
#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 已提交
2676
   }
2677
#endif
G
Guy Schalnat 已提交
2678
}
2679
#endif /* PNG_WRITE_SUPPORTED */