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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
178
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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
               png_memcpy(comp->output_ptr, old_ptr, old_max
                  * sizeof (png_charp));
240 241 242 243 244 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)));
         }

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

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

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

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

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

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

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

   /* handle the no-compression case */
   if (comp->input)
   {
335 336
       png_write_chunk_data(png_ptr, (png_bytep)comp->input,
                            (png_size_t)comp->input_len);
337 338 339 340 341 342
       return;
   }

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

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

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

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

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

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

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

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

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

G
Guy Schalnat 已提交
523
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
524 525 526
}

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

A
Andreas Dilger 已提交
540
   png_debug(1, "in png_write_PLTE\n");
541
   if ((
542
#if defined(PNG_MNG_FEATURES_SUPPORTED)
543
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
544 545
#endif
        num_pal == 0) || num_pal > 256)
546 547
   {
     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
548
     {
549 550 551 552 553 554 555 556 557 558 559 560 561 562
        png_error(png_ptr, "Invalid number of colors in palette");
     }
     else
     {
        png_warning(png_ptr, "Invalid number of colors in palette");
        return;
     }
   }

   if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
   {
      png_warning(png_ptr,
        "Ignoring request to write a PLTE chunk in grayscale PNG");
      return;
G
Guy Schalnat 已提交
563 564
   }

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

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

/* write an IDAT chunk */
593
void /* PRIVATE */
A
Andreas Dilger 已提交
594
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
595
{
596 597 598
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
599
   png_debug(1, "in png_write_IDAT\n");
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639

   /* Optimize the CMF field in the zlib stream. */
   /* This hack of the zlib stream is compliant to the stream specification. */
   if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
       png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
   {
      unsigned int z_cmf = data[0];  /* zlib compression method and flags */
      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
      {
         /* Avoid memory underflows and multiplication overflows. */
         /* The conditions below are practically always satisfied;
            however, they still must be checked. */
         if (length >= 2 &&
             png_ptr->height < 16384 && png_ptr->width < 16384)
         {
            png_uint_32 uncompressed_idat_size = png_ptr->height *
               ((png_ptr->width *
                  png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
            unsigned int z_cinfo = z_cmf >> 4;
            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
            while (uncompressed_idat_size <= half_z_window_size &&
                   half_z_window_size >= 256)
            {
               z_cinfo--;
               half_z_window_size >>= 1;
            }
            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
            if (data[0] != (png_byte)z_cmf)
            {
               data[0] = (png_byte)z_cmf;
               data[1] &= 0xe0;
               data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
            }
         }
      }
      else
         png_error(png_ptr,
            "Invalid zlib compression method or flags in IDAT");
   }

640
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
641
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
642 643 644
}

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

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

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

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

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

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

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

733
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
734
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
735

736
   if (profile == NULL)
737 738 739
      profile_len = 0;

   if (profile_len)
740
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
741
          PNG_COMPRESSION_TYPE_BASE, &comp);
742 743 744 745

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

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

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

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

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

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

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

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

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

892
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
893
}
G
Guy Schalnat 已提交
894
#endif
G
Guy Schalnat 已提交
895

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
1174 1175 1176 1177
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1178
   {
1179
      png_warning(png_ptr, "zero length keyword");
1180
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1181
   }
A
Andreas Dilger 已提交
1182 1183 1184

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

1185
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
1186

A
Andreas Dilger 已提交
1187 1188
   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
1189
   {
1190
      if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
A
Andreas Dilger 已提交
1191
      {
1192
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
A
Andreas Dilger 已提交
1193
         char msg[40];
A
Andreas Dilger 已提交
1194

1195
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1196
         png_warning(png_ptr, msg);
1197
#else
1198
         png_warning(png_ptr, "invalid character in keyword");
1199
#endif
A
Andreas Dilger 已提交
1200 1201 1202 1203 1204 1205
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1206
   }
A
Andreas Dilger 已提交
1207
   *dp = '\0';
A
Andreas Dilger 已提交
1208

A
Andreas Dilger 已提交
1209 1210 1211
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1212
   {
1213
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1214 1215 1216 1217 1218 1219

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1220 1221 1222
   }

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

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

A
Andreas Dilger 已提交
1235 1236 1237 1238
   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 已提交
1239
   {
A
Andreas Dilger 已提交
1240
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1241
      {
A
Andreas Dilger 已提交
1242 1243
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1244
      }
A
Andreas Dilger 已提交
1245
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1246 1247
      {
         key_len--;
1248
         kwarn=1;
A
Andreas Dilger 已提交
1249 1250 1251
      }
      else
      {
A
Andreas Dilger 已提交
1252 1253
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1254 1255
      }
   }
A
Andreas Dilger 已提交
1256
   *dp = '\0';
1257 1258
   if(kwarn)
      png_warning(png_ptr, "extra interior spaces removed from keyword");
A
Andreas Dilger 已提交
1259 1260

   if (key_len == 0)
A
Andreas Dilger 已提交
1261
   {
1262 1263
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1264
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1265 1266 1267 1268
   }

   if (key_len > 79)
   {
1269
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1270 1271 1272
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1273

1274
   return (key_len);
A
Andreas Dilger 已提交
1275 1276 1277
}
#endif

G
Guy Schalnat 已提交
1278
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1279
/* write a tEXt chunk */
1280
void /* PRIVATE */
G
Guy Schalnat 已提交
1281
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1282
   png_size_t text_len)
