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

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3
 *
4
 * libpng 1.0.6h - April 24, 2000
5 6 7
 * For conditions of distribution and use, see copyright notice in png.h
 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
 * Copyright (c) 1996, 1997 Andreas Dilger
8
 * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson
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.
 */
G
Guy Schalnat 已提交
18
void
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.
 */
G
Guy Schalnat 已提交
32
void
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.
 */
G
Guy Schalnat 已提交
46
void
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.
 */
G
Guy Schalnat 已提交
62
void
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().
 */
G
Guy Schalnat 已提交
75
void
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 80 81
   png_byte buf[4];
   png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);

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().
 */
G
Guy Schalnat 已提交
98
void
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(). */
G
Guy Schalnat 已提交
110
void
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.
 */
G
Guy Schalnat 已提交
127
void
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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 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 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
/*
 * 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 */
static int
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;
       return(text_len);
   }

   if (compression >= PNG_TEXT_COMPRESSION_LAST)
   {
#if !defined(PNG_NO_STDIO)
      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);
      if (ret != Z_OK && 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");
      }

      /* check to see if we need more room */
      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
      {
         /* check to make sure our 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;
               /* 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)));
         }

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

         /* and reset the buffer pointers */
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_out = png_ptr->zbuf;
      }
   } 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;

   return(text_len);
}

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

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

A
Andreas Dilger 已提交
411
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
412 413
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
414
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
415 416
   }

A
Andreas Dilger 已提交
417
   if (filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
418 419
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
420
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
421 422
   }

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

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

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

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

G
Guy Schalnat 已提交
493
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
494 495 496
}

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

A
Andreas Dilger 已提交
510
   png_debug(1, "in png_write_PLTE\n");
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
   if ((
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
        !png_ptr->empty_plte_permitted &&
#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 已提交
526 527
   }

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

531
   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
A
Andreas Dilger 已提交
532
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
533 534 535 536
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
537
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
538 539
   }
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
540
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
541 542 543 544
}

/* write an IDAT chunk */
void
A
Andreas Dilger 已提交
545
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
546
{
547 548 549
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IDAT;
#endif
A
Andreas Dilger 已提交
550
   png_debug(1, "in png_write_IDAT\n");
551
   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
G
Guy Schalnat 已提交
552
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
553 554 555 556
}

/* write an IEND chunk */
void
G
Guy Schalnat 已提交
557
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
558
{
559 560 561
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_IEND;
#endif
A
Andreas Dilger 已提交
562
   png_debug(1, "in png_write_IEND\n");
563
   png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
A
Andreas Dilger 已提交
564
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
565 566
}

G
Guy Schalnat 已提交
567
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
568
/* write a gAMA chunk */
569
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
570
void
A
Andreas Dilger 已提交
571
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
572
{
573 574 575
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
G
Guy Schalnat 已提交
576 577 578
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
579
   png_debug(1, "in png_write_gAMA\n");
580
   /* file_gamma is saved in 1/100,000ths */
581
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
582
   png_save_uint_32(buf, igamma);
583
   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
584
}
G
Guy Schalnat 已提交
585
#endif
586
#ifdef PNG_FIXED_POINT_SUPPORTED
587 588
void
png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
589 590 591 592 593 594 595
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_gAMA;
#endif
   png_byte buf[4];

   png_debug(1, "in png_write_gAMA\n");
596
   /* file_gamma is saved in 1/100,000ths */
597 598 599 600 601
   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 已提交
602

603 604 605
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
void
606
png_write_sRGB(png_structp png_ptr, int srgb_intent)
607
{
608 609 610
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sRGB;
#endif
611 612 613
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
614
   if(srgb_intent >= PNG_sRGB_INTENT_LAST)
615 616
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
617
   buf[0]=(png_byte)srgb_intent;
618
   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
619 620 621
}
#endif

622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
#if defined(PNG_WRITE_iCCP_SUPPORTED)
/* write an iCCP chunk */
void
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;
   }

   if (compression_type)
644
      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668

   if (profile == NULL || *profile == '\0')
      profile_len = 0;

   if (profile_len)
       profile_len = png_text_compress(png_ptr, profile, profile_len,
                   PNG_TEXT_COMPRESSION_zTXt, &comp);

   /* 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);
   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 */
void
669
png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
670 671 672 673 674 675 676 677 678
{
#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;
679
   png_sPLT_entryp ep;
680 681

   png_debug(1, "in png_write_sPLT\n");
682 683
   if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
      spalette->name, &new_name))==0)
684 685 686 687 688 689 690
   {
      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,
691
          (png_uint_32)(name_len + 2 + palette_size));
692
   png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
693
   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721

   /* loop through each palette entry, writing appropriately */
   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);
   }

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

G
Guy Schalnat 已提交
722
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
723 724
/* write the sBIT chunk */
void
G
Guy Schalnat 已提交
725
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
726
{
727 728 729
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sBIT;
#endif
G
Guy Schalnat 已提交
730
   png_byte buf[4];
A
Andreas Dilger 已提交
731
   png_size_t size;
G
Guy Schalnat 已提交
732

A
Andreas Dilger 已提交
733
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
734
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
735 736
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
737
      png_byte maxbits;
G
Guy Schalnat 已提交
738

739 740
      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
                png_ptr->usr_bit_depth);
741 742
      if (sbit->red == 0 || sbit->red > maxbits ||
          sbit->green == 0 || sbit->green > maxbits ||
G
Guy Schalnat 已提交
743 744 745 746 747
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
748 749 750 751 752 753 754
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
755 756 757 758 759
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
760 761 762 763 764 765
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
766 767 768 769 770
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
771 772 773
      buf[size++] = sbit->alpha;
   }

774
   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
G
Guy Schalnat 已提交
775
}
G
Guy Schalnat 已提交
776
#endif
G
Guy Schalnat 已提交
777

G
Guy Schalnat 已提交
778
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
779
/* write the cHRM chunk */
780
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
781
void
A
Andreas Dilger 已提交
782
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
783 784
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
785
{
786 787 788
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
G
Guy Schalnat 已提交
789
   png_byte buf[32];
790
   png_uint_32 itemp;
G
Guy Schalnat 已提交
791

A
Andreas Dilger 已提交
792
   png_debug(1, "in png_write_cHRM\n");
793
   /* each value is saved in 1/100,000ths */
G
Guy Schalnat 已提交
794 795 796 797
   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");
798
#if !defined(PNG_NO_STDIO)
799
      printf("white_x=%f, white_y=%f\n",white_x, white_y);
800
#endif
G
Guy Schalnat 已提交
801 802
      return;
   }
803
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
804
   png_save_uint_32(buf, itemp);
805
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
806
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
807 808 809 810 811 812 813

   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;
   }
814
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
815
   png_save_uint_32(buf + 8, itemp);
816
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
817
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
818 819 820 821 822 823 824

   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;
   }
825
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
826
   png_save_uint_32(buf + 16, itemp);
827
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
828
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
829 830 831 832 833 834 835

   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;
   }
836
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
G
Guy Schalnat 已提交
837
   png_save_uint_32(buf + 24, itemp);
838
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
G
Guy Schalnat 已提交
839
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
840

841
   png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
842
}
G
Guy Schalnat 已提交
843
#endif
844 845
#ifdef PNG_FIXED_POINT_SUPPORTED
void
846 847 848 849
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)
850 851 852 853 854 855 856
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_cHRM;
#endif
   png_byte buf[32];

   png_debug(1, "in png_write_cHRM\n");
857
   /* each value is saved in 1/100,000ths */
858 859
   if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
   {
860
      png_warning(png_ptr, "Invalid fixed cHRM white point specified");
861
#if !defined(PNG_NO_STDIO)
862
      printf("white_x=%ld, white_y=%ld\n",white_x, white_y);
863
#endif
864 865 866 867 868 869 870
      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)
   {
871
      png_warning(png_ptr, "Invalid cHRM fixed red point specified");
872 873 874 875 876 877 878
      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)
   {
879
      png_warning(png_ptr, "Invalid fixed cHRM green point specified");
880 881 882 883 884 885 886
      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)
   {
887
      png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
888 889 890 891 892 893 894 895 896
      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 已提交
897

G
Guy Schalnat 已提交
898
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
899 900
/* write the tRNS chunk */
void
G
Guy Schalnat 已提交
901
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
902 903
   int num_trans, int color_type)
{
904 905 906
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tRNS;
#endif
G
Guy Schalnat 已提交
907 908
   png_byte buf[6];

A
Andreas Dilger 已提交
909
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
910 911
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
912
      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
913 914 915 916
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
917
      /* write the chunk out as it is */
918
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
919 920 921 922 923
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
      png_save_uint_16(buf, tran->gray);
924
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
925 926 927 928 929 930 931
   }
   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);
932
      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
933
   }
G
Guy Schalnat 已提交
934 935
   else
   {
936
      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
G
Guy Schalnat 已提交
937
   }
G
Guy Schalnat 已提交
938
}
G
Guy Schalnat 已提交
939
#endif
G
Guy Schalnat 已提交
940

G
Guy Schalnat 已提交
941
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
942 943
/* write the background chunk */
void
G
Guy Schalnat 已提交
944
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
945
{
946 947 948
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_bKGD;
#endif
G
Guy Schalnat 已提交
949 950
   png_byte buf[6];

A
Andreas Dilger 已提交
951
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
952 953
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
954 955 956 957 958 959
      if (
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
          (!png_ptr->empty_plte_permitted ||
          (png_ptr->empty_plte_permitted && png_ptr->num_palette)) &&
#endif
         back->index > png_ptr->num_palette)
G
Guy Schalnat 已提交
960 961 962 963
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
964
      buf[0] = back->index;
965
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
966 967 968 969 970 971
   }
   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);
972
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
973 974
   }
   else
G
Guy Schalnat 已提交
975
   {
G
Guy Schalnat 已提交
976
      png_save_uint_16(buf, back->gray);
977
      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
978 979
   }
}
G
Guy Schalnat 已提交
980
#endif
G
Guy Schalnat 已提交
981

G
Guy Schalnat 已提交
982
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
983 984
/* write the histogram */
void
985
png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
G
Guy Schalnat 已提交
986
{
987 988 989
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_hIST;
#endif
990
   int i;
G
Guy Schalnat 已提交
991 992
   png_byte buf[3];

A
Andreas Dilger 已提交
993
   png_debug(1, "in png_write_hIST\n");
994
   if (num_hist > (int)png_ptr->num_palette)
G
Guy Schalnat 已提交
995
   {
A
Andreas Dilger 已提交
996 997
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
998 999 1000 1001
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

1002
   png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
A
Andreas Dilger 已提交
1003
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
1004
   {
G
Guy Schalnat 已提交
1005
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
1006
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
1007 1008 1009
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
1010
#endif
G
Guy Schalnat 已提交
1011

1012 1013
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
A
Andreas Dilger 已提交
1014 1015 1016 1017 1018
/* 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 已提交
1019 1020 1021 1022
 *
 * 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 已提交
1023
 */
A
Andreas Dilger 已提交
1024
png_size_t
1025
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
1026
{
A
Andreas Dilger 已提交
1027
   png_size_t key_len;
1028
   png_charp kp, dp;
A
Andreas Dilger 已提交
1029 1030
   int kflag;

A
Andreas Dilger 已提交
1031 1032 1033 1034
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
1035
   {
1036
      png_chunk_warning(png_ptr, "zero length keyword");
1037
      return ((png_size_t)0);
A
Andreas Dilger 已提交
1038
   }
A
Andreas Dilger 已提交
1039 1040 1041

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

1042
   *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 1));
A
Andreas Dilger 已提交
1043 1044 1045

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

1052 1053 1054 1055 1056
         sprintf(msg, "invalid keyword character 0x%02X", *kp);
         png_chunk_warning(png_ptr, msg);
#else
         png_chunk_warning(png_ptr, "invalid character in keyword");
#endif
A
Andreas Dilger 已提交
1057 1058 1059 1060 1061 1062
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
1063
   }
A
Andreas Dilger 已提交
1064
   *dp = '\0';
A
Andreas Dilger 已提交
1065

A
Andreas Dilger 已提交
1066 1067 1068
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1069
   {
1070
      png_chunk_warning(png_ptr, "trailing spaces removed from keyword");
A
Andreas Dilger 已提交
1071 1072 1073 1074 1075 1076

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
1077 1078 1079
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
1080 1081
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
1082
   {
1083
      png_chunk_warning(png_ptr, "leading spaces removed from keyword");
A
Andreas Dilger 已提交
1084 1085 1086 1087 1088 1089

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

A
Andreas Dilger 已提交
1092 1093 1094 1095
   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 已提交
1096
   {
A
Andreas Dilger 已提交
1097
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
1098
      {
A
Andreas Dilger 已提交
1099 1100
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
1101
      }
A
Andreas Dilger 已提交
1102
      else if (*kp == ' ')
A
Andreas Dilger 已提交
1103 1104 1105 1106 1107
      {
         key_len--;
      }
      else
      {
A
Andreas Dilger 已提交
1108 1109
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
1110 1111
      }
   }
A
Andreas Dilger 已提交
1112
   *dp = '\0';
A
Andreas Dilger 已提交
1113 1114

   if (key_len == 0)
A
Andreas Dilger 已提交
1115
   {
1116 1117
      png_free(png_ptr, *new_key);
      *new_key=NULL;
1118
      png_chunk_warning(png_ptr, "Zero length keyword");
A
Andreas Dilger 已提交
1119 1120 1121 1122
   }

   if (key_len > 79)
   {
1123
      png_chunk_warning(png_ptr, "keyword length must be 1 - 79 characters");
A
Andreas Dilger 已提交
1124 1125 1126
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
1127

1128
   return (key_len);
A
Andreas Dilger 已提交
1129 1130 1131
}
#endif

G
Guy Schalnat 已提交
1132
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
1133 1134
/* write a tEXt chunk */
void
G
Guy Schalnat 已提交
1135
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1136
   png_size_t text_len)
G
Guy Schalnat 已提交
1137
{
1138 1139 1140
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tEXt;
#endif
A
Andreas Dilger 已提交
1141
   png_size_t key_len;
1142
   png_charp new_key;
A
Andreas Dilger 已提交
1143 1144 1145 1146

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

A
Andreas Dilger 已提交
1151
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
1152
      text_len = 0;
1153 1154
   else
      text_len = png_strlen(text);
A
Andreas Dilger 已提交
1155 1156

   /* make sure we include the 0 after the key */
1157
   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1158 1159 1160 1161
   /*
    * 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.
1162
    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1163
    */
1164
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
1165
   if (text_len)
A
Andreas Dilger 已提交
1166
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
1167

G
Guy Schalnat 已提交
1168
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
1169
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
1170
}
G
Guy Schalnat 已提交
1171
#endif
G
Guy Schalnat 已提交
1172

G
Guy Schalnat 已提交
1173
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
1174
/* write a compressed text chunk */
G
Guy Schalnat 已提交
1175
void
G
Guy Schalnat 已提交
1176
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
1177
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
1178
{
1179 1180 1181
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_zTXt;
#endif
A
Andreas Dilger 已提交
1182
   png_size_t key_len;
G
Guy Schalnat 已提交
1183
   char buf[1];
1184
   png_charp new_key;
1185
   compression_state comp;
G
Guy Schalnat 已提交
1186

A
Andreas Dilger 已提交
1187 1188 1189 1190
   png_debug(1, "in png_write_zTXt\n");

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

A
Andreas Dilger 已提交
1195 1196 1197 1198 1199 1200 1201
   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;
   }

1202 1203
   text_len = png_strlen(text);

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

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

1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
   /* 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 已提交
1219

1220 1221 1222 1223
   /* close the chunk */
   png_write_chunk_end(png_ptr);
}
#endif
G
Guy Schalnat 已提交
1224

1225 1226 1227 1228
#if defined(PNG_WRITE_iTXt_SUPPORTED)
/* write an iTXt chunk */
void
png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1229
    png_charp lang, png_charp lang_key, png_charp text)
1230 1231 1232 1233
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_iTXt;
#endif
1234
   png_size_t lang_len, key_len, lang_key_len, text_len;
1235 1236 1237
   png_charp new_lang, new_key;
   png_byte cbuf[2];
   compression_state comp;
G
Guy Schalnat 已提交
1238

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

1241
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
G
Guy Schalnat 已提交
1242
   {
1243
      png_warning(png_ptr, "Empty keyword in iTXt chunk");
1244 1245
      return;
   }
1246 1247
   if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang,
      &new_lang))==0)
1248
   {
1249
      png_warning(png_ptr, "Empty language field in iTXt chunk");
1250 1251
      return;
   }
1252 1253
   lang_key_len = png_strlen(lang_key);
   text_len = png_strlen(text);
G
Guy Schalnat 已提交
1254

1255 1256
   if (text == NULL || *text == '\0')
      text_len = 0;
G
Guy Schalnat 已提交
1257

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

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

1264 1265 1266 1267 1268 1269 1270
   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 已提交
1271

1272 1273 1274 1275 1276 1277 1278
   /*
    * 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);
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289

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

1290
   png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
1291
   png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
1292
   png_write_chunk_data(png_ptr, '\0', 1);
G
Guy Schalnat 已提交
1293

1294
   png_write_compressed_data_out(png_ptr, &comp);
G
Guy Schalnat 已提交
1295 1296

   png_write_chunk_end(png_ptr);
1297 1298
   png_free(png_ptr, new_key);
   png_free(png_ptr, new_lang);
G
Guy Schalnat 已提交
1299
}
G
Guy Schalnat 已提交
1300
#endif
G
Guy Schalnat 已提交
1301

A
Andreas Dilger 已提交
1302 1303
#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
G
Guy Schalnat 已提交
1304
void
A
Andreas Dilger 已提交
1305 1306
png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
   png_uint_32 y_offset,
G
Guy Schalnat 已提交
1307 1308
   int unit_type)
{
1309 1310 1311
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_oFFs;
#endif
G
Guy Schalnat 已提交
1312 1313
   png_byte buf[9];

A
Andreas Dilger 已提交
1314 1315 1316
   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 已提交
1317

A
Andreas Dilger 已提交
1318 1319
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
1320
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1321

1322
   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1323
}
G
Guy Schalnat 已提交
1324
#endif
G
Guy Schalnat 已提交
1325

A
Andreas Dilger 已提交
1326 1327
#if defined(PNG_WRITE_pCAL_SUPPORTED)
/* write the pCAL chunk (png-scivis-19970203) */
G
Guy Schalnat 已提交
1328
void
A
Andreas Dilger 已提交
1329 1330 1331
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)
{
1332 1333 1334
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pCAL;
#endif
1335
   png_size_t purpose_len, units_len, total_len;
A
Andreas Dilger 已提交
1336 1337
   png_uint_32p params_len;
   png_byte buf[10];
1338
   png_charp new_purpose;
A
Andreas Dilger 已提交
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
   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;

1351 1352
   params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
      *sizeof(png_uint_32)));
A
Andreas Dilger 已提交
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363

   /* 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);
      png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
      total_len += (png_size_t)params_len[i];
   }

   png_debug1(3, "pCAL total length = %d\n", total_len);
1364
   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1365
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
   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]);
   }

1381
   png_free(png_ptr, params_len);
A
Andreas Dilger 已提交
1382 1383 1384 1385
   png_write_chunk_end(png_ptr);
}
#endif

1386 1387
#if defined(PNG_WRITE_sCAL_SUPPORTED)
/* write the sCAL chunk */
1388
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1389
void
1390
png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
{
#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");

   sprintf(wbuf, "%12.12e", width);
   sprintf(hbuf, "%12.12e", height);
1402
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1403 1404 1405

   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);
1406
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1407 1408 1409 1410 1411
   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);
}
1412 1413
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
1414
void
1415
png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1416 1417 1418 1419 1420 1421 1422 1423
   png_charp height)
{
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_sCAL;
#endif
   png_size_t total_len;
   char wbuf[32], hbuf[32];

1424
   png_debug(1, "in png_write_sCAL_s\n");
1425

1426 1427
   strcpy(wbuf,(const char *)width);
   strcpy(hbuf,(const char *)height);
1428
   total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1429 1430 1431

   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);
1432
   png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
1433 1434 1435 1436 1437 1438
   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
1439 1440
#endif
#endif
1441

A
Andreas Dilger 已提交
1442 1443 1444 1445 1446
#if defined(PNG_WRITE_pHYs_SUPPORTED)
/* write the pHYs chunk */
void
png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
   png_uint_32 y_pixels_per_unit,
G
Guy Schalnat 已提交
1447 1448
   int unit_type)
{
1449 1450 1451
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_pHYs;
#endif
G
Guy Schalnat 已提交
1452 1453
   png_byte buf[9];

A
Andreas Dilger 已提交
1454 1455 1456
   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 已提交
1457

A
Andreas Dilger 已提交
1458 1459
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1460
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1461

1462
   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1463
}
G
Guy Schalnat 已提交
1464
#endif
G
Guy Schalnat 已提交
1465

G
Guy Schalnat 已提交
1466
#if defined(PNG_WRITE_tIME_SUPPORTED)
1467 1468 1469
/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
 * or png_convert_from_time_t(), or fill in the structure yourself.
 */
G
Guy Schalnat 已提交
1470
void
G
Guy Schalnat 已提交
1471
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1472
{
1473 1474 1475
#ifdef PNG_USE_LOCAL_ARRAYS
   PNG_tIME;
#endif
G
Guy Schalnat 已提交
1476 1477
   png_byte buf[7];

A
Andreas Dilger 已提交
1478
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1479 1480 1481 1482 1483 1484 1485 1486
   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 已提交
1487 1488 1489 1490 1491 1492 1493
   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;

1494
   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1495
}
G
Guy Schalnat 已提交
1496
#endif
G
Guy Schalnat 已提交
1497 1498 1499

/* initializes the row writing capability of libpng */
void
G
Guy Schalnat 已提交
1500
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1501
{
1502
#ifdef PNG_USE_LOCAL_ARRAYS
1503
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1504

1505 1506
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1507

1508 1509
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1510

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

1514 1515
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1516
#endif
1517

A
Andreas Dilger 已提交
1518 1519 1520 1521 1522 1523
   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 已提交
1524
   /* set up row buffer */
1525
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1526
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1527 1528 1529

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1530
   {
A
Andreas Dilger 已提交
1531
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1532
         (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1533
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1534 1535
   }

A
Andreas Dilger 已提交
1536
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1537 1538 1539
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
1540
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
A
Andreas Dilger 已提交
1541
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1542 1543 1544

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1545
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1546
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1547
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1548 1549 1550 1551
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
1552 1553
         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1554
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1555 1556 1557 1558
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1559
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1560
            (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1561
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1562
      }
G
Guy Schalnat 已提交
1563 1564
   }

1565
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1566
   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1567
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1568 1569 1570 1571 1572
   {
      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 已提交
1573 1574
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1575 1576 1577 1578 1579 1580 1581 1582
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
1583
#endif
G
Guy Schalnat 已提交
1584
   {
G
Guy Schalnat 已提交
1585 1586 1587
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1588 1589
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1590 1591
}

A
Andreas Dilger 已提交
1592
/* Internal use only.  Called when finished processing a row of data. */
G
Guy Schalnat 已提交
1593
void
G
Guy Schalnat 已提交
1594
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1595
{
1596
#ifdef PNG_USE_LOCAL_ARRAYS
1597
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1598

1599 1600
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1601

1602 1603
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1604

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

1608 1609
   /* offset to next interlace block in the y direction */
   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1610
#endif
1611

G
Guy Schalnat 已提交
1612 1613
   int ret;

A
Andreas Dilger 已提交
1614
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1615 1616
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1617

G
Guy Schalnat 已提交
1618
   /* see if we are done */
G
Guy Schalnat 已提交
1619
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1620
      return;
G
Guy Schalnat 已提交
1621

1622
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
G
Guy Schalnat 已提交
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
   /* 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 已提交
1639
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1640 1641 1642 1643 1644 1645 1646
               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 已提交
1647 1648
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1649 1650 1651 1652
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1653
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1654
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1655
      {
A
Andreas Dilger 已提交
1656
         if (png_ptr->prev_row != NULL)
1657
            png_memset(png_ptr->prev_row, 0,
A
Andreas Dilger 已提交
1658
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1659 1660
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1661
         return;
G
Guy Schalnat 已提交
1662
      }
G
Guy Schalnat 已提交
1663
   }
1664
#endif
G
Guy Schalnat 已提交
1665 1666 1667 1668 1669 1670

   /* 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 已提交
1671
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1672 1673 1674
      /* check for an error */
      if (ret != Z_OK && ret != Z_STREAM_END)
      {
A
Andreas Dilger 已提交
1675
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1676
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1677
         else
G
Guy Schalnat 已提交
1678
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1679
      }
G
Guy Schalnat 已提交
1680
      /* check to see if we need more room */
A
Andreas Dilger 已提交
1681
      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
G
Guy Schalnat 已提交
1682 1683
      {
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
1684 1685
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
1686 1687 1688 1689
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1690
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1691 1692
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1693
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1694 1695
   }

A
Andreas Dilger 已提交
1696
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1697 1698
}

G
Guy Schalnat 已提交
1699
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1700 1701 1702 1703 1704 1705 1706
/* 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.
 */
G
Guy Schalnat 已提交
1707
void
G
Guy Schalnat 已提交
1708
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1709
{
1710
#ifdef PNG_USE_LOCAL_ARRAYS
1711
   /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1712

1713 1714
   /* start of interlace block */
   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1715

1716 1717
   /* offset to next interlace block */
   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1718
#endif
1719

A
Andreas Dilger 已提交
1720
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1721
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1722 1723 1724 1725 1726
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1727
   {
1728
      /* each pixel depth is handled separately */
G
Guy Schalnat 已提交
1729
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1730
      {
G
Guy Schalnat 已提交
1731 1732
         case 1:
         {
G
Guy Schalnat 已提交
1733 1734
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1735 1736 1737
            int shift;
            int d;
            int value;
1738 1739
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1740 1741 1742 1743

            dp = row;
            d = 0;
            shift = 7;
1744
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1745 1746 1747
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
1748
               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
G
Guy Schalnat 已提交
1749 1750 1751 1752 1753
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1754
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1755 1756 1757 1758 1759 1760 1761
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1762
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1763 1764 1765
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1766
         {
G
Guy Schalnat 已提交
1767 1768
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1769 1770 1771
            int shift;
            int d;
            int value;
1772 1773
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1774 1775 1776 1777

            dp = row;
            shift = 6;
            d = 0;
1778
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1779 1780 1781
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
1782
               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
G
Guy Schalnat 已提交
1783 1784 1785 1786 1787
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1788
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1789 1790 1791 1792 1793 1794
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1795
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1796 1797 1798 1799
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1800 1801
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1802
            int shift;
G
Guy Schalnat 已提交
1803 1804
            int d;
            int value;
1805 1806
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
1807 1808 1809 1810

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

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1820 1821
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1822 1823 1824 1825 1826 1827
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1828
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1829 1830 1831 1832
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
1833 1834
            png_bytep sp;
            png_bytep dp;
1835 1836
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
1837
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
1838

G
Guy Schalnat 已提交
1839
            /* start at the beginning */
G
Guy Schalnat 已提交
1840 1841 1842 1843 1844
            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 */
1845
            for (i = png_pass_start[pass]; i < row_width;
G
Guy Schalnat 已提交
1846 1847 1848
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
1849
               sp = row + (png_size_t)i * pixel_bytes;
G
Guy Schalnat 已提交
1850 1851
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
1852
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
1853 1854 1855
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
1856
            break;
G
Guy Schalnat 已提交
1857 1858 1859 1860 1861 1862 1863
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
1864 1865
         row_info->rowbytes = ((row_info->width *
            row_info->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
1866 1867
   }
}
G
Guy Schalnat 已提交
1868
#endif
G
Guy Schalnat 已提交
1869

A
Andreas Dilger 已提交
1870 1871
/* 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
1872 1873
 * chosen filter.
 */
1874
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
A
Andreas Dilger 已提交
1875
#define PNG_HISHIFT 10
1876 1877
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
G
Guy Schalnat 已提交
1878
void
G
Guy Schalnat 已提交
1879
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
1880
{
G
Guy Schalnat 已提交
1881
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
1882
   png_uint_32 mins, bpp;
1883
   png_byte filter_to_do = png_ptr->do_filter;
1884 1885 1886 1887
   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 已提交
1888

A
Andreas Dilger 已提交
1889
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
1890 1891
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
1892 1893 1894

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
1895 1896 1897 1898
   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
1899
    * from zero, using anything >= 128 as negative numbers.  This is known
A
Andreas Dilger 已提交
1900
    * as the "minimum sum of absolute differences" heuristic.  Other
1901
    * heuristics are the "weighted minimum sum of absolute differences"
A
Andreas Dilger 已提交
1902
    * (experimental and can in theory improve compression), and the "zlib
1903 1904 1905
    * 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 已提交
1906
    * computationally expensive).
1907 1908 1909 1910 1911 1912 1913 1914 1915
    *
    * 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 已提交
1916
    */
G
Guy Schalnat 已提交
1917

1918

G
Guy Schalnat 已提交
1919
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
1920 1921
    * that has been chosen, as it doesn't actually do anything to the data.
    */
1922
   if ((filter_to_do & PNG_FILTER_NONE) &&
1923
       filter_to_do != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
1924
   {
G
Guy Schalnat 已提交
1925 1926
      png_bytep rp;
      png_uint_32 sum = 0;
1927
      png_uint_32 i;
A
Andreas Dilger 已提交
1928
      int v;
G
Guy Schalnat 已提交
1929

1930
      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
G
Guy Schalnat 已提交
1931 1932 1933 1934
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
1935 1936 1937 1938 1939

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
1940
         int j;
A
Andreas Dilger 已提交
1941 1942 1943 1944
         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 */
1945
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
1946
         {
1947
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
1948
            {
1949
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
1950
                  PNG_WEIGHT_SHIFT;
1951
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970
                  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 已提交
1971 1972
      mins = sum;
   }
G
Guy Schalnat 已提交
1973

G
Guy Schalnat 已提交
1974
   /* sub filter */
1975 1976 1977 1978
   if (filter_to_do == PNG_FILTER_SUB)
   /* it's the only filter so no testing is needed */
   {
      png_bytep rp, lp, dp;
1979
      png_uint_32 i;
1980 1981 1982 1983 1984
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         *dp = *rp;
      }
1985
      for (lp = row_buf + 1; i < row_bytes;
1986 1987 1988 1989 1990 1991 1992 1993
         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 已提交
1994 1995
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
1996
      png_uint_32 sum = 0, lmins = mins;
1997
      png_uint_32 i;
A
Andreas Dilger 已提交
1998 1999 2000
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2001
      /* We temporarily increase the "minimum sum" by the factor we
A
Andreas Dilger 已提交
2002 2003 2004 2005 2006
       * 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)
      {
2007
         int j;
A
Andreas Dilger 已提交
2008 2009 2010 2011
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2012
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2013
         {
2014
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2015
            {
2016
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2017
                  PNG_WEIGHT_SHIFT;
2018
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
                  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 已提交
2034

G
Guy Schalnat 已提交
2035 2036 2037 2038
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
2039

G
Guy Schalnat 已提交
2040 2041
         sum += (v < 128) ? v : 256 - v;
      }
2042 2043
      for (lp = row_buf + 1; i < row_info->rowbytes;
         i++, rp++, lp++, dp++)
G
Guy Schalnat 已提交
2044 2045 2046 2047
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2048 2049 2050 2051 2052 2053 2054 2055

         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)
      {
2056
         int j;
A
Andreas Dilger 已提交
2057 2058 2059 2060
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2061
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2062
         {
2063
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
A
Andreas Dilger 已提交
2064
            {
2065
               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2066
                  PNG_WEIGHT_SHIFT;
2067
               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080
                  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 已提交
2081
      }
A
Andreas Dilger 已提交
2082 2083
#endif

G
Guy Schalnat 已提交
2084 2085 2086 2087 2088
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
2089 2090
   }

G
Guy Schalnat 已提交
2091
   /* up filter */
2092 2093 2094
   if (filter_to_do == PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
2095
      png_uint_32 i;
2096 2097

      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2098
           pp = prev_row + 1; i < row_bytes;
2099 2100 2101 2102 2103 2104 2105 2106
           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 已提交
2107 2108
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
2109
      png_uint_32 sum = 0, lmins = mins;
2110
      png_uint_32 i;
A
Andreas Dilger 已提交
2111 2112
      int v;

2113

A
Andreas Dilger 已提交
2114 2115 2116
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2117
         int j;
A
Andreas Dilger 已提交
2118 2119 2120 2121
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

2122
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2123
         {
2124
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2125
            {
2126
               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2127
                  PNG_WEIGHT_SHIFT;
2128
               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
A
Andreas Dilger 已提交
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
                  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 已提交
2144

G
Guy Schalnat 已提交
2145
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2146
           pp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2147
      {
2148
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2149 2150

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2151 2152 2153

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2154
      }
A
Andreas Dilger 已提交
2155 2156 2157 2158

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2159
         int j;
A
Andreas Dilger 已提交
2160 2161 2162 2163
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2164
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2165
         {
2166
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
A
Andreas Dilger 已提交
2167
            {
2168
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2169
                  PNG_WEIGHT_SHIFT;
2170
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
                  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 已提交
2187 2188 2189 2190 2191 2192 2193 2194
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
2195 2196 2197
   if (filter_to_do == PNG_FILTER_AVG)
   {
      png_bytep rp, dp, pp, lp;
2198
      png_uint_32 i;
2199
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2200
           pp = prev_row + 1; i < bpp; i++)
2201
      {
2202
         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2203
      }
2204
      for (lp = row_buf + 1; i < row_bytes; i++)
2205
      {
2206 2207
         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
                 & 0xff);
2208 2209 2210 2211 2212
      }
      best_row = png_ptr->avg_row;
   }

   else if (filter_to_do & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
2213
   {
G
Guy Schalnat 已提交
2214
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
2215
      png_uint_32 sum = 0, lmins = mins;
2216
      png_uint_32 i;
A
Andreas Dilger 已提交
2217 2218 2219 2220 2221
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2222
         int j;
A
Andreas Dilger 已提交
2223 2224 2225 2226
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

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

G
Guy Schalnat 已提交
2250
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2251
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2252
      {
2253
         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
G
Guy Schalnat 已提交
2254

G
Guy Schalnat 已提交
2255 2256
         sum += (v < 128) ? v : 256 - v;
      }
2257
      for (lp = row_buf + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2258
      {
2259
         v = *dp++ =
2260
          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
G
Guy Schalnat 已提交
2261

G
Guy Schalnat 已提交
2262
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
2263 2264 2265

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
2266
      }
A
Andreas Dilger 已提交
2267 2268 2269 2270

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
2271
         int j;
A
Andreas Dilger 已提交
2272 2273 2274 2275
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

2276
         for (j = 0; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2277
         {
2278
            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
A
Andreas Dilger 已提交
2279
            {
2280
               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2281
                  PNG_WEIGHT_SHIFT;
2282
               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
A
Andreas Dilger 已提交
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298
                  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 已提交
2299 2300 2301 2302 2303 2304
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
2305

A
Andreas Dilger 已提交
2306
   /* Paeth filter */
2307 2308 2309
   if (filter_to_do == PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
2310
      png_uint_32 i;
2311
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2312
           pp = prev_row + 1; i < bpp; i++)
2313
      {
2314
         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2315 2316
      }

2317
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2318 2319 2320
      {
         int a, b, c, pa, pb, pc, p;

2321 2322 2323
         b = *pp++;
         c = *cp++;
         a = *lp++;
2324

2325 2326
         p = b - c;
         pc = a - c;
2327 2328

#ifdef PNG_USE_ABS
2329 2330 2331
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2332
#else
2333 2334 2335
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2336 2337 2338 2339
#endif

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

2340
         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2341 2342 2343 2344 2345
      }
      best_row = png_ptr->paeth_row;
   }

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

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

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

G
Guy Schalnat 已提交
2383
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2384
           pp = prev_row + 1; i < bpp; i++)
G
Guy Schalnat 已提交
2385
      {
2386
         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
G
Guy Schalnat 已提交
2387

G
Guy Schalnat 已提交
2388 2389
         sum += (v < 128) ? v : 256 - v;
      }
2390

2391
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
G
Guy Schalnat 已提交
2392 2393
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
2394

2395 2396 2397
         b = *pp++;
         c = *cp++;
         a = *lp++;
2398 2399

#ifndef PNG_SLOW_PAETH
2400 2401
         p = b - c;
         pc = a - c;
2402
#ifdef PNG_USE_ABS
2403 2404 2405
         pa = abs(p);
         pb = abs(pc);
         pc = abs(p + pc);
2406
#else
2407 2408 2409
         pa = p < 0 ? -p : p;
         pb = pc < 0 ? -pc : pc;
         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2410 2411 2412
#endif
         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
2413
         p = a + b - c;
2414 2415 2416
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
2417 2418 2419 2420 2421 2422
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
2423
#endif /* PNG_SLOW_PAETH */
G
Guy Schalnat 已提交
2424

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

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

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

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

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

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

G
Guy Schalnat 已提交
2472
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
2473 2474 2475 2476 2477

#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)
   {
2478 2479
      int j;
      for (j = 1; j < num_p_filters; j++)
A
Andreas Dilger 已提交
2480
      {
2481
         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
A
Andreas Dilger 已提交
2482
      }
2483
      png_ptr->prev_filters[j] = best_row[0];
A
Andreas Dilger 已提交
2484 2485
   }
#endif
G
Guy Schalnat 已提交
2486
}
G
Guy Schalnat 已提交
2487

G
Guy Schalnat 已提交
2488

A
Andreas Dilger 已提交
2489
/* Do the actual writing of a previously filtered row. */
G
Guy Schalnat 已提交
2490 2491 2492
void
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
2493 2494
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
2495
   /* set up the zlib input buffer */
A
Andreas Dilger 已提交
2496 2497
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
2498 2499
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
2500
   {
G
Guy Schalnat 已提交
2501
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
2502

G
Guy Schalnat 已提交
2503
      /* compress the data */
A
Andreas Dilger 已提交
2504
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
2505 2506 2507
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
2508
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
2509
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
2510 2511 2512
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
2513

G
Guy Schalnat 已提交
2514
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
2515
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
2516 2517 2518
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
2519 2520
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
2521 2522
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
2523
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
2524

G
Guy Schalnat 已提交
2525
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
2526
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
2527 2528 2529 2530 2531 2532 2533 2534
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
2535 2536
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
2537

G
Guy Schalnat 已提交
2538 2539 2540 2541 2542 2543 2544
#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 已提交
2545
   }
2546
#endif
G
Guy Schalnat 已提交
2547
}