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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
175
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
      char msg[50];
      sprintf(msg, "Unknown compression type %d", compression);
      png_warning(png_ptr, msg);
#else
      png_warning(png_ptr, "Unknown compression type");
#endif
   }

   /* We can't write the chunk until we find out how much data we have,
    * which means we need to run the compressor first and save the
    * output.  This shouldn't be a problem, as the vast majority of
    * comments should be reasonable, but we will set up an array of
    * malloc'd pointers to be sure.
    *
    * If we knew the application was well behaved, we could simplify this
    * greatly by assuming we can always malloc an output buffer large
    * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
    * and malloc this directly.  The only time this would be a bad idea is
    * if we can't malloc more than 64K and we have 64K of random input
    * data, or if the input string is incredibly large (although this
    * wouldn't cause a failure, just a slowdown due to swapping).
    */

   /* set up the compression buffers */
   png_ptr->zstream.avail_in = (uInt)text_len;
   png_ptr->zstream.next_in = (Bytef *)text;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;

   /* this is the same compression loop as in png_write_row() */
   do
   {
      /* compress the data */
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
      if (ret != Z_OK)
      {
         /* error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
      }
      /* check to see if we need more room */
      if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
      {
         /* make sure the output array has room */
         if (comp->num_output_ptr >= comp->max_output_ptr)
         {
            int old_max;

            old_max = comp->max_output_ptr;
            comp->max_output_ptr = comp->num_output_ptr + 4;
            if (comp->output_ptr != NULL)
            {
               png_charpp old_ptr;

               old_ptr = comp->output_ptr;
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
                  (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp)));
               png_memcpy(comp->output_ptr, old_ptr,
           old_max * sizeof (png_charp));
               png_free(png_ptr, old_ptr);
            }
            else
               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
                  (png_uint_32)(comp->max_output_ptr * sizeof (png_charp)));
         }

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

         /* and reset the buffer */
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_out = png_ptr->zbuf;
      }
   /* continue until we don't have any more to compress */
   } while (png_ptr->zstream.avail_in);

   /* finish the compression */
   do
   {
      /* tell zlib we are finished */
      ret = deflate(&png_ptr->zstream, Z_FINISH);

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

               old_max = comp->max_output_ptr;
               comp->max_output_ptr = comp->num_output_ptr + 4;
               if (comp->output_ptr != NULL)
               {
                  png_charpp old_ptr;

                  old_ptr = comp->output_ptr;
                  /* This could be optimized to realloc() */
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
                     (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp)));
                  png_memcpy(comp->output_ptr, old_ptr,
              old_max * sizeof (png_charp));
                  png_free(png_ptr, old_ptr);
               }
               else
                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
                     (png_uint_32)(comp->max_output_ptr * sizeof (png_charp)));
291 292
            }

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

300 301 302 303 304 305 306 307 308 309 310 311
            /* and reset the buffer pointers */
            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
            png_ptr->zstream.next_out = png_ptr->zbuf;
         }
      }
      else if (ret != Z_STREAM_END)
      {
         /* we got an error */
         if (png_ptr->zstream.msg != NULL)
            png_error(png_ptr, png_ptr->zstream.msg);
         else
            png_error(png_ptr, "zlib error");
312 313 314 315 316 317 318 319
      }
   } while (ret != Z_STREAM_END);

   /* text length is number of buffers plus last buffer */
   text_len = png_ptr->zbuf_size * comp->num_output_ptr;
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;

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

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

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

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

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

}
#endif

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

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

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

422
   if (filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
423 424
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
425
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
426 427
   }

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

   /* 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;
   png_ptr->width = width;
   png_ptr->height = height;

G
Guy Schalnat 已提交
446
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
A
Andreas Dilger 已提交
447
   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
448 449 450
   /* 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 已提交
451 452 453 454 455 456 457 458 459 460
   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 已提交
461 462

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

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

G
Guy Schalnat 已提交
498
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
499 500 501
}

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

A
Andreas Dilger 已提交
515
   png_debug(1, "in png_write_PLTE\n");
516
   if ((
517 518
#if defined(PNG_MNG_FEATURES_SUPPORTED)
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
519 520 521 522 523 524 525 526 527 528 529 530
#endif
        num_pal == 0) || num_pal > 256)
     {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
         {
           png_error(png_ptr, "Invalid number of colors in palette");
         }
       else
         {
           png_warning(png_ptr, "Invalid number of colors in palette");
           return;
         }
G
Guy Schalnat 已提交
531 532
   }

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

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

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

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

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

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

   png_debug(1, "in png_write_gAMA\n");
613
   /* file_gamma is saved in 1/100,000ths */