G
Guy Schalnat 已提交
1283
{
1284 1285 1286
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1287
   png_size_t key_len;
1288
   png_charp new_key;
A
Andreas Dilger 已提交
1289 1290 1291 1292

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

A
Andreas Dilger 已提交
1297
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1298
      text_len = 0;
1299 1300
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1301 1302

   /* make sure we include the 0 after the key */
1303
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1304 1305 1306 1307
   /*
    * 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.
1308
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1309
    */
1310
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1311
   if (text_len)
A
Andreas Dilger 已提交
1312
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1313

G
Guy Schalnat 已提交
1314
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1315
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1316
}
G
Guy Schalnat 已提交
1317
#endif
G
Guy Schalnat 已提交
1318

G
Guy Schalnat 已提交
1319
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1320
/* write a compressed text chunk */
1321
void /* PRIVATE */
G
Guy Schalnat 已提交
1322
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1323
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1324
{
1325 1326 1327
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1328
   png_size_t key_len;
G
Guy Schalnat 已提交
1329
   char buf[1];
1330
   png_charp new_key;
1331
   compression_state comp;
G
Guy Schalnat 已提交
1332

A
Andreas Dilger 已提交
1333 1334 1335 1336
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1341 1342 1343 1344 1345 1346 1347
   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;
   }

1348 1349
   text_len = png_strlen(text);

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

1352
   /* compute the compressed data; do it now for the length */
1353 1354
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1355

1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
   /* 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 已提交
1366

1367 1368 1369 1370
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1371

1372 1373
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
1374
void /* PRIVATE */
1375
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1376
    png_charp lang, png_charp lang_key, png_charp text)
1377 1378 1379 1380
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1381
   png_size_t lang_len, key_len, lang_key_len, text_len;
1382 1383 1384
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1385

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

1388
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1389
   {
1390
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1391 1392
      return;
   }
1393
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1394
   {
1395
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1396
      new_lang = NULL;
1397
      lang_len = 0;
1398
   }
G
Guy Schalnat 已提交
1399

1400 1401 1402 1403 1404 1405
   if (lang_key == NULL)
     lang_key_len = 0;
   else
     lang_key_len = png_strlen(lang_key);

   if (text == NULL)
1406
      text_len = 0;
1407 1408
   else
     text_len = png_strlen(text);
G
Guy Schalnat 已提交
1409

1410
   /* compute the compressed data; do it now for the length */
1411 1412
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1413

1414

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

1418 1419 1420 1421 1422 1423 1424
   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 已提交
1425

1426 1427 1428 1429 1430 1431 1432
   /*
    * 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);
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443

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

1444 1445 1446
   cbuf[0] = 0;
   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
1447
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1448 1449

   png_write_chunk_end(png_ptr);
1450
   png_free(png_ptr, new_key);
1451 1452
   if (new_lang)
     png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1453
}
G
Guy Schalnat 已提交
1454
#endif
G
Guy Schalnat 已提交
1455

A
Andreas Dilger 已提交
1456 1457
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
1458
void /* PRIVATE */
1459
png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
G
Guy Schalnat 已提交
1460 1461
   int unit_type)
{
1462 1463 1464
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1465 1466
   png_byte buf[9];

A
Andreas Dilger 已提交
1467 1468 1469
   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 已提交
1470

1471 1472
   png_save_int_32(buf, x_offset);
   png_save_int_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1473
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1474

1475
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1476
}
G
Guy Schalnat 已提交
1477
#endif
G
Guy Schalnat 已提交
1478

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

