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

A
Andreas Dilger 已提交
2
/* pngwutil.c - utilities to write a PNG file
3 4 5 6 7 8 9
 *
 * libpng 1.00.97
 * 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
 * May 28, 1997
 */
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
{
A
Andreas Dilger 已提交
130 131
   /* write the rest of the 8 byte signature */
   png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
A
Andreas Dilger 已提交
132
      (png_size_t)8 - png_ptr->sig_bytes);
G
Guy Schalnat 已提交
133 134 135
}

/* Write the IHDR chunk, and update the png_struct with the necessary
136 137 138
 * information.  Note that the rest of this code depends upon this
 * information being correct.
 */
G
Guy Schalnat 已提交
139
void
G
Guy Schalnat 已提交
140
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
G
Guy Schalnat 已提交
141 142 143 144 145
   int bit_depth, int color_type, int compression_type, int filter_type,
   int interlace_type)
{
   png_byte buf[13]; /* buffer to store the IHDR info */

A
Andreas Dilger 已提交
146
   png_debug(1, "in png_write_IHDR\n");
G
Guy Schalnat 已提交
147
   /* Check that we have valid input data from the application info */
G
Guy Schalnat 已提交
148 149
   switch (color_type)
   {
A
Andreas Dilger 已提交
150
      case PNG_COLOR_TYPE_GRAY:
G
Guy Schalnat 已提交
151 152 153 154 155 156 157
         switch (bit_depth)
         {
            case 1:
            case 2:
            case 4:
            case 8:
            case 16: png_ptr->channels = 1; break;
A
Andreas Dilger 已提交
158
            default: png_error(png_ptr,"Invalid bit depth for grayscale image");
G
Guy Schalnat 已提交
159
         }
G
Guy Schalnat 已提交
160
         break;
A
Andreas Dilger 已提交
161
      case PNG_COLOR_TYPE_RGB:
G
Guy Schalnat 已提交
162 163
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGB image");
G
Guy Schalnat 已提交
164 165
         png_ptr->channels = 3;
         break;
A
Andreas Dilger 已提交
166
      case PNG_COLOR_TYPE_PALETTE:
G
Guy Schalnat 已提交
167 168 169 170 171 172 173 174 175
         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 已提交
176
      case PNG_COLOR_TYPE_GRAY_ALPHA:
G
Guy Schalnat 已提交
177 178
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
G
Guy Schalnat 已提交
179 180
         png_ptr->channels = 2;
         break;
A
Andreas Dilger 已提交
181
      case PNG_COLOR_TYPE_RGB_ALPHA:
G
Guy Schalnat 已提交
182 183
         if (bit_depth != 8 && bit_depth != 16)
            png_error(png_ptr, "Invalid bit depth for RGBA image");
G
Guy Schalnat 已提交
184 185
         png_ptr->channels = 4;
         break;
G
Guy Schalnat 已提交
186 187 188 189
      default:
         png_error(png_ptr, "Invalid image color type specified");
   }

A
Andreas Dilger 已提交
190
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
G
Guy Schalnat 已提交
191 192
   {
      png_warning(png_ptr, "Invalid compression type specified");
A
Andreas Dilger 已提交
193
      compression_type = PNG_COMPRESSION_TYPE_BASE;
G
Guy Schalnat 已提交
194 195
   }

A
Andreas Dilger 已提交
196
   if (filter_type != PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
197 198
   {
      png_warning(png_ptr, "Invalid filter type specified");
A
Andreas Dilger 已提交
199
      filter_type = PNG_FILTER_TYPE_BASE;
G
Guy Schalnat 已提交
200 201
   }

A
Andreas Dilger 已提交
202 203
   if (interlace_type != PNG_INTERLACE_NONE &&
      interlace_type != PNG_INTERLACE_ADAM7)
G
Guy Schalnat 已提交
204 205
   {
      png_warning(png_ptr, "Invalid interlace type specified");
A
Andreas Dilger 已提交
206
      interlace_type = PNG_INTERLACE_ADAM7;
G
Guy Schalnat 已提交
207
   }
G
Guy Schalnat 已提交
208 209 210 211 212 213 214 215

   /* 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 已提交
216
   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
A
Andreas Dilger 已提交
217
   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
G
Guy Schalnat 已提交
218 219 220
   /* 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 已提交
221 222 223 224 225 226 227 228 229 230
   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 已提交
231 232

   /* write the chunk */
A
Andreas Dilger 已提交
233
   png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
G
Guy Schalnat 已提交
234

A
Andreas Dilger 已提交
235
   /* initialize zlib with PNG info */
A
Andreas Dilger 已提交
236 237 238
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
239
   if (!(png_ptr->do_filter))
G
Guy Schalnat 已提交
240
   {
A
Andreas Dilger 已提交
241 242
      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
         png_ptr->bit_depth < 8)
G
Guy Schalnat 已提交
243
         png_ptr->do_filter = PNG_FILTER_NONE;
G
Guy Schalnat 已提交
244
      else
G
Guy Schalnat 已提交
245
         png_ptr->do_filter = PNG_ALL_FILTERS;
G
Guy Schalnat 已提交
246
   }
G
Guy Schalnat 已提交
247
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
G
Guy Schalnat 已提交
248
   {
G
Guy Schalnat 已提交
249
      if (png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
250 251 252 253
         png_ptr->zlib_strategy = Z_FILTERED;
      else
         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
   }
G
Guy Schalnat 已提交
254
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
G
Guy Schalnat 已提交
255
      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
G
Guy Schalnat 已提交
256
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
G
Guy Schalnat 已提交
257
      png_ptr->zlib_mem_level = 8;
G
Guy Schalnat 已提交
258
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
G
Guy Schalnat 已提交
259
      png_ptr->zlib_window_bits = 15;
G
Guy Schalnat 已提交
260
   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
G
Guy Schalnat 已提交
261
      png_ptr->zlib_method = 8;
A
Andreas Dilger 已提交
262
   deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
A
Andreas Dilger 已提交
263 264
      png_ptr->zlib_method, png_ptr->zlib_window_bits,
      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
A
Andreas Dilger 已提交
265 266
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
267

G
Guy Schalnat 已提交
268
   png_ptr->mode = PNG_HAVE_IHDR;
G
Guy Schalnat 已提交
269 270 271
}

/* write the palette.  We are careful not to trust png_color to be in the
272 273 274
 * correct order for PNG, so people can redefine it to any convient
 * structure.
 */
G
Guy Schalnat 已提交
275
void
A
Andreas Dilger 已提交
276
png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
G
Guy Schalnat 已提交
277
{
A
Andreas Dilger 已提交
278
   png_uint_32 i;
G
Guy Schalnat 已提交
279
   png_colorp pal_ptr;
G
Guy Schalnat 已提交
280 281
   png_byte buf[3];

A
Andreas Dilger 已提交
282 283
   png_debug(1, "in png_write_PLTE\n");
   if (num_pal == 0 || num_pal > 256)
G
Guy Schalnat 已提交
284 285 286 287 288 289 290 291 292 293 294 295
   {
      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;
      }
   }

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

A
Andreas Dilger 已提交
299 300
   png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
G
Guy Schalnat 已提交
301 302 303 304
   {
      buf[0] = pal_ptr->red;
      buf[1] = pal_ptr->green;
      buf[2] = pal_ptr->blue;
A
Andreas Dilger 已提交
305
      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
G
Guy Schalnat 已提交
306 307
   }
   png_write_chunk_end(png_ptr);
G
Guy Schalnat 已提交
308
   png_ptr->mode |= PNG_HAVE_PLTE;
G
Guy Schalnat 已提交
309 310 311 312
}