614 615 616 617 618
   png_save_uint_32(buf, file_gamma);
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
}
#endif
#endif
G
Guy Schalnat 已提交
619

620 621
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
622
void /* PRIVATE */
623
png_write_sRGB(png_structp png_ptr, int srgb_intent)
624
{
625 626 627
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
628 629 630
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
631
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
632 633
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
634
   buf[0]=(png_byte)srgb_intent;
635
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
636 637 638
}
#endif

639 640
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
641
void /* PRIVATE */
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
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;
   }

660
   if (compression_type)
661
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
662

663
   if (profile == NULL)
664 665 666
      profile_len = 0;

   if (profile_len)
667
       profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
668
          PNG_TEXT_COMPRESSION_zTXt, &comp);
669 670 671 672

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

   png_debug(1, "in png_write_sPLT\n");
703 704
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
705 706 707 708 709 710 711
   {
      png_warning(png_ptr, "Empty keyword in sPLT chunk");
      return;
   }

   /* make sure we include the NULL after the name */
   png_write_chunk_start(png_ptr, (png_bytep) png_sPLT,
712
          (png_uint_32)(name_len + 2 + palette_size));
713
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
714
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
715 716

   /* loop through each palette entry, writing appropriately */
717
#ifndef PNG_NO_POINTER_INDEXING
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
   for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
   {
       if (spalette->depth == 8)
       {
           entrybuf[0] = (png_byte)ep->red;
           entrybuf[1] = (png_byte)ep->green;
           entrybuf[2] = (png_byte)ep->blue;
           entrybuf[3] = (png_byte)ep->alpha;
           png_save_uint_16(entrybuf + 4, ep->frequency);
       }
       else
       {
           png_save_uint_16(entrybuf + 0, ep->red);
           png_save_uint_16(entrybuf + 2, ep->green);
           png_save_uint_16(entrybuf + 4, ep->blue);
           png_save_uint_16(entrybuf + 6, ep->alpha);
           png_save_uint_16(entrybuf + 8, ep->frequency);
       }
       png_write_chunk_data(png_ptr, entrybuf, entry_size);
   }
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
#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
761 762 763 764 765 766

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

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

A
Andreas Dilger 已提交
778
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
779
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
780 781
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
782
      png_byte maxbits;
G
Guy Schalnat 已提交
783

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

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
811 812 813 814 815
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
816 817 818
      buf[size++] = sbit->alpha;
   }

819
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
820
}
G
Guy Schalnat 已提交
821
#endif
G
Guy Schalnat 已提交
822

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

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

   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;
   }
859
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
860
   png_save_uint_32(buf + 8, itemp);
861
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
862
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
863 864 865 866 867 868 869

   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;
   }
870
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
871
   png_save_uint_32(buf + 16, itemp);
872
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
873
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
874 875 876 877 878 879 880

   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;
   }
881
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
882
   png_save_uint_32(buf + 24, itemp);
883
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
884
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
885

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

   png_debug(1, "in png_write_cHRM\n");
902
   /* each value is saved in 1/100,000ths */
903 904
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
905
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
906 907
#if !defined(PNG_NO_CONSOLE_IO)
      fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
908
#endif
909 910 911 912 913 914 915
      return;
   }
   png_save_uint_32(buf, white_x);
   png_save_uint_32(buf + 4, white_y);

   if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
   {
916
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
917 918 919 920 921 922 923
      return;
   }
   png_save_uint_32(buf + 8, red_x);
   png_save_uint_32(buf + 12, red_y);

   if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
   {
924
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
925 926 927 928 929 930 931
      return;
   }
   png_save_uint_32(buf + 16, green_x);
   png_save_uint_32(buf + 20, green_y);

   if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
   {
932
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
933 934 935 936 937 938 939 940 941
      return;
   }
   png_save_uint_32(buf + 24, blue_x);
   png_save_uint_32(buf + 28, blue_y);

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