1504 1505
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1506 1507 1508 1509 1510 1511

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

1516
   png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1517
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1518
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533
   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]);
   }

1534
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1535 1536 1537 1538
   png_write_chunk_end(png_ptr);
}
#endif

1539 1540
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1541
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1542
void /* PRIVATE */
1543
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1544 1545 1546 1547 1548 1549 1550 1551 1552
{
#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");

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
#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
1563 1564
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1565
#endif
1566
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1567

1568
   png_debug1(3, "sCAL total length = %d\n", (int)total_len);
1569
   png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1570
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1571 1572
   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));
1573 1574 1575

   png_write_chunk_end(png_ptr);
}
1576 1577
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1578
void /* PRIVATE */
1579
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1580 1581 1582 1583 1584 1585 1586 1587
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1588
   png_debug(1, "in png_write_sCAL_s\n");
1589

1590 1591
   png_strcpy(wbuf,(const char *)width);
   png_strcpy(hbuf,(const char *)height);
1592
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1593 1594 1595

   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);
1596
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1597 1598
   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));
1599 1600 1601 1602

   png_write_chunk_end(png_ptr);
}
#endif
1603 1604
#endif
#endif
1605

A
Andreas Dilger 已提交
1606 1607
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
1608
void /* PRIVATE */
A
Andreas Dilger 已提交
1609 1610
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1611 1612
   int unit_type)
{
1613 1614 1615
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1616 1617
   png_byte buf[9];

A
Andreas Dilger 已提交
1618 1619 1620
   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 已提交
1621

A
Andreas Dilger 已提交
1622 1623
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1624
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1625

1626
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1627
}
G
Guy Schalnat 已提交
1628
#endif
G
Guy Schalnat 已提交
1629

G
Guy Schalnat 已提交
1630
#if defined(PNG_WRITE_tIME_SUPPORTED)
1631 1632 1633
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
1634
void /* PRIVATE */
G
Guy Schalnat 已提交
1635
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1636
{
1637 1638 1639
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1640 1641
   png_byte buf[7];

A
Andreas Dilger 已提交
1642
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1643 1644 1645 1646 1647 1648 1649 1650
   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 已提交
1651 1652 1653 1654 1655 1656 1657
   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;

1658
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1659
}
G
Guy Schalnat 已提交
1660
#endif
G
Guy Schalnat 已提交
1661 1662

/* initializes the row writing capability of libpng */
1663
void /* PRIVATE */
G
Guy Schalnat 已提交
1664
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1665
{
1666
#ifdef PNG_USE_LOCAL_ARRAYS
1667
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1668

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

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

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

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

A
Andreas Dilger 已提交
1682 1683 1684 1685 1686 1687
   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 已提交
1688
   /* set up row buffer */
1689
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1690
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1691 1692 1693

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1694
   {
A
Andreas Dilger 已提交
1695
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1696
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1697
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1698 1699
   }

A
Andreas Dilger 已提交
1700
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1701 1702 1703
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1704
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1705
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1706 1707 1708

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1709
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1710
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1711
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1712 1713 1714 1715
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1716 1717
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1718
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1719 1720 1721 1722
      }

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

1729
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1730
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1731
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1732 1733 1734 1735 1736
   {
      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 已提交
1737 1738
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1739 1740 1741 1742 1743 1744 1745 1746
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1747
#endif
G
Guy Schalnat 已提交
1748
   {
G
Guy Schalnat 已提交
1749 1750 1751
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1752 1753
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1754 1755
}

A
Andreas Dilger 已提交
1756
/* Internal use only.  Called when finished processing a row of data. */
1757
void /* PRIVATE */
G
Guy Schalnat 已提交
1758
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1759
{
1760
#ifdef PNG_USE_LOCAL_ARRAYS
1761
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1762

1763 1764
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1765

1766 1767
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1768

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

1772 1773
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1774
#endif
1775

G
Guy Schalnat 已提交
1776 1777
   int ret;

A
Andreas Dilger 已提交
1778
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1779 1780
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1781

G
Guy Schalnat 已提交
1782
   /* see if we are done */
G
Guy Schalnat 已提交
1783
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1784
      return;
G
Guy Schalnat 已提交
1785

1786
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
   /* 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 已提交
1803
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1804 1805 1806 1807 1808 1809 1810
               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 已提交
1811 1812
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1813 1814 1815 1816
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1817
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1818
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1819
      {
A
Andreas Dilger 已提交
1820
         if (png_ptr->prev_row != NULL)
1821
            png_memset(png_ptr->prev_row, 0,
A
Andreas Dilger 已提交
1822
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1823 1824
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1825
         return;
G
Guy Schalnat 已提交
1826
      }
G
Guy Schalnat 已提交
1827
   }
1828
#endif
G
Guy Schalnat 已提交
1829 1830 1831 1832 1833 1834

   /* 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 已提交
1835
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1836
      /* check for an error */
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
      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 已提交
1848
      {
A
Andreas Dilger 已提交
1849
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1850
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1851
         else
G
Guy Schalnat 已提交
1852
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1853 1854 1855 1856
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1857
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1858 1859
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1860
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1861 1862
   }

A
Andreas Dilger 已提交
1863
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1864 1865
}

G
Guy Schalnat 已提交
1866
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1867 1868 1869 1870 1871 1872 1873
/* 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.
 */
1874
void /* PRIVATE */
G
Guy Schalnat 已提交
1875
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1876
{
1877
#ifdef PNG_USE_LOCAL_ARRAYS
1878
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1879

1880 1881
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1882

1883 1884
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1885
#endif
1886

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

            dp = row;
            d = 0;
            shift = 7;
1911
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1912 1913 1914
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1915
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1916 1917 1918 1919 1920
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1921
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1922 1923 1924 1925 1926 1927 1928
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1929
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1930 1931 1932
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1933
         {
G
Guy Schalnat 已提交
1934 1935
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1936 1937 1938
            int shift;
            int d;
            int value;
1939 1940
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1941 1942 1943 1944

            dp = row;
            shift = 6;
            d = 0;
1945
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1946 1947 1948
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1949
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1950 1951 1952 1953 1954
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1955
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1956 1957 1958 1959 1960 1961
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1962
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1963 1964 1965 1966
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1967 1968
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1969
            int shift;
G
Guy Schalnat 已提交
1970 1971
            int d;
            int value;
1972 1973
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1974 1975 1976 1977

            dp = row;
            shift = 4;
            d = 0;
1978
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1979 1980 1981
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
1982
               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
G
Guy Schalnat 已提交
1983 1984 1985 1986
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1987 1988
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1989 1990 1991 1992 1993 1994
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1995
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1996 1997 1998 1999
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
2000 2001
            png_bytep sp;
            png_bytep dp;
2002 2003
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
2004
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
2005

G
Guy Schalnat 已提交
2006
            /* start at the beginning */
G
Guy Schalnat 已提交
2007 2008 2009 2010 2011
            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 */
2012
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
2013 2014 2015
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
2016
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
2017 2018
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
2019
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
2020 2021 2022
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
2023
            break;
G
Guy Schalnat 已提交
2024 2025 2026 2027 2028 2029 2030
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
2031 2032
         row_info->rowbytes = ((row_info->width *
            row_info->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
2033 2034
   }
}
G
Guy Schalnat 已提交
2035
#endif
G
Guy Schalnat 已提交
2036

A
Andreas Dilger 已提交
2037 2038
/* 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
2039 2040
 * chosen filter.
 */
2041
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
A
Andreas Dilger 已提交
2042
#define PNG_HISHIFT 10
2043 2044
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2045
void /* PRIVATE */
G
Guy Schalnat 已提交
2046
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
2047
{
G
Guy Schalnat 已提交
2048
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
2049
   png_uint_32 mins, bpp;
2050
   png_byte filter_to_do = png_ptr->do_filter;
2051 2052 2053 2054
   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 已提交
2055

A
Andreas Dilger 已提交
2056
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
2057 2058
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
2059 2060 2061

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
2062 2063 2064 2065
   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
2066
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
2067
    * as the "minimum sum of absolute differences" heuristic.  Other
2068
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
2069
    * (experimental and can in theory improve compression), and the "zlib
2070 2071 2072
    * 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 已提交
2073
    * computationally expensive).
2074 2075 2076 2077 2078 2079 2080 2081 2082
    *
    * 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 已提交
2083
    */
G
Guy Schalnat 已提交
2084

2085

G
Guy Schalnat 已提交
2086
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
2087 2088
    * that has been chosen, as it doesn't actually do anything to the data.
    */
2089
   if ((filter_to_do & PNG_FILTER_NONE) &&
2090
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
2091
   {
G
Guy Schalnat 已提交
2092 2093
      png_bytep rp;
      png_uint_32 sum = 0;
2094
      png_uint_32 i;
A
Andreas Dilger 已提交
2095
      int v;
G
Guy Schalnat 已提交
2096

2097
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
2098 2099 2100 2101
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2102 2103 2104 2105 2106

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
2107
         int j;
A
Andreas Dilger 已提交
2108 2109 2110 2111
         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 */
2112
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2113
         {
2114
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2115
            {
2116
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2117
                  PNG_WEIGHT_SHIFT;
2118
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
                  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 已提交
2138 2139
      mins = sum;
   }
G
Guy Schalnat 已提交
2140

G
Guy Schalnat 已提交
2141
   /* sub filter */
2142 2143 2144 2145
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
2146
      png_uint_32 i;
2147 2148 2149 2150 2151
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
2152
      for (lp = row_buf + 1; i < row_bytes;
2153 2154 2155 2156 2157 2158 2159 2160
         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 已提交
2161 2162
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
2163
      png_uint_32 sum = 0, lmins = mins;
2164
      png_uint_32 i;
A
Andreas Dilger 已提交
2165 2166 2167
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2168
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2169 2170 2171 2172 2173
       * 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)
      {
2174
         int j;
A
Andreas Dilger 已提交
2175 2176 2177 2178
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2179
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2180
         {
2181
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2182
            {
2183
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2184
                  PNG_WEIGHT_SHIFT;
2185
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
                  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 已提交
2201

G
Guy Schalnat 已提交
2202 2203 2204 2205
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2206

G
Guy Schalnat 已提交
2207 2208
         sum += (v < 128) ? v : 256 - v;
      }
2209
      for (lp = row_buf + 1; i < row_bytes;
2210
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2211 2212 2213 2214
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2215 2216 2217 2218 2219 2220 2221 2222

         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)
      {
2223
         int j;
A
Andreas Dilger 已提交
2224 2225 2226 2227
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2228
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2229
         {
2230
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2231
            {
2232
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2233
                  PNG_WEIGHT_SHIFT;
2234
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
                  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 已提交
2248
      }
A
Andreas Dilger 已提交
2249 2250
#endif

G
Guy Schalnat 已提交
2251 2252 2253 2254 2255
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2256 2257
   }

G
Guy Schalnat 已提交
2258
   /* up filter */
2259 2260 2261
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2262
      png_uint_32 i;
2263 2264

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2265
           pp = prev_row + 1; i < row_bytes;
2266 2267 2268 2269 2270 2271 2272 2273
           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 已提交
2274 2275
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2276
      png_uint_32 sum = 0, lmins = mins;
2277
      png_uint_32 i;
A
Andreas Dilger 已提交
2278 2279
      int v;

2280

A
Andreas Dilger 已提交
2281 2282 2283
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2284
         int j;
A
Andreas Dilger 已提交
2285 2286 2287 2288
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2289
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2290
         {
2291
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2292
            {
2293
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2294
                  PNG_WEIGHT_SHIFT;
2295
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
                  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 已提交
2311

G
Guy Schalnat 已提交
2312
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2313
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2314
      {
2315
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2316 2317

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2318 2319 2320

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2321
      }
A
Andreas Dilger 已提交
2322 2323 2324 2325

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2326
         int j;
A
Andreas Dilger 已提交
2327 2328 2329 2330
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2331
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2332
         {
2333
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2334
            {
2335
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2336
                  PNG_WEIGHT_SHIFT;
2337
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353
                  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 已提交
2354 2355 2356 2357 2358 2359 2360 2361
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2362 2363 2364
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2365
      png_uint_32 i;
2366
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2367
           pp = prev_row + 1; i < bpp; i++)
2368
      {
2369
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2370
      }
2371
      for (lp = row_buf + 1; i < row_bytes; i++)
2372
      {
2373 2374
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2375 2376 2377 2378 2379
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2380
   {
G
Guy Schalnat 已提交
2381
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2382
      png_uint_32 sum = 0, lmins = mins;
2383
      png_uint_32 i;
A
Andreas Dilger 已提交
2384 2385 2386 2387 2388
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2389
         int j;
A
Andreas Dilger 已提交
2390 2391 2392 2393
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2394
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2395
         {
2396
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
A
Andreas Dilger 已提交
2397
            {
2398
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2399
                  PNG_WEIGHT_SHIFT;
2400
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
                  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 已提交
2416

G
Guy Schalnat 已提交
2417
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2418
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2419
      {
2420
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2421

G
Guy Schalnat 已提交
2422 2423
         sum += (v < 128) ? v : 256 - v;
      }
2424
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2425
      {
2426
         v = *dp++ =
2427
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2428

G
Guy Schalnat 已提交
2429
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2430 2431 2432

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2433
      }
A
Andreas Dilger 已提交
2434 2435 2436 2437

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2438
         int j;
A
Andreas Dilger 已提交
2439 2440 2441 2442
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2443
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2444
         {
2445
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2446
            {
2447
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2448
                  PNG_WEIGHT_SHIFT;
2449
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
                  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 已提交
2466 2467 2468 2469 2470 2471
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2472

A
Andreas Dilger 已提交
2473
   /* Paeth filter */
2474 2475 2476
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2477
      png_uint_32 i;
2478
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2479
           pp = prev_row + 1; i < bpp; i++)
2480
      {
2481
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2482 2483
      }

2484
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2485 2486 2487
      {
         int a, b, c, pa, pb, pc, p;

2488 2489 2490
         b = *pp++;
         c = *cp++;
         a = *lp++;
2491

2492 2493
         p = b - c;
         pc = a - c;
2494 2495

#ifdef PNG_USE_ABS
2496 2497 2498
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2499
#else
2500 2501 2502
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2503 2504 2505 2506
#endif

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

2507
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2508 2509 2510 2511 2512
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2513 2514
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2515
      png_uint_32 sum = 0, lmins = mins;
2516
      png_uint_32 i;
A
Andreas Dilger 已提交
2517 2518 2519 2520 2521
      int v;

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

2527
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2528
         {
2529
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2530
            {
2531
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2532
                  PNG_WEIGHT_SHIFT;
2533
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
                  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 已提交
2549

G
Guy Schalnat 已提交
2550
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2551
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2552
      {
2553
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2554

G
Guy Schalnat 已提交
2555 2556
         sum += (v < 128) ? v : 256 - v;
      }
2557

2558
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2559 2560
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2561

2562 2563 2564
         b = *pp++;
         c = *cp++;
         a = *lp++;
2565 2566

#ifndef PNG_SLOW_PAETH
2567 2568
         p = b - c;
         pc = a - c;
2569
#ifdef PNG_USE_ABS
2570 2571 2572
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2573
#else
2574 2575 2576
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2577 2578 2579
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2580
         p = a + b - c;
2581 2582 2583
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2584 2585 2586 2587 2588 2589
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2590
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2591

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

G
Guy Schalnat 已提交
2594
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2595 2596 2597

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2598
      }
A
Andreas Dilger 已提交
2599 2600 2601 2602

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2603
         int j;
A
Andreas Dilger 已提交
2604 2605 2606 2607
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2608
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2609
         {
2610
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
A
Andreas Dilger 已提交
2611
            {
2612
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2613
                  PNG_WEIGHT_SHIFT;
2614
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630
                  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 已提交
2631 2632 2633 2634
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
2635 2636
   }

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

G
Guy Schalnat 已提交
2639
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2640 2641 2642 2643 2644

#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)
   {
2645 2646
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2647
      {
2648
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2649
      }
2650
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2651 2652
   }
#endif
G
Guy Schalnat 已提交
2653
}
G
Guy Schalnat 已提交
2654

G
Guy Schalnat 已提交
2655

A
Andreas Dilger 已提交
2656
/* Do the actual writing of a previously filtered row. */
2657
void /* PRIVATE */
G
Guy Schalnat 已提交
2658 2659
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2660 2661
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2662
   /* set up the zlib input buffer */
2663

A
Andreas Dilger 已提交
2664 2665
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2666 2667
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2668
   {
G
Guy Schalnat 已提交
2669
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2670

G
Guy Schalnat 已提交
2671
      /* compress the data */
A
Andreas Dilger 已提交
2672
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2673 2674 2675
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2676
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2677
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2678 2679 2680
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2681

G
Guy Schalnat 已提交
2682
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2683
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2684 2685 2686
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2687 2688
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2689 2690
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2691
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2692

G
Guy Schalnat 已提交
2693
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2694
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2695 2696 2697 2698 2699 2700 2701 2702
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2703 2704
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2705

G
Guy Schalnat 已提交
2706 2707 2708 2709 2710 2711 2712
#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 已提交
2713
   }
2714
#endif
G
Guy Schalnat 已提交
2715
}
2716
#endif /* PNG_WRITE_SUPPORTED */