/* write an IDAT chunk */
void
A
Andreas Dilger 已提交
313
png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
G
Guy Schalnat 已提交
314
{
A
Andreas Dilger 已提交
315
   png_debug(1, "in png_write_IDAT\n");
G
Guy Schalnat 已提交
316
   png_write_chunk(png_ptr, png_IDAT, data, length);
G
Guy Schalnat 已提交
317
   png_ptr->mode |= PNG_HAVE_IDAT;
G
Guy Schalnat 已提交
318 319 320 321
}

/* write an IEND chunk */
void
G
Guy Schalnat 已提交
322
png_write_IEND(png_structp png_ptr)
G
Guy Schalnat 已提交
323
{
A
Andreas Dilger 已提交
324 325
   png_debug(1, "in png_write_IEND\n");
   png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
A
Andreas Dilger 已提交
326
   png_ptr->mode |= PNG_HAVE_IEND;
G
Guy Schalnat 已提交
327 328
}

G
Guy Schalnat 已提交
329
#if defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
330 331
/* write a gAMA chunk */
void
A
Andreas Dilger 已提交
332
png_write_gAMA(png_structp png_ptr, double file_gamma)
G
Guy Schalnat 已提交
333 334 335 336
{
   png_uint_32 igamma;
   png_byte buf[4];

A
Andreas Dilger 已提交
337 338 339
   png_debug(1, "in png_write_gAMA\n");
   /* file_gamma is saved in 1/100,000ths */
   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
G
Guy Schalnat 已提交
340
   png_save_uint_32(buf, igamma);
A
Andreas Dilger 已提交
341
   png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
G
Guy Schalnat 已提交
342
}
G
Guy Schalnat 已提交
343
#endif
G
Guy Schalnat 已提交
344

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
#if defined(PNG_WRITE_sRGB_SUPPORTED)
/* write a sRGB chunk */
void
png_write_sRGB(png_structp png_ptr, png_byte srgb_intent)
{
   png_byte buf[1];

   png_debug(1, "in png_write_sRGB\n");
   if(srgb_intent > 3)
         png_warning(png_ptr,
            "Invalid sRGB rendering intent specified");
   buf[0]=srgb_intent;
   png_write_chunk(png_ptr, png_sRGB, buf, (png_size_t)1);
}
#endif

G
Guy Schalnat 已提交
361
#if defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
362 363
/* write the sBIT chunk */
void
G
Guy Schalnat 已提交
364
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
G
Guy Schalnat 已提交
365 366
{
   png_byte buf[4];
A
Andreas Dilger 已提交
367
   png_size_t size;
G
Guy Schalnat 已提交
368

A
Andreas Dilger 已提交
369
   png_debug(1, "in png_write_sBIT\n");
G
Guy Schalnat 已提交
370
   /* make sure we don't depend upon the order of PNG_COLOR_8 */
G
Guy Schalnat 已提交
371 372
   if (color_type & PNG_COLOR_MASK_COLOR)
   {
G
Guy Schalnat 已提交
373 374 375 376 377 378 379 380 381 382
      int maxbits;

      maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
      if (sbit->red == 0 || sbit->red > maxbits || 
          sbit->green == 0 || sbit->green > maxbits || 
          sbit->blue == 0 || sbit->blue > maxbits)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
383 384 385 386 387 388 389
      buf[0] = sbit->red;
      buf[1] = sbit->green;
      buf[2] = sbit->blue;
      size = 3;
   }
   else
   {
G
Guy Schalnat 已提交
390 391 392 393 394
      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
395 396 397 398 399 400
      buf[0] = sbit->gray;
      size = 1;
   }

   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
G
Guy Schalnat 已提交
401 402 403 404 405
      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
      {
         png_warning(png_ptr, "Invalid sBIT depth specified");
         return;
      }
G
Guy Schalnat 已提交
406 407 408
      buf[size++] = sbit->alpha;
   }

A
Andreas Dilger 已提交
409
   png_write_chunk(png_ptr, png_sBIT, buf, size);
G
Guy Schalnat 已提交
410
}
G
Guy Schalnat 已提交
411
#endif
G
Guy Schalnat 已提交
412

G
Guy Schalnat 已提交
413
#if defined(PNG_WRITE_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
414 415
/* write the cHRM chunk */
void
A
Andreas Dilger 已提交
416
png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
G
Guy Schalnat 已提交
417 418
   double red_x, double red_y, double green_x, double green_y,
   double blue_x, double blue_y)
G
Guy Schalnat 已提交
419 420 421 422
{
   png_uint_32 itemp;
   png_byte buf[32];

A
Andreas Dilger 已提交
423
   png_debug(1, "in png_write_cHRM\n");
G
Guy Schalnat 已提交
424
   /* each value is saved int 1/100,000ths */
G
Guy Schalnat 已提交
425 426 427 428 429 430
   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");
      return;
   }
G
Guy Schalnat 已提交
431 432 433 434
   itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
   png_save_uint_32(buf, itemp);
   itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
   png_save_uint_32(buf + 4, itemp);
G
Guy Schalnat 已提交
435 436 437 438 439 440 441

   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;
   }
G
Guy Schalnat 已提交
442 443 444 445
   itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
   png_save_uint_32(buf + 8, itemp);
   itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
   png_save_uint_32(buf + 12, itemp);
G
Guy Schalnat 已提交
446 447 448 449 450 451 452

   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;
   }
G
Guy Schalnat 已提交
453 454 455 456
   itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
   png_save_uint_32(buf + 16, itemp);
   itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
   png_save_uint_32(buf + 20, itemp);
G
Guy Schalnat 已提交
457 458 459 460 461 462 463

   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;
   }
G
Guy Schalnat 已提交
464 465 466 467
   itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
   png_save_uint_32(buf + 24, itemp);
   itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
   png_save_uint_32(buf + 28, itemp);
G
Guy Schalnat 已提交
468

A
Andreas Dilger 已提交
469
   png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
G
Guy Schalnat 已提交
470
}
G
Guy Schalnat 已提交
471
#endif
G
Guy Schalnat 已提交
472

G
Guy Schalnat 已提交
473
#if defined(PNG_WRITE_tRNS_SUPPORTED)
G
Guy Schalnat 已提交
474 475
/* write the tRNS chunk */
void
G
Guy Schalnat 已提交
476
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
G
Guy Schalnat 已提交
477 478 479 480
   int num_trans, int color_type)
{
   png_byte buf[6];

A
Andreas Dilger 已提交
481
   png_debug(1, "in png_write_tRNS\n");
G
Guy Schalnat 已提交
482 483
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
G
Guy Schalnat 已提交
484 485 486 487 488
      if (num_trans <= 0 || num_trans > png_ptr->num_palette)
      {
         png_warning(png_ptr,"Invalid number of transparent colors specified");
         return;
      }
G
Guy Schalnat 已提交
489
      /* write the chunk out as it is */
A
Andreas Dilger 已提交
490
      png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
G
Guy Schalnat 已提交
491 492 493 494 495
   }
   else if (color_type == PNG_COLOR_TYPE_GRAY)
   {
      /* one 16 bit value */
      png_save_uint_16(buf, tran->gray);
A
Andreas Dilger 已提交
496
      png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
G
Guy Schalnat 已提交
497 498 499 500 501 502 503
   }
   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);