G
Guy Schalnat 已提交
943
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
944
/* write the tRNS chunk */
945
void /* PRIVATE */
G
Guy Schalnat 已提交
946
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
947 948
   int num_trans, int color_type)
{
949 950 951
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
952 953
   png_byte buf[6];

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

G
Guy Schalnat 已提交
986
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
987
/* write the background chunk */
988
void /* PRIVATE */
G
Guy Schalnat 已提交
989
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
990
{
991 992 993
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
994 995
   png_byte buf[6];

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

G
Guy Schalnat 已提交
1027
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
1028
/* write the histogram */
1029
void /* PRIVATE */
1030
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
1031
{
1032 1033 1034
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
1035
   int i;
G
Guy Schalnat 已提交
1036 1037
   png_byte buf[3];

A
Andreas Dilger 已提交
1038
   png_debug(1, "in png_write_hIST\n");
1039
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
1040
   {
A
Andreas Dilger 已提交
1041 1042
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
1043 1044 1045 1046
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1047
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1048
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1049
   {
G
Guy Schalnat 已提交
1050
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1051
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1052 1053 1054
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1055
#endif
G
Guy Schalnat 已提交
1056

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

A
Andreas Dilger 已提交
1077 1078 1079 1080
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1081
   {
1082
      png_warning(png_ptr, "zero length keyword");
1083
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1084
   }
A
Andreas Dilger 已提交
1085 1086 1087

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

1088
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
A
Andreas Dilger 已提交
1089 1090 1091

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

1098
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
1099
         png_warning(png_ptr, msg);
1100
#else
1101
         png_warning(png_ptr, "invalid character in keyword");
1102
#endif
A
Andreas Dilger 已提交
1103 1104 1105 1106 1107 1108
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1109
   }
A
Andreas Dilger 已提交
1110
   *dp = '\0';
A
Andreas Dilger 已提交
1111

A
Andreas Dilger 已提交
1112 1113 1114
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1115
   {
1116
      png_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1117 1118 1119 1120 1121 1122

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1123 1124 1125
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1126 1127
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1128
   {
1129
      png_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1130 1131 1132 1133 1134 1135

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

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

   if (key_len == 0)
A
Andreas Dilger 已提交
1164
   {
1165 1166
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1167
      png_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1168 1169 1170 1171
   }

   if (key_len > 79)
   {
1172
      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1173 1174 1175
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1176

1177
   return (key_len);
A
Andreas Dilger 已提交
1178 1179 1180
}
#endif

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

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

A
Andreas Dilger 已提交
1200
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1201
      text_len = 0;
1202 1203
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1204 1205

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

G
Guy Schalnat 已提交
1217
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1218
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1219
}
G
Guy Schalnat 已提交
1220
#endif
G
Guy Schalnat 已提交
1221

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

A
Andreas Dilger 已提交
1236 1237 1238 1239
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1244 1245 1246 1247 1248 1249 1250
   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;
   }

1251 1252
   text_len = png_strlen(text);

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

1255
   /* compute the compressed data; do it now for the length */
1256 1257
   text_len = png_text_compress(png_ptr, text, text_len, compression,
       &comp);
G
Guy Schalnat 已提交
1258

1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
   /* 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 已提交
1269

1270 1271 1272 1273
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1274

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

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

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

1305 1306
   if (text == NULL || *text == '\0')
      text_len = 0;
G
Guy Schalnat 已提交
1307

1308
   /* compute the compressed data; do it now for the length */
1309 1310
   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
      &comp);
G
Guy Schalnat 已提交
1311

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

1315 1316 1317 1318 1319 1320 1321
   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 已提交
1322

1323 1324 1325 1326 1327 1328 1329
   /*
    * 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);
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340

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

1341
   png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
1342
   png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
1343
   png_write_chunk_data(png_ptr, '\0', 1);
G
Guy Schalnat 已提交
1344

1345
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1346 1347

   png_write_chunk_end(png_ptr);
1348 1349
   png_free(png_ptr, new_key);
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1350
}
G
Guy Schalnat 已提交
1351
#endif
G
Guy Schalnat 已提交
1352

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

A
Andreas Dilger 已提交
1365 1366 1367
   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 已提交
1368

A
Andreas Dilger 已提交
1369 1370
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1371
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1372

1373
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1374
}
G
Guy Schalnat 已提交
1375
#endif
G
Guy Schalnat 已提交
1376

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

   png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
   if (type >= PNG_EQUATION_LAST)
      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");

   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
   png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
   png_debug1(3, "pCAL units length = %d\n", units_len);
   total_len = purpose_len + units_len + 10;

1402 1403
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1404 1405 1406 1407 1408 1409

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

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

1432
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1433 1434 1435 1436
   png_write_chunk_end(png_ptr);
}
#endif

1437 1438
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1439
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1440
void /* PRIVATE */
1441
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1442 1443 1444 1445 1446 1447 1448 1449 1450
{
#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");

1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
#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
1461 1462
   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1463
#endif
1464
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1465 1466 1467

   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);
1468
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1469 1470 1471 1472 1473
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf));

   png_write_chunk_end(png_ptr);
}
1474 1475
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1476
void /* PRIVATE */
1477
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1478 1479 1480 1481 1482 1483 1484 1485
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1486
   png_debug(1, "in png_write_sCAL_s\n");
1487

1488 1489
   strcpy(wbuf,(const char *)width);
   strcpy(hbuf,(const char *)height);
1490
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1491 1492 1493

   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);
1494
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1495 1496 1497 1498 1499 1500
   png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1);
   png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf));

   png_write_chunk_end(png_ptr);
}
#endif
1501 1502
#endif
#endif
1503

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

A
Andreas Dilger 已提交
1516 1517 1518
   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 已提交
1519

A
Andreas Dilger 已提交
1520 1521
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1522
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1523

1524
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1525
}
G
Guy Schalnat 已提交
1526
#endif
G
Guy Schalnat 已提交
1527

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

A
Andreas Dilger 已提交
1540
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1541 1542 1543 1544 1545 1546 1547 1548
   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 已提交
1549 1550 1551 1552 1553 1554 1555
   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;

1556
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1557
}
G
Guy Schalnat 已提交
1558
#endif
G
Guy Schalnat 已提交
1559 1560

/* initializes the row writing capability of libpng */
1561
void /* PRIVATE */
G
Guy Schalnat 已提交
1562
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1563
{
1564
#ifdef PNG_USE_LOCAL_ARRAYS
1565
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1566

1567 1568
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1569

1570 1571
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1572

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

1576 1577
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1578
#endif
1579

A
Andreas Dilger 已提交
1580 1581 1582 1583 1584 1585
   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 已提交
1586
   /* set up row buffer */
1587
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1588
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1589 1590 1591

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1592
   {
A
Andreas Dilger 已提交
1593
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1594
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1595
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1596 1597
   }

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

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1607
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1608
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1609
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1610 1611 1612 1613
      }

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

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

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

A
Andreas Dilger 已提交
1654
/* Internal use only.  Called when finished processing a row of data. */
1655
void /* PRIVATE */
G
Guy Schalnat 已提交
1656
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1657
{
1658
#ifdef PNG_USE_LOCAL_ARRAYS
1659
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1660

1661 1662
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1663

1664 1665
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1666

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

1670 1671
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1672
#endif
1673

G
Guy Schalnat 已提交
1674 1675
   int ret;

A
Andreas Dilger 已提交
1676
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1677 1678
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1679

G
Guy Schalnat 已提交
1680
   /* see if we are done */
G
Guy Schalnat 已提交
1681
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1682
      return;
G
Guy Schalnat 已提交
1683

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

      }

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

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

   /* write any extra space */
A
Andreas Dilger 已提交
1755
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1756 1757
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1758
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1759 1760
   }

A
Andreas Dilger 已提交
1761
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1762 1763
}

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

1778 1779
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1780

1781 1782
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1783
#endif
1784

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

            dp = row;
            d = 0;
            shift = 7;
1809
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1810 1811 1812
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1813
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1814 1815 1816 1817 1818
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1819
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1820 1821 1822 1823 1824 1825 1826
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1827
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1828 1829 1830
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1831
         {
G
Guy Schalnat 已提交
1832 1833
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1834 1835 1836
            int shift;
            int d;
            int value;
1837 1838
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1839 1840 1841 1842

            dp = row;
            shift = 6;
            d = 0;
1843
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1844 1845 1846
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1847
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1848 1849 1850 1851 1852
               d |= (value << shift);

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

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

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

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

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

A
Andreas Dilger 已提交
1954
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
1955 1956
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
1957 1958 1959

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

1983

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

1995
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
1996 1997 1998 1999
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
2000 2001 2002 2003 2004

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

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

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

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

G
Guy Schalnat 已提交
2100 2101 2102 2103
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2104

G
Guy Schalnat 已提交
2105 2106
         sum += (v < 128) ? v : 256 - v;
      }
2107 2108
      for (lp = row_buf + 1; i < row_info->rowbytes;
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2109 2110 2111 2112
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2113 2114 2115 2116 2117 2118 2119 2120

         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)
      {
2121
         int j;
A
Andreas Dilger 已提交
2122 2123 2124 2125
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2149 2150 2151 2152 2153
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2154 2155
   }

G
Guy Schalnat 已提交
2156
   /* up filter */
2157 2158 2159
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2160
      png_uint_32 i;
2161 2162

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

2178

A
Andreas Dilger 已提交
2179 2180 2181
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2182
         int j;
A
Andreas Dilger 已提交
2183 2184 2185 2186
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2210
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2211
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2212
      {
2213
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2214 2215

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

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2219
      }
A
Andreas Dilger 已提交
2220 2221 2222 2223

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2224
         int j;
A
Andreas Dilger 已提交
2225 2226 2227 2228
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

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

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2278
   {
G
Guy Schalnat 已提交
2279
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2280
      png_uint_32 sum = 0, lmins = mins;
2281
      png_uint_32 i;
A
Andreas Dilger 已提交
2282 2283 2284 2285 2286
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2287
         int j;
A
Andreas Dilger 已提交
2288 2289 2290 2291
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2315
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2316
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2317
      {
2318
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2319

G
Guy Schalnat 已提交
2320 2321
         sum += (v < 128) ? v : 256 - v;
      }
2322
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2323
      {
2324
         v = *dp++ =
2325
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2326

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

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

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

2341
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2342
         {
2343
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2344
            {
2345
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2346
                  PNG_WEIGHT_SHIFT;
2347
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363
                  PNG_WEIGHT_SHIFT;
            }
         }

         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_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 已提交
2364 2365 2366 2367 2368 2369
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2370

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

2382
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2383 2384 2385
      {
         int a, b, c, pa, pb, pc, p;

2386 2387 2388
         b = *pp++;
         c = *cp++;
         a = *lp++;
2389

2390 2391
         p = b - c;
         pc = a - c;
2392 2393

#ifdef PNG_USE_ABS
2394 2395 2396
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2397
#else
2398 2399 2400
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2401 2402 2403 2404
#endif

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

2405
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2406 2407 2408 2409 2410
      }
      best_row = png_ptr->paeth_row;
   }

   else if (filter_to_do & PNG_FILTER_PAETH)
G
Guy Schalnat 已提交
2411 2412
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
2413
      png_uint_32 sum = 0, lmins = mins;
2414
      png_uint_32 i;
A
Andreas Dilger 已提交
2415 2416 2417 2418 2419
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2420
         int j;
A
Andreas Dilger 已提交
2421 2422 2423 2424
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2448
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2449
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2450
      {
2451
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2452

G
Guy Schalnat 已提交
2453 2454
         sum += (v < 128) ? v : 256 - v;
      }
2455

2456
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2457 2458
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2459

2460 2461 2462
         b = *pp++;
         c = *cp++;
         a = *lp++;
2463 2464

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

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

G
Guy Schalnat 已提交
2492
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2493 2494 2495

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2496
      }
A
Andreas Dilger 已提交
2497 2498 2499 2500

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2501
         int j;
A
Andreas Dilger 已提交
2502 2503 2504 2505
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

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

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

G
Guy Schalnat 已提交
2537
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2538 2539 2540 2541 2542

#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)
   {
2543 2544
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2545
      {
2546
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2547
      }
2548
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2549 2550
   }
#endif
G
Guy Schalnat 已提交
2551
}
G
Guy Schalnat 已提交
2552

G
Guy Schalnat 已提交
2553

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

A
Andreas Dilger 已提交
2562 2563
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2564 2565
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2566
   {
G
Guy Schalnat 已提交
2567
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2568

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

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

G
Guy Schalnat 已提交
2591
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2592
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2593 2594 2595 2596 2597 2598 2599 2600
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2601 2602
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2603

G
Guy Schalnat 已提交
2604 2605 2606 2607 2608 2609 2610
#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 已提交
2611
   }
2612
#endif
G
Guy Schalnat 已提交
2613
}