A
Andreas Dilger 已提交
504
      png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
G
Guy Schalnat 已提交
505
   }
G
Guy Schalnat 已提交
506 507 508 509
   else
   {
      png_warning(png_ptr, "Can't write tRNS with and alpha channel");
   }
G
Guy Schalnat 已提交
510
}
G
Guy Schalnat 已提交
511
#endif
G
Guy Schalnat 已提交
512

G
Guy Schalnat 已提交
513
#if defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
514 515
/* write the background chunk */
void
G
Guy Schalnat 已提交
516
png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
G
Guy Schalnat 已提交
517 518 519
{
   png_byte buf[6];

A
Andreas Dilger 已提交
520
   png_debug(1, "in png_write_bKGD\n");
G
Guy Schalnat 已提交
521 522
   if (color_type == PNG_COLOR_TYPE_PALETTE)
   {
G
Guy Schalnat 已提交
523 524 525 526 527
      if (back->index > png_ptr->num_palette)
      {
         png_warning(png_ptr, "Invalid background palette index");
         return;
      }
G
Guy Schalnat 已提交
528
      buf[0] = back->index;
A
Andreas Dilger 已提交
529
      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
G
Guy Schalnat 已提交
530 531 532 533 534 535
   }
   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);
A
Andreas Dilger 已提交
536
      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
G
Guy Schalnat 已提交
537 538
   }
   else
G
Guy Schalnat 已提交
539
   {
G
Guy Schalnat 已提交
540
      png_save_uint_16(buf, back->gray);
A
Andreas Dilger 已提交
541
      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
G
Guy Schalnat 已提交
542 543
   }
}
G
Guy Schalnat 已提交
544
#endif
G
Guy Schalnat 已提交
545

G
Guy Schalnat 已提交
546
#if defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
547 548
/* write the histogram */
void
A
Andreas Dilger 已提交
549
png_write_hIST(png_structp png_ptr, png_uint_16p hist, png_uint_32 num_hist)
G
Guy Schalnat 已提交
550
{
A
Andreas Dilger 已提交
551
   png_uint_32 i;
G
Guy Schalnat 已提交
552 553
   png_byte buf[3];

A
Andreas Dilger 已提交
554 555
   png_debug(1, "in png_write_hIST\n");
   if (num_hist > png_ptr->num_palette)
G
Guy Schalnat 已提交
556
   {
A
Andreas Dilger 已提交
557 558
      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
         png_ptr->num_palette);
G
Guy Schalnat 已提交
559 560 561 562
      png_warning(png_ptr, "Invalid number of histogram entries specified");
      return;
   }

A
Andreas Dilger 已提交
563 564
   png_write_chunk_start(png_ptr, png_hIST, num_hist * 2);
   for (i = 0; i < num_hist; i++)
G
Guy Schalnat 已提交
565
   {
G
Guy Schalnat 已提交
566
      png_save_uint_16(buf, hist[i]);
A
Andreas Dilger 已提交
567
      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
G
Guy Schalnat 已提交
568 569 570
   }
   png_write_chunk_end(png_ptr);
}
G
Guy Schalnat 已提交
571
#endif
G
Guy Schalnat 已提交
572

A
Andreas Dilger 已提交
573 574 575 576 577 578
#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
/* 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 已提交
579 580 581 582
 *
 * 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 已提交
583
 */
A
Andreas Dilger 已提交
584
png_size_t
585
png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
A
Andreas Dilger 已提交
586
{
A
Andreas Dilger 已提交
587
   png_size_t key_len;
588
   png_charp kp, dp;
A
Andreas Dilger 已提交
589 590
   int kflag;

A
Andreas Dilger 已提交
591 592 593 594
   png_debug(1, "in png_check_keyword\n");
   *new_key = NULL;

   if (key == NULL || (key_len = png_strlen(key)) == 0)
A
Andreas Dilger 已提交
595 596 597 598 599 600 601
   {
      char msg[40];

      sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
      png_warning(png_ptr, msg);
      return 0;
   }
A
Andreas Dilger 已提交
602 603 604

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

605
   *new_key = (png_charp)png_malloc(png_ptr, key_len + 1);
A
Andreas Dilger 已提交
606 607 608

   /* Replace non-printing characters with a blank and print a warning */
   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
A
Andreas Dilger 已提交
609
   {
610
      if (*kp < 0x20 || (*kp > 0x7E && *kp < 0xA1))
A
Andreas Dilger 已提交
611 612
      {
         char msg[40];
A
Andreas Dilger 已提交
613

A
Andreas Dilger 已提交
614 615 616 617 618 619 620 621 622
         sprintf(msg, "Invalid %s keyword character 0x%02X",
            png_ptr->chunk_name, *kp);
         png_warning(png_ptr, msg);
         *dp = ' ';
      }
      else
      {
         *dp = *kp;
      }
A
Andreas Dilger 已提交
623
   }
A
Andreas Dilger 已提交
624
   *dp = '\0';
A
Andreas Dilger 已提交
625

A
Andreas Dilger 已提交
626 627 628
   /* Remove any trailing white space. */
   kp = *new_key + key_len - 1;
   if (*kp == ' ')
A
Andreas Dilger 已提交
629
   {
A
Andreas Dilger 已提交
630 631 632 633 634 635 636 637 638 639 640
      char msg[50];
      sprintf(msg, "Trailing spaces removed from %s keyword",
         png_ptr->chunk_name);

      png_warning(png_ptr, msg);

      while (*kp == ' ')
      {
        *(kp--) = '\0';
        key_len--;
      }
A
Andreas Dilger 已提交
641 642 643
   }

   /* Remove any leading white space. */
A
Andreas Dilger 已提交
644 645
   kp = *new_key;
   if (*kp == ' ')
A
Andreas Dilger 已提交
646
   {
A
Andreas Dilger 已提交
647 648 649 650 651 652 653 654 655 656 657
      char msg[50];
      sprintf(msg, "Leading spaces removed from %s keyword",
         png_ptr->chunk_name);

      png_warning(png_ptr, msg);

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

A
Andreas Dilger 已提交
660 661 662 663
   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 已提交
664
   {
A
Andreas Dilger 已提交
665
      if (*kp == ' ' && kflag == 0)
A
Andreas Dilger 已提交
666
      {
A
Andreas Dilger 已提交
667 668
         *(dp++) = *kp;
         kflag = 1;
A
Andreas Dilger 已提交
669
      }
A
Andreas Dilger 已提交
670
      else if (*kp == ' ')
A
Andreas Dilger 已提交
671 672 673 674 675
      {
         key_len--;
      }
      else
      {
A
Andreas Dilger 已提交
676 677
         *(dp++) = *kp;
         kflag = 0;
A
Andreas Dilger 已提交
678 679
      }
   }
A
Andreas Dilger 已提交
680
   *dp = '\0';
A
Andreas Dilger 已提交
681 682

   if (key_len == 0)
A
Andreas Dilger 已提交
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
   {
      char msg[40];

      sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
      png_warning(png_ptr, msg);
   }

   if (key_len > 79)
   {
      char msg[50];

      sprintf(msg, "%s keyword length must be 1 - 79 characters",
         png_ptr->chunk_name);
      png_warning(png_ptr, msg);
      new_key[79] = '\0';
      key_len = 79;
   }
A
Andreas Dilger 已提交
700 701 702 703 704

   return key_len;
}
#endif

G
Guy Schalnat 已提交
705
#if defined(PNG_WRITE_tEXt_SUPPORTED)
G
Guy Schalnat 已提交
706 707
/* write a tEXt chunk */
void
G
Guy Schalnat 已提交
708
png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
709
   png_size_t text_len)
G
Guy Schalnat 已提交
710
{
A
Andreas Dilger 已提交
711
   png_size_t key_len;
712
   png_charp new_key;
A
Andreas Dilger 已提交
713 714 715 716 717

   png_debug(1, "in png_write_tEXt\n");
   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
      char msg[40];
G
Guy Schalnat 已提交
718

A
Andreas Dilger 已提交
719 720
      sprintf(msg, "Empty keyword in %s chunk", "tEXt");
      png_warning(png_ptr, msg);
G
Guy Schalnat 已提交
721
      return;
A
Andreas Dilger 已提交
722
   }
G
Guy Schalnat 已提交
723

A
Andreas Dilger 已提交
724
   if (text == NULL || *text == '\0')
A
Andreas Dilger 已提交
725 726 727
      text_len = 0;

   /* make sure we include the 0 after the key */
A
Andreas Dilger 已提交
728
   png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
729
   png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
A
Andreas Dilger 已提交
730
   if (text_len)
A
Andreas Dilger 已提交
731
      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
A
Andreas Dilger 已提交
732

G
Guy Schalnat 已提交
733
   png_write_chunk_end(png_ptr);
A
Andreas Dilger 已提交
734
   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
735
}
G
Guy Schalnat 已提交
736
#endif
G
Guy Schalnat 已提交
737

G
Guy Schalnat 已提交
738
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
739
/* write a compressed text chunk */
G
Guy Schalnat 已提交
740
void
G
Guy Schalnat 已提交
741
png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
A
Andreas Dilger 已提交
742
   png_size_t text_len, int compression)
G
Guy Schalnat 已提交
743
{
A
Andreas Dilger 已提交
744
   png_size_t key_len;
G
Guy Schalnat 已提交
745
   char buf[1];
746
   png_charp new_key;
G
Guy Schalnat 已提交
747
   int i, ret;
G
Guy Schalnat 已提交
748
   png_charpp output_ptr = NULL; /* array of pointers to output */
G
Guy Schalnat 已提交
749 750 751
   int num_output_ptr = 0; /* number of output pointers used */
   int max_output_ptr = 0; /* size of output_ptr */

A
Andreas Dilger 已提交
752 753 754 755 756 757 758 759
   png_debug(1, "in png_write_zTXt\n");

   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
   {
      char msg[40];

      sprintf(msg, "Empty keyword in %s chunk", "zTXt");
      png_warning(png_ptr, msg);
G
Guy Schalnat 已提交
760
      return;
A
Andreas Dilger 已提交
761
   }
A
Andreas Dilger 已提交
762

A
Andreas Dilger 已提交
763 764 765 766 767 768 769 770
   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;
   }

   png_free(png_ptr, new_key);
G
Guy Schalnat 已提交
771

A
Andreas Dilger 已提交
772
   if (compression >= PNG_TEXT_COMPRESSION_LAST)
G
Guy Schalnat 已提交
773
   {
A
Andreas Dilger 已提交
774 775 776 777
      char msg[50];
      sprintf(msg, "Unknown zTXt compression type %d", compression);
      png_warning(png_ptr, msg);
      compression = PNG_TEXT_COMPRESSION_zTXt;
G
Guy Schalnat 已提交
778 779
   }

A
Andreas Dilger 已提交
780 781 782 783 784 785 786 787 788 789 790 791 792 793
   /* 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).
    */
G
Guy Schalnat 已提交
794 795

   /* set up the compression buffers */
A
Andreas Dilger 已提交
796 797 798 799
   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;
G
Guy Schalnat 已提交
800

G
Guy Schalnat 已提交
801
   /* this is the same compression loop as in png_write_row() */
G
Guy Schalnat 已提交
802 803 804
   do
   {
      /* compress the data */
A
Andreas Dilger 已提交
805
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
806 807 808
      if (ret != Z_OK)
      {
         /* error */
A
Andreas Dilger 已提交
809
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
810
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
811
         else
G
Guy Schalnat 已提交
812
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
813 814
      }
      /* check to see if we need more room */
A
Andreas Dilger 已提交
815
      if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
G
Guy Schalnat 已提交
816 817 818
      {
         /* make sure the output array has room */
         if (num_output_ptr >= max_output_ptr)
G
Guy Schalnat 已提交
819
         {
A
Andreas Dilger 已提交
820
            int old_max;
G
Guy Schalnat 已提交
821 822

            old_max = max_output_ptr;
G
Guy Schalnat 已提交
823
            max_output_ptr = num_output_ptr + 4;
A
Andreas Dilger 已提交
824
            if (output_ptr != NULL)
G
Guy Schalnat 已提交
825 826 827 828
            {
               png_charpp old_ptr;

               old_ptr = output_ptr;
A
Andreas Dilger 已提交
829
               output_ptr = (png_charpp)png_malloc(png_ptr,
G
Guy Schalnat 已提交
830
                  max_output_ptr * sizeof (png_charpp));
A
Andreas Dilger 已提交
831
               png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
A
Andreas Dilger 已提交
832
               png_free(png_ptr, old_ptr);
G
Guy Schalnat 已提交
833 834
            }
            else
A
Andreas Dilger 已提交
835
               output_ptr = (png_charpp)png_malloc(png_ptr,
G
Guy Schalnat 已提交
836
                  max_output_ptr * sizeof (png_charp));
G
Guy Schalnat 已提交
837 838 839
         }

         /* save the data */
A
Andreas Dilger 已提交
840
         output_ptr[num_output_ptr] = png_malloc(png_ptr, png_ptr->zbuf_size);
G
Guy Schalnat 已提交
841
         png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
A
Andreas Dilger 已提交
842
            png_ptr->zbuf_size);
G
Guy Schalnat 已提交
843 844 845
         num_output_ptr++;

         /* and reset the buffer */
A
Andreas Dilger 已提交
846 847
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
848 849
      }
   /* continue until we don't have anymore to compress */
A
Andreas Dilger 已提交
850
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
851

G
Guy Schalnat 已提交
852
   /* finish the compression */
G
Guy Schalnat 已提交
853 854 855
   do
   {
      /* tell zlib we are finished */
A
Andreas Dilger 已提交
856
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
857 858 859
      if (ret != Z_OK && ret != Z_STREAM_END)
      {
         /* we got an error */
A
Andreas Dilger 已提交
860
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
861
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
862
         else
G
Guy Schalnat 已提交
863
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
864 865 866
      }

      /* check to see if we need more room */
A
Andreas Dilger 已提交
867
      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
G
Guy Schalnat 已提交
868
      {
G
Guy Schalnat 已提交
869 870
         /* check to make sure our output array has room */
         if (num_output_ptr >= max_output_ptr)
G
Guy Schalnat 已提交
871
         {
A
Andreas Dilger 已提交
872
            int old_max;
G
Guy Schalnat 已提交
873 874

            old_max = max_output_ptr;
G
Guy Schalnat 已提交
875
            max_output_ptr = num_output_ptr + 4;
A
Andreas Dilger 已提交
876
            if (output_ptr != NULL)
G
Guy Schalnat 已提交
877 878 879 880
            {
               png_charpp old_ptr;

               old_ptr = output_ptr;
A
Andreas Dilger 已提交
881
               /* This could be optimized to realloc() */
A
Andreas Dilger 已提交
882
               output_ptr = (png_charpp)png_malloc(png_ptr,
G
Guy Schalnat 已提交
883
                  max_output_ptr * sizeof (png_charpp));
A
Andreas Dilger 已提交
884
               png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
A
Andreas Dilger 已提交
885
               png_free(png_ptr, old_ptr);
G
Guy Schalnat 已提交
886 887
            }
            else
A
Andreas Dilger 已提交
888
               output_ptr = (png_charpp)png_malloc(png_ptr,
G
Guy Schalnat 已提交
889 890 891 892
                  max_output_ptr * sizeof (png_charp));
         }

         /* save off the data */
A
Andreas Dilger 已提交
893
         output_ptr[num_output_ptr] = png_malloc(png_ptr,
G
Guy Schalnat 已提交
894 895
            png_ptr->zbuf_size);
         png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
A
Andreas Dilger 已提交
896
            png_ptr->zbuf_size);
G
Guy Schalnat 已提交
897 898 899
         num_output_ptr++;

         /* and reset the buffer pointers */
A
Andreas Dilger 已提交
900 901
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
902 903 904 905
      }
   } while (ret != Z_STREAM_END);

   /* text length is number of buffers plus last buffer */
G
Guy Schalnat 已提交
906
   text_len = png_ptr->zbuf_size * num_output_ptr;
A
Andreas Dilger 已提交
907
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
A
Andreas Dilger 已提交
908
      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
G
Guy Schalnat 已提交
909 910

   /* write start of chunk */
A
Andreas Dilger 已提交
911
   png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)(key_len+text_len+2));
G
Guy Schalnat 已提交
912
   /* write key */
A
Andreas Dilger 已提交
913
   png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
G
Guy Schalnat 已提交
914
   buf[0] = (png_byte)compression;
G
Guy Schalnat 已提交
915
   /* write compression */
A
Andreas Dilger 已提交
916
   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
G
Guy Schalnat 已提交
917 918 919 920

   /* write saved output buffers, if any */
   for (i = 0; i < num_output_ptr; i++)
   {
A
Andreas Dilger 已提交
921
      png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
A
Andreas Dilger 已提交
922
      png_free(png_ptr, output_ptr[i]);
G
Guy Schalnat 已提交
923
   }
A
Andreas Dilger 已提交
924
   if (max_output_ptr != 0)
A
Andreas Dilger 已提交
925
      png_free(png_ptr, output_ptr);
G
Guy Schalnat 已提交
926
   /* write anything left in zbuf */
A
Andreas Dilger 已提交
927
   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
G
Guy Schalnat 已提交
928
      png_write_chunk_data(png_ptr, png_ptr->zbuf,
A
Andreas Dilger 已提交
929
         png_ptr->zbuf_size - png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
930 931 932 933
   /* close the chunk */
   png_write_chunk_end(png_ptr);

   /* reset zlib for another zTXt or the image data */
A
Andreas Dilger 已提交
934
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
935
}
G
Guy Schalnat 已提交
936
#endif
G
Guy Schalnat 已提交
937

A
Andreas Dilger 已提交
938 939 940

#if defined(PNG_WRITE_oFFs_SUPPORTED)
/* write the oFFs chunk */
G
Guy Schalnat 已提交
941
void
A
Andreas Dilger 已提交
942 943
png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
   png_uint_32 y_offset,
G
Guy Schalnat 已提交
944 945 946 947
   int unit_type)
{
   png_byte buf[9];

A
Andreas Dilger 已提交
948 949 950
   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 已提交
951

A
Andreas Dilger 已提交
952 953
   png_save_uint_32(buf, x_offset);
   png_save_uint_32(buf + 4, y_offset);
G
Guy Schalnat 已提交
954
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
955

A
Andreas Dilger 已提交
956
   png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
957
}
G
Guy Schalnat 已提交
958
#endif
G
Guy Schalnat 已提交
959

A
Andreas Dilger 已提交
960 961
#if defined(PNG_WRITE_pCAL_SUPPORTED)
/* write the pCAL chunk (png-scivis-19970203) */
G
Guy Schalnat 已提交
962
void
A
Andreas Dilger 已提交
963 964 965 966 967 968
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)
{
   png_size_t purpose_len, units_len, total_len; 
   png_uint_32p params_len;
   png_byte buf[10];
969
   png_charp new_purpose;
A
Andreas Dilger 已提交
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
   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;

   params_len = (png_uint_32p)png_malloc(png_ptr, nparams*sizeof(png_uint_32));

   /* 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);
   png_write_chunk_start(png_ptr, png_pCAL, total_len);
995
   png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
A
Andreas Dilger 已提交
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
   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]);
   }

   png_write_chunk_end(png_ptr);
}
#endif

#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 已提交
1020 1021 1022 1023
   int unit_type)
{
   png_byte buf[9];

A
Andreas Dilger 已提交
1024 1025 1026
   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 已提交
1027

A
Andreas Dilger 已提交
1028 1029
   png_save_uint_32(buf, x_pixels_per_unit);
   png_save_uint_32(buf + 4, y_pixels_per_unit);
G
Guy Schalnat 已提交
1030
   buf[8] = (png_byte)unit_type;
G
Guy Schalnat 已提交
1031

A
Andreas Dilger 已提交
1032
   png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
G
Guy Schalnat 已提交
1033
}
G
Guy Schalnat 已提交
1034
#endif
G
Guy Schalnat 已提交
1035

G
Guy Schalnat 已提交
1036
#if defined(PNG_WRITE_tIME_SUPPORTED)
1037 1038 1039
/* 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 已提交
1040
void
G
Guy Schalnat 已提交
1041
png_write_tIME(png_structp png_ptr, png_timep mod_time)
G
Guy Schalnat 已提交
1042 1043 1044
{
   png_byte buf[7];

A
Andreas Dilger 已提交
1045
   png_debug(1, "in png_write_tIME\n");
G
Guy Schalnat 已提交
1046 1047 1048 1049 1050 1051 1052 1053
   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 已提交
1054 1055 1056 1057 1058 1059 1060
   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;

A
Andreas Dilger 已提交
1061
   png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
G
Guy Schalnat 已提交
1062
}
G
Guy Schalnat 已提交
1063
#endif
G
Guy Schalnat 已提交
1064 1065 1066

/* initializes the row writing capability of libpng */
void
G
Guy Schalnat 已提交
1067
png_write_start_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1068
{
A
Andreas Dilger 已提交
1069 1070 1071 1072 1073 1074
   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 已提交
1075
   /* set up row buffer */
A
Andreas Dilger 已提交
1076 1077
   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
G
Guy Schalnat 已提交
1078 1079 1080

   /* set up filtering buffer, if using this filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
G
Guy Schalnat 已提交
1081
   {
A
Andreas Dilger 已提交
1082
      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
G
Guy Schalnat 已提交
1083
         png_ptr->rowbytes + 1);
A
Andreas Dilger 已提交
1084
      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1085 1086
   }

A
Andreas Dilger 已提交
1087
   /* We only need to keep the previous row if we are using one of these. */
G
Guy Schalnat 已提交
1088 1089 1090
   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
   {
     /* set up previous row buffer */
A
Andreas Dilger 已提交
1091 1092
      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, buf_size);
      png_memset(png_ptr->prev_row, 0, buf_size);
G
Guy Schalnat 已提交
1093 1094 1095

      if (png_ptr->do_filter & PNG_FILTER_UP)
      {
A
Andreas Dilger 已提交
1096
         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
G
Guy Schalnat 已提交
1097
            png_ptr->rowbytes + 1);
A
Andreas Dilger 已提交
1098
         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1099 1100 1101 1102
      }

      if (png_ptr->do_filter & PNG_FILTER_AVG)
      {
A
Andreas Dilger 已提交
1103
         png_ptr->avg_row = (png_bytep )png_malloc(png_ptr,
G
Guy Schalnat 已提交
1104
            png_ptr->rowbytes + 1);
A
Andreas Dilger 已提交
1105
         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1106 1107 1108 1109
      }

      if (png_ptr->do_filter & PNG_FILTER_PAETH)
      {
A
Andreas Dilger 已提交
1110
         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
G
Guy Schalnat 已提交
1111
            png_ptr->rowbytes + 1);
A
Andreas Dilger 已提交
1112
         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1113
      }
G
Guy Schalnat 已提交
1114 1115 1116
   }

   /* if interlaced, we need to set up width and height of pass */
G
Guy Schalnat 已提交
1117
   if (png_ptr->interlaced)
G
Guy Schalnat 已提交
1118 1119 1120 1121 1122
   {
      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 已提交
1123 1124
         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
            png_pass_start[0]) / png_pass_inc[0];
G
Guy Schalnat 已提交
1125 1126 1127 1128 1129 1130 1131 1132
      }
      else
      {
         png_ptr->num_rows = png_ptr->height;
         png_ptr->usr_width = png_ptr->width;
      }
   }
   else
G
Guy Schalnat 已提交
1133
   {
G
Guy Schalnat 已提交
1134 1135 1136
      png_ptr->num_rows = png_ptr->height;
      png_ptr->usr_width = png_ptr->width;
   }
A
Andreas Dilger 已提交
1137 1138
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
   png_ptr->zstream.next_out = png_ptr->zbuf;
G
Guy Schalnat 已提交
1139 1140
}

A
Andreas Dilger 已提交
1141
/* Internal use only.  Called when finished processing a row of data. */
G
Guy Schalnat 已提交
1142
void
G
Guy Schalnat 已提交
1143
png_write_finish_row(png_structp png_ptr)
G
Guy Schalnat 已提交
1144 1145 1146
{
   int ret;

A
Andreas Dilger 已提交
1147
   png_debug(1, "in png_write_finish_row\n");
G
Guy Schalnat 已提交
1148 1149
   /* next row */
   png_ptr->row_number++;
G
Guy Schalnat 已提交
1150

G
Guy Schalnat 已提交
1151
   /* see if we are done */
G
Guy Schalnat 已提交
1152
   if (png_ptr->row_number < png_ptr->num_rows)
G
Guy Schalnat 已提交
1153
      return;
G
Guy Schalnat 已提交
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170

   /* 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 已提交
1171
            png_ptr->usr_width = (png_ptr->width +
G
Guy Schalnat 已提交
1172 1173 1174 1175 1176 1177 1178
               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 已提交
1179 1180
            if (png_ptr->transformations & PNG_INTERLACE)
               break;
G
Guy Schalnat 已提交
1181 1182 1183 1184
         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

      }

G
Guy Schalnat 已提交
1185
      /* reset the row above the image for the next pass */
G
Guy Schalnat 已提交
1186
      if (png_ptr->pass < 7)
G
Guy Schalnat 已提交
1187
      {
A
Andreas Dilger 已提交
1188
         if (png_ptr->prev_row != NULL)
A
Andreas Dilger 已提交
1189 1190
            png_memset(png_ptr->prev_row, 0, 
               (png_size_t) (((png_uint_32)png_ptr->usr_channels *
G
Guy Schalnat 已提交
1191 1192
               (png_uint_32)png_ptr->usr_bit_depth *
               png_ptr->width + 7) >> 3) + 1);
G
Guy Schalnat 已提交
1193
         return;
G
Guy Schalnat 已提交
1194
      }
G
Guy Schalnat 已提交
1195 1196 1197 1198 1199 1200 1201
   }

   /* 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 已提交
1202
      ret = deflate(&png_ptr->zstream, Z_FINISH);
G
Guy Schalnat 已提交
1203 1204 1205
      /* check for an error */
      if (ret != Z_OK && ret != Z_STREAM_END)
      {
A
Andreas Dilger 已提交
1206
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1207
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1208
         else
G
Guy Schalnat 已提交
1209
            png_error(png_ptr, "zlib error");
G
Guy Schalnat 已提交
1210
      }
G
Guy Schalnat 已提交
1211
      /* check to see if we need more room */
A
Andreas Dilger 已提交
1212
      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
G
Guy Schalnat 已提交
1213 1214
      {
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
1215 1216
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
1217 1218 1219 1220
      }
   } while (ret != Z_STREAM_END);

   /* write any extra space */
A
Andreas Dilger 已提交
1221
   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
G
Guy Schalnat 已提交
1222 1223
   {
      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
A
Andreas Dilger 已提交
1224
         png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
1225 1226
   }

A
Andreas Dilger 已提交
1227
   deflateReset(&png_ptr->zstream);
G
Guy Schalnat 已提交
1228 1229
}

G
Guy Schalnat 已提交
1230
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
1231 1232 1233 1234 1235 1236 1237
/* 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 已提交
1238
void
G
Guy Schalnat 已提交
1239
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
G
Guy Schalnat 已提交
1240
{
A
Andreas Dilger 已提交
1241
   png_debug(1, "in png_do_write_interlace\n");
G
Guy Schalnat 已提交
1242
   /* we don't have to do anything on the last pass (6) */
A
Andreas Dilger 已提交
1243 1244 1245 1246 1247
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL && pass < 6)
#else
   if (pass < 6)
#endif
G
Guy Schalnat 已提交
1248 1249 1250
   {
      /* each pixel depth is handled seperately */
      switch (row_info->pixel_depth)
G
Guy Schalnat 已提交
1251
      {
G
Guy Schalnat 已提交
1252 1253
         case 1:
         {
G
Guy Schalnat 已提交
1254 1255
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1256 1257 1258 1259 1260 1261 1262 1263
            int shift;
            int d;
            int value;
            png_uint_32 i;

            dp = row;
            d = 0;
            shift = 7;
A
Andreas Dilger 已提交
1264
            for (i = png_pass_start[pass]; i < row_info->width;
G
Guy Schalnat 已提交
1265 1266 1267
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 3);
G
Guy Schalnat 已提交
1268
               value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
G
Guy Schalnat 已提交
1269 1270 1271 1272 1273
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 7;
G
Guy Schalnat 已提交
1274
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1275 1276 1277 1278 1279 1280 1281
                  d = 0;
               }
               else
                  shift--;

            }
            if (shift != 7)
G
Guy Schalnat 已提交
1282
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1283 1284 1285
            break;
         }
         case 2:
G
Guy Schalnat 已提交
1286
         {
G
Guy Schalnat 已提交
1287 1288
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1289 1290 1291 1292 1293 1294 1295 1296
            int shift;
            int d;
            int value;
            png_uint_32 i;

            dp = row;
            shift = 6;
            d = 0;
A
Andreas Dilger 已提交
1297
            for (i = png_pass_start[pass]; i < row_info->width;
G
Guy Schalnat 已提交
1298 1299 1300 1301 1302 1303 1304 1305 1306
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 2);
               value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
               d |= (value << shift);

               if (shift == 0)
               {
                  shift = 6;
G
Guy Schalnat 已提交
1307
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1308 1309 1310 1311 1312 1313
                  d = 0;
               }
               else
                  shift -= 2;
            }
            if (shift != 6)
G
Guy Schalnat 已提交
1314
                   *dp = (png_byte)d;
G
Guy Schalnat 已提交
1315 1316 1317 1318
            break;
         }
         case 4:
         {
G
Guy Schalnat 已提交
1319 1320
            png_bytep sp;
            png_bytep dp;
G
Guy Schalnat 已提交
1321
            int shift;
G
Guy Schalnat 已提交
1322 1323 1324 1325 1326 1327 1328
            int d;
            int value;
            png_uint_32 i;

            dp = row;
            shift = 4;
            d = 0;
A
Andreas Dilger 已提交
1329
            for (i = png_pass_start[pass]; i < row_info->width;
G
Guy Schalnat 已提交
1330 1331 1332 1333 1334 1335 1336 1337
               i += png_pass_inc[pass])
            {
               sp = row + (png_size_t)(i >> 1);
               value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
               d |= (value << shift);

               if (shift == 0)
               {
G
Guy Schalnat 已提交
1338 1339
                  shift = 4;
                  *dp++ = (png_byte)d;
G
Guy Schalnat 已提交
1340 1341 1342 1343 1344 1345
                  d = 0;
               }
               else
                  shift -= 4;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
1346
               *dp = (png_byte)d;
G
Guy Schalnat 已提交
1347 1348 1349 1350
            break;
         }
         default:
         {
G
Guy Schalnat 已提交
1351 1352
            png_bytep sp;
            png_bytep dp;
A
Andreas Dilger 已提交
1353 1354
            png_uint_32 i;
            png_size_t pixel_bytes;
G
Guy Schalnat 已提交
1355

G
Guy Schalnat 已提交
1356
            /* start at the beginning */
G
Guy Schalnat 已提交
1357 1358 1359 1360 1361
            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 */
A
Andreas Dilger 已提交
1362
            for (i = png_pass_start[pass]; i < row_info->width;
G
Guy Schalnat 已提交
1363 1364 1365
               i += png_pass_inc[pass])
            {
               /* find out where the original pixel is */
A
Andreas Dilger 已提交
1366
               sp = row + i * pixel_bytes;
G
Guy Schalnat 已提交
1367 1368
               /* move the pixel */
               if (dp != sp)
G
Guy Schalnat 已提交
1369
                  png_memcpy(dp, sp, pixel_bytes);
G
Guy Schalnat 已提交
1370 1371 1372
               /* next pixel */
               dp += pixel_bytes;
            }
G
Guy Schalnat 已提交
1373
            break;
G
Guy Schalnat 已提交
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
         }
      }
      /* set new row width */
      row_info->width = (row_info->width +
         png_pass_inc[pass] - 1 -
         png_pass_start[pass]) /
         png_pass_inc[pass];
      row_info->rowbytes = ((row_info->width *
         row_info->pixel_depth + 7) >> 3);

   }
}
G
Guy Schalnat 已提交
1386
#endif
G
Guy Schalnat 已提交
1387

A
Andreas Dilger 已提交
1388 1389
/* 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
1390 1391
 * chosen filter.
 */
A
Andreas Dilger 已提交
1392 1393 1394 1395
#define PNG_MAXSUM (~0x0UL >> 1)
#define PNG_HISHIFT 10
#define PNG_LOMASK 0xffffL
#define PNG_HIMASK (~PNG_LOMASK >> PNG_HISHIFT)
G
Guy Schalnat 已提交
1396
void
G
Guy Schalnat 已提交
1397
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
G
Guy Schalnat 已提交
1398
{
G
Guy Schalnat 已提交
1399
   png_bytep prev_row, best_row, row_buf;
A
Andreas Dilger 已提交
1400
   png_uint_32 mins, bpp;
G
Guy Schalnat 已提交
1401

A
Andreas Dilger 已提交
1402
   png_debug(1, "in png_write_find_filter\n");
G
Guy Schalnat 已提交
1403 1404
   /* find out how many bytes offset each pixel is */
   bpp = (row_info->pixel_depth + 7) / 8;
G
Guy Schalnat 已提交
1405 1406 1407

   prev_row = png_ptr->prev_row;
   best_row = row_buf = png_ptr->row_buf;
A
Andreas Dilger 已提交
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
   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
    * from zero using anything >= 128 as negative numbers.  This is known
    * as the "minimum sum of absolute differences" heuristic.  Other
    * heruistics are the "weighted minumum sum of absolute differences"
    * (experimental and can in theory improve compression), and the "zlib
    * predictive" method (not implemented in libpng 0.95), which does test
    * compressions of lines using different filter methods, and then chooses
    * the (series of) filter(s) which give minimum compressed data size (VERY
    * computationally expensive).
    */
G
Guy Schalnat 已提交
1421

G
Guy Schalnat 已提交
1422
   /* We don't need to test the 'no filter' case if this is the only filter
A
Andreas Dilger 已提交
1423 1424
    * that has been chosen, as it doesn't actually do anything to the data.
    */
G
Guy Schalnat 已提交
1425 1426
   if (png_ptr->do_filter & PNG_FILTER_NONE &&
       png_ptr->do_filter != PNG_FILTER_NONE)
G
Guy Schalnat 已提交
1427
   {
G
Guy Schalnat 已提交
1428 1429
      png_bytep rp;
      png_uint_32 sum = 0;
A
Andreas Dilger 已提交
1430 1431
      png_size_t i;
      int v;
G
Guy Schalnat 已提交
1432

G
Guy Schalnat 已提交
1433 1434 1435 1436 1437
      for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
      {
         v = *rp;
         sum += (v < 128) ? v : 256 - v;
      }
A
Andreas Dilger 已提交
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
         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 */
         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
            {
               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
                  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 已提交
1473 1474
      mins = sum;
   }
G
Guy Schalnat 已提交
1475

G
Guy Schalnat 已提交
1476 1477 1478 1479
   /* sub filter */
   if (png_ptr->do_filter & PNG_FILTER_SUB)
   {
      png_bytep rp, dp, lp;
A
Andreas Dilger 已提交
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
      png_uint_32 sum = 0, lmins = mins;
      png_size_t i;
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      /* We temporarily increase the "minumum sum" by the factor we
       * 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)
      {
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
            {
               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
                  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 已提交
1517

G
Guy Schalnat 已提交
1518 1519 1520 1521
      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
           i++, rp++, dp++)
      {
         v = *dp = *rp;
G
Guy Schalnat 已提交
1522

G
Guy Schalnat 已提交
1523 1524 1525 1526 1527 1528 1529
         sum += (v < 128) ? v : 256 - v;
      }
      for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
      {
         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561

         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)
      {
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
            {
               sumlo = (sumlo * png_ptr->inv_filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               sumhi = (sumhi * png_ptr->inv_filter_weights[i]) >>
                  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 已提交
1562
      }
A
Andreas Dilger 已提交
1563 1564
#endif

G
Guy Schalnat 已提交
1565 1566 1567 1568 1569
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->sub_row;
      }
G
Guy Schalnat 已提交
1570 1571
   }

G
Guy Schalnat 已提交
1572 1573 1574 1575
   /* up filter */
   if (png_ptr->do_filter & PNG_FILTER_UP)
   {
      png_bytep rp, dp, pp;
A
Andreas Dilger 已提交
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
      png_uint_32 sum = 0, lmins = mins;
      png_size_t i;
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_UP)
            {
               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
                  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 已提交
1609

G
Guy Schalnat 已提交
1610 1611 1612 1613 1614 1615
      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
           pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
      {
         v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);

         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
1616 1617 1618

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
1619
      }
A
Andreas Dilger 已提交
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_UP)
            {
               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
                  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 已提交
1651 1652 1653 1654 1655 1656 1657 1658 1659
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->up_row;
      }
   }

   /* avg filter */
   if (png_ptr->do_filter & PNG_FILTER_AVG)
G
Guy Schalnat 已提交
1660
   {
G
Guy Schalnat 已提交
1661
      png_bytep rp, dp, pp, lp;
A
Andreas Dilger 已提交
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694
      png_uint_32 sum = 0, lmins = mins;
      png_size_t i;
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_AVG)
            {
               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
                  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 已提交
1695

G
Guy Schalnat 已提交
1696 1697 1698 1699
      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
           pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
      {
         v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
G
Guy Schalnat 已提交
1700

G
Guy Schalnat 已提交
1701 1702 1703 1704 1705 1706
         sum += (v < 128) ? v : 256 - v;
      }
      for (lp = row_buf + 1; i < row_info->rowbytes;
           i++, rp++, pp++, lp++, dp++)
      {
         v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
G
Guy Schalnat 已提交
1707

G
Guy Schalnat 已提交
1708
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
1709 1710 1711

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
1712
      }
A
Andreas Dilger 已提交
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
            {
               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
                  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 已提交
1744 1745 1746 1747 1748 1749
      if (sum < mins)
      {
         mins = sum;
         best_row = png_ptr->avg_row;
      }
   }
G
Guy Schalnat 已提交
1750

A
Andreas Dilger 已提交
1751
   /* Paeth filter */
G
Guy Schalnat 已提交
1752 1753 1754
   if (png_ptr->do_filter & PNG_FILTER_PAETH)
   {
      png_bytep rp, dp, pp, cp, lp;
A
Andreas Dilger 已提交
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
      png_uint_32 sum = 0, lmins = mins;
      png_size_t i;
      int v;

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 lmhi, lmlo;
         lmlo = lmins & PNG_LOMASK;
         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_PAETH)
            {
               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
                  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 已提交
1788

G
Guy Schalnat 已提交
1789 1790 1791 1792
      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
           pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
      {
         v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
G
Guy Schalnat 已提交
1793

G
Guy Schalnat 已提交
1794 1795 1796 1797 1798 1799
         sum += (v < 128) ? v : 256 - v;
      }
      for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
           i++, rp++, pp++, lp++, dp++, cp++)
      {
         int a, b, c, pa, pb, pc, p;
G
Guy Schalnat 已提交
1800

G
Guy Schalnat 已提交
1801 1802 1803
         b = *pp;
         c = *cp;
         a = *lp;
G
Guy Schalnat 已提交
1804

G
Guy Schalnat 已提交
1805 1806 1807 1808
         p = a + b - c;
         pa = abs(p - a);
         pb = abs(p - b);
         pc = abs(p - c);
G
Guy Schalnat 已提交
1809

G
Guy Schalnat 已提交
1810 1811 1812 1813 1814 1815
         if (pa <= pb && pa <= pc)
            p = a;
         else if (pb <= pc)
            p = b;
         else
            p = c;
G
Guy Schalnat 已提交
1816

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

G
Guy Schalnat 已提交
1819
         sum += (v < 128) ? v : 256 - v;
A
Andreas Dilger 已提交
1820 1821 1822

         if (sum > lmins)  /* We are already worse, don't continue. */
            break;
G
Guy Schalnat 已提交
1823
      }
A
Andreas Dilger 已提交
1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
      {
         png_uint_32 sumhi, sumlo;
         sumlo = sum & PNG_LOMASK;
         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

         for (i = 0; i < png_ptr->num_prev_filters; i++)
         {
            if (png_ptr->prev_filters[i] == PNG_FILTER_PAETH)
            {
               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
                  PNG_WEIGHT_SHIFT;
               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
                  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 已提交
1855 1856 1857 1858
      if (sum < mins)
      {
         best_row = png_ptr->paeth_row;
      }
G
Guy Schalnat 已提交
1859 1860
   }

A
Andreas Dilger 已提交
1861
   /* Do the actual writing of the filtered row data from the chosen filter. */
G
Guy Schalnat 已提交
1862
   png_write_filtered_row(png_ptr, best_row);
A
Andreas Dilger 已提交
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876

#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)
   {
      png_byte i;

      for (i = 1; i < png_ptr->num_prev_filters; i++)
      {
         png_ptr->prev_filters[i] = png_ptr->prev_filters[i - 1];
      }
      png_ptr->prev_filters[i] = best_row[0];
   }
#endif
G
Guy Schalnat 已提交
1877
}
G
Guy Schalnat 已提交
1878

G
Guy Schalnat 已提交
1879

A
Andreas Dilger 已提交
1880
/* Do the actual writing of a previously filtered row. */
G
Guy Schalnat 已提交
1881 1882 1883
void
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
A
Andreas Dilger 已提交
1884 1885
   png_debug(1, "in png_write_filtered_row\n");
   png_debug1(2, "filter = %d\n", filtered_row[0]);
G
Guy Schalnat 已提交
1886
   /* set up the zlib input buffer */
A
Andreas Dilger 已提交
1887 1888
   png_ptr->zstream.next_in = filtered_row;
   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
G
Guy Schalnat 已提交
1889 1890
   /* repeat until we have compressed all the data */
   do
G
Guy Schalnat 已提交
1891
   {
G
Guy Schalnat 已提交
1892
      int ret; /* return of zlib */
G
Guy Schalnat 已提交
1893

G
Guy Schalnat 已提交
1894
      /* compress the data */
A
Andreas Dilger 已提交
1895
      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
G
Guy Schalnat 已提交
1896 1897 1898
      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
1899
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
1900
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
1901 1902 1903
         else
            png_error(png_ptr, "zlib error");
      }
G
Guy Schalnat 已提交
1904

G
Guy Schalnat 已提交
1905
      /* see if it is time to write another IDAT */
A
Andreas Dilger 已提交
1906
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
1907 1908 1909
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
1910 1911
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
1912 1913
      }
   /* repeat until all data has been compressed */
A
Andreas Dilger 已提交
1914
   } while (png_ptr->zstream.avail_in);
G
Guy Schalnat 已提交
1915

G
Guy Schalnat 已提交
1916
   /* swap the current and previous rows */
A
Andreas Dilger 已提交
1917
   if (png_ptr->prev_row != NULL)
G
Guy Schalnat 已提交
1918 1919 1920 1921 1922 1923 1924 1925
   {
      png_bytep tptr;

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

G
Guy Schalnat 已提交
1926 1927
   /* finish row - updates counters and flushes zlib if last row */
   png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
1928

G
Guy Schalnat 已提交
1929 1930 1931 1932 1933 1934 1935
#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 已提交
1936
   }
G
Guy Schalnat 已提交
1937
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
1938
}
G
Guy Schalnat 已提交
1939