1
2/* pngwutil.c - utilities to write a PNG file
3 *
4 * Last changed in libpng 1.2.43 [February 25, 2010]
5 * Copyright (c) 1998-2010 Glenn Randers-Pehrson
6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8 *
9 * This code is released under the libpng license.
10 * For conditions of distribution and use, see the disclaimer
11 * and license in png.h
12 */
13
14#define PNG_INTERNAL
15#define PNG_NO_PEDANTIC_WARNINGS
16#include "png.h"
17#ifdef PNG_WRITE_SUPPORTED
18
19/* Place a 32-bit number into a buffer in PNG byte order.  We work
20 * with unsigned numbers for convenience, although one supported
21 * ancillary chunk uses signed (two's complement) numbers.
22 */
23void PNGAPI
24png_save_uint_32(png_bytep buf, png_uint_32 i)
25{
26   buf[0] = (png_byte)((i >> 24) & 0xff);
27   buf[1] = (png_byte)((i >> 16) & 0xff);
28   buf[2] = (png_byte)((i >> 8) & 0xff);
29   buf[3] = (png_byte)(i & 0xff);
30}
31
32/* The png_save_int_32 function assumes integers are stored in two's
33 * complement format.  If this isn't the case, then this routine needs to
34 * be modified to write data in two's complement format.
35 */
36void PNGAPI
37png_save_int_32(png_bytep buf, png_int_32 i)
38{
39   buf[0] = (png_byte)((i >> 24) & 0xff);
40   buf[1] = (png_byte)((i >> 16) & 0xff);
41   buf[2] = (png_byte)((i >> 8) & 0xff);
42   buf[3] = (png_byte)(i & 0xff);
43}
44
45/* Place a 16-bit number into a buffer in PNG byte order.
46 * The parameter is declared unsigned int, not png_uint_16,
47 * just to avoid potential problems on pre-ANSI C compilers.
48 */
49void PNGAPI
50png_save_uint_16(png_bytep buf, unsigned int i)
51{
52   buf[0] = (png_byte)((i >> 8) & 0xff);
53   buf[1] = (png_byte)(i & 0xff);
54}
55
56/* Simple function to write the signature.  If we have already written
57 * the magic bytes of the signature, or more likely, the PNG stream is
58 * being embedded into another stream and doesn't need its own signature,
59 * we should call png_set_sig_bytes() to tell libpng how many of the
60 * bytes have already been written.
61 */
62void /* PRIVATE */
63png_write_sig(png_structp png_ptr)
64{
65   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
66
67   /* Write the rest of the 8 byte signature */
68   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
69      (png_size_t)(8 - png_ptr->sig_bytes));
70   if (png_ptr->sig_bytes < 3)
71      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
72}
73
74/* Write a PNG chunk all at once.  The type is an array of ASCII characters
75 * representing the chunk name.  The array must be at least 4 bytes in
76 * length, and does not need to be null terminated.  To be safe, pass the
77 * pre-defined chunk names here, and if you need a new one, define it
78 * where the others are defined.  The length is the length of the data.
79 * All the data must be present.  If that is not possible, use the
80 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
81 * functions instead.
82 */
83void PNGAPI
84png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
85   png_bytep data, png_size_t length)
86{
87   if (png_ptr == NULL)
88      return;
89   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
90   png_write_chunk_data(png_ptr, data, (png_size_t)length);
91   png_write_chunk_end(png_ptr);
92}
93
94/* Write the start of a PNG chunk.  The type is the chunk type.
95 * The total_length is the sum of the lengths of all the data you will be
96 * passing in png_write_chunk_data().
97 */
98void PNGAPI
99png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
100   png_uint_32 length)
101{
102   png_byte buf[8];
103
104   png_debug2(0, "Writing %s chunk, length = %lu", chunk_name,
105      (unsigned long)length);
106
107   if (png_ptr == NULL)
108      return;
109
110
111   /* Write the length and the chunk name */
112   png_save_uint_32(buf, length);
113   png_memcpy(buf + 4, chunk_name, 4);
114   png_write_data(png_ptr, buf, (png_size_t)8);
115   /* Put the chunk name into png_ptr->chunk_name */
116   png_memcpy(png_ptr->chunk_name, chunk_name, 4);
117   /* Reset the crc and run it over the chunk name */
118   png_reset_crc(png_ptr);
119   png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
120}
121
122/* Write the data of a PNG chunk started with png_write_chunk_start().
123 * Note that multiple calls to this function are allowed, and that the
124 * sum of the lengths from these calls *must* add up to the total_length
125 * given to png_write_chunk_start().
126 */
127void PNGAPI
128png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
129{
130   /* Write the data, and run the CRC over it */
131   if (png_ptr == NULL)
132      return;
133   if (data != NULL && length > 0)
134   {
135      png_write_data(png_ptr, data, length);
136      /* Update the CRC after writing the data,
137       * in case that the user I/O routine alters it.
138       */
139      png_calculate_crc(png_ptr, data, length);
140   }
141}
142
143/* Finish a chunk started with png_write_chunk_start(). */
144void PNGAPI
145png_write_chunk_end(png_structp png_ptr)
146{
147   png_byte buf[4];
148
149   if (png_ptr == NULL) return;
150
151   /* Write the crc in a single operation */
152   png_save_uint_32(buf, png_ptr->crc);
153
154   png_write_data(png_ptr, buf, (png_size_t)4);
155}
156
157#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
158/* This pair of functions encapsulates the operation of (a) compressing a
159 * text string, and (b) issuing it later as a series of chunk data writes.
160 * The compression_state structure is shared context for these functions
161 * set up by the caller in order to make the whole mess thread-safe.
162 */
163
164typedef struct
165{
166   char *input;   /* The uncompressed input data */
167   int input_len;   /* Its length */
168   int num_output_ptr; /* Number of output pointers used */
169   int max_output_ptr; /* Size of output_ptr */
170   png_charpp output_ptr; /* Array of pointers to output */
171} compression_state;
172
173/* Compress given text into storage in the png_ptr structure */
174static int /* PRIVATE */
175png_text_compress(png_structp png_ptr,
176        png_charp text, png_size_t text_len, int compression,
177        compression_state *comp)
178{
179   int ret;
180
181   comp->num_output_ptr = 0;
182   comp->max_output_ptr = 0;
183   comp->output_ptr = NULL;
184   comp->input = NULL;
185   comp->input_len = 0;
186
187   /* We may just want to pass the text right through */
188   if (compression == PNG_TEXT_COMPRESSION_NONE)
189   {
190       comp->input = text;
191       comp->input_len = text_len;
192       return((int)text_len);
193   }
194
195   if (compression >= PNG_TEXT_COMPRESSION_LAST)
196   {
197#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
198      char msg[50];
199      png_snprintf(msg, 50, "Unknown compression type %d", compression);
200      png_warning(png_ptr, msg);
201#else
202      png_warning(png_ptr, "Unknown compression type");
203#endif
204   }
205
206   /* We can't write the chunk until we find out how much data we have,
207    * which means we need to run the compressor first and save the
208    * output.  This shouldn't be a problem, as the vast majority of
209    * comments should be reasonable, but we will set up an array of
210    * malloc'd pointers to be sure.
211    *
212    * If we knew the application was well behaved, we could simplify this
213    * greatly by assuming we can always malloc an output buffer large
214    * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
215    * and malloc this directly.  The only time this would be a bad idea is
216    * if we can't malloc more than 64K and we have 64K of random input
217    * data, or if the input string is incredibly large (although this
218    * wouldn't cause a failure, just a slowdown due to swapping).
219    */
220
221   /* Set up the compression buffers */
222   png_ptr->zstream.avail_in = (uInt)text_len;
223   png_ptr->zstream.next_in = (Bytef *)text;
224   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
225   png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
226
227   /* This is the same compression loop as in png_write_row() */
228   do
229   {
230      /* Compress the data */
231      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
232      if (ret != Z_OK)
233      {
234         /* Error */
235         if (png_ptr->zstream.msg != NULL)
236            png_error(png_ptr, png_ptr->zstream.msg);
237         else
238            png_error(png_ptr, "zlib error");
239      }
240      /* Check to see if we need more room */
241      if (!(png_ptr->zstream.avail_out))
242      {
243         /* Make sure the output array has room */
244         if (comp->num_output_ptr >= comp->max_output_ptr)
245         {
246            int old_max;
247
248            old_max = comp->max_output_ptr;
249            comp->max_output_ptr = comp->num_output_ptr + 4;
250            if (comp->output_ptr != NULL)
251            {
252               png_charpp old_ptr;
253
254               old_ptr = comp->output_ptr;
255               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
256                  (png_uint_32)
257                  (comp->max_output_ptr * png_sizeof(png_charpp)));
258               png_memcpy(comp->output_ptr, old_ptr, old_max
259                  * png_sizeof(png_charp));
260               png_free(png_ptr, old_ptr);
261            }
262            else
263               comp->output_ptr = (png_charpp)png_malloc(png_ptr,
264                  (png_uint_32)
265                  (comp->max_output_ptr * png_sizeof(png_charp)));
266         }
267
268         /* Save the data */
269         comp->output_ptr[comp->num_output_ptr] =
270            (png_charp)png_malloc(png_ptr,
271            (png_uint_32)png_ptr->zbuf_size);
272         png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
273            png_ptr->zbuf_size);
274         comp->num_output_ptr++;
275
276         /* and reset the buffer */
277         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
278         png_ptr->zstream.next_out = png_ptr->zbuf;
279      }
280   /* Continue until we don't have any more to compress */
281   } while (png_ptr->zstream.avail_in);
282
283   /* Finish the compression */
284   do
285   {
286      /* Tell zlib we are finished */
287      ret = deflate(&png_ptr->zstream, Z_FINISH);
288
289      if (ret == Z_OK)
290      {
291         /* Check to see if we need more room */
292         if (!(png_ptr->zstream.avail_out))
293         {
294            /* Check to make sure our output array has room */
295            if (comp->num_output_ptr >= comp->max_output_ptr)
296            {
297               int old_max;
298
299               old_max = comp->max_output_ptr;
300               comp->max_output_ptr = comp->num_output_ptr + 4;
301               if (comp->output_ptr != NULL)
302               {
303                  png_charpp old_ptr;
304
305                  old_ptr = comp->output_ptr;
306                  /* This could be optimized to realloc() */
307                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
308                     (png_uint_32)(comp->max_output_ptr *
309                     png_sizeof(png_charp)));
310                  png_memcpy(comp->output_ptr, old_ptr,
311                     old_max * png_sizeof(png_charp));
312                  png_free(png_ptr, old_ptr);
313               }
314               else
315                  comp->output_ptr = (png_charpp)png_malloc(png_ptr,
316                     (png_uint_32)(comp->max_output_ptr *
317                     png_sizeof(png_charp)));
318            }
319
320            /* Save the data */
321            comp->output_ptr[comp->num_output_ptr] =
322               (png_charp)png_malloc(png_ptr,
323               (png_uint_32)png_ptr->zbuf_size);
324            png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
325               png_ptr->zbuf_size);
326            comp->num_output_ptr++;
327
328            /* and reset the buffer pointers */
329            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
330            png_ptr->zstream.next_out = png_ptr->zbuf;
331         }
332      }
333      else if (ret != Z_STREAM_END)
334      {
335         /* We got an error */
336         if (png_ptr->zstream.msg != NULL)
337            png_error(png_ptr, png_ptr->zstream.msg);
338         else
339            png_error(png_ptr, "zlib error");
340      }
341   } while (ret != Z_STREAM_END);
342
343   /* Text length is number of buffers plus last buffer */
344   text_len = png_ptr->zbuf_size * comp->num_output_ptr;
345   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
346      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
347
348   return((int)text_len);
349}
350
351/* Ship the compressed text out via chunk writes */
352static void /* PRIVATE */
353png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
354{
355   int i;
356
357   /* Handle the no-compression case */
358   if (comp->input)
359   {
360      png_write_chunk_data(png_ptr, (png_bytep)comp->input,
361                            (png_size_t)comp->input_len);
362      return;
363   }
364
365   /* Write saved output buffers, if any */
366   for (i = 0; i < comp->num_output_ptr; i++)
367   {
368      png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i],
369         (png_size_t)png_ptr->zbuf_size);
370      png_free(png_ptr, comp->output_ptr[i]);
371       comp->output_ptr[i]=NULL;
372   }
373   if (comp->max_output_ptr != 0)
374      png_free(png_ptr, comp->output_ptr);
375       comp->output_ptr=NULL;
376   /* Write anything left in zbuf */
377   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
378      png_write_chunk_data(png_ptr, png_ptr->zbuf,
379         (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
380
381   /* Reset zlib for another zTXt/iTXt or image data */
382   deflateReset(&png_ptr->zstream);
383   png_ptr->zstream.data_type = Z_BINARY;
384}
385#endif
386
387/* Write the IHDR chunk, and update the png_struct with the necessary
388 * information.  Note that the rest of this code depends upon this
389 * information being correct.
390 */
391void /* PRIVATE */
392png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
393   int bit_depth, int color_type, int compression_type, int filter_type,
394   int interlace_type)
395{
396#ifdef PNG_USE_LOCAL_ARRAYS
397   PNG_IHDR;
398#endif
399   int ret;
400
401   png_byte buf[13]; /* Buffer to store the IHDR info */
402
403   png_debug(1, "in png_write_IHDR");
404
405   /* Check that we have valid input data from the application info */
406   switch (color_type)
407   {
408      case PNG_COLOR_TYPE_GRAY:
409         switch (bit_depth)
410         {
411            case 1:
412            case 2:
413            case 4:
414            case 8:
415            case 16: png_ptr->channels = 1; break;
416            default: png_error(png_ptr,
417                         "Invalid bit depth for grayscale image");
418         }
419         break;
420      case PNG_COLOR_TYPE_RGB:
421         if (bit_depth != 8 && bit_depth != 16)
422            png_error(png_ptr, "Invalid bit depth for RGB image");
423         png_ptr->channels = 3;
424         break;
425      case PNG_COLOR_TYPE_PALETTE:
426         switch (bit_depth)
427         {
428            case 1:
429            case 2:
430            case 4:
431            case 8: png_ptr->channels = 1; break;
432            default: png_error(png_ptr, "Invalid bit depth for paletted image");
433         }
434         break;
435      case PNG_COLOR_TYPE_GRAY_ALPHA:
436         if (bit_depth != 8 && bit_depth != 16)
437            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
438         png_ptr->channels = 2;
439         break;
440      case PNG_COLOR_TYPE_RGB_ALPHA:
441         if (bit_depth != 8 && bit_depth != 16)
442            png_error(png_ptr, "Invalid bit depth for RGBA image");
443         png_ptr->channels = 4;
444         break;
445      default:
446         png_error(png_ptr, "Invalid image color type specified");
447   }
448
449   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
450   {
451      png_warning(png_ptr, "Invalid compression type specified");
452      compression_type = PNG_COMPRESSION_TYPE_BASE;
453   }
454
455   /* Write filter_method 64 (intrapixel differencing) only if
456    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
457    * 2. Libpng did not write a PNG signature (this filter_method is only
458    *    used in PNG datastreams that are embedded in MNG datastreams) and
459    * 3. The application called png_permit_mng_features with a mask that
460    *    included PNG_FLAG_MNG_FILTER_64 and
461    * 4. The filter_method is 64 and
462    * 5. The color_type is RGB or RGBA
463    */
464   if (
465#ifdef PNG_MNG_FEATURES_SUPPORTED
466      !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
467      ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
468      (color_type == PNG_COLOR_TYPE_RGB ||
469       color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
470      (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
471#endif
472      filter_type != PNG_FILTER_TYPE_BASE)
473   {
474      png_warning(png_ptr, "Invalid filter type specified");
475      filter_type = PNG_FILTER_TYPE_BASE;
476   }
477
478#ifdef PNG_WRITE_INTERLACING_SUPPORTED
479   if (interlace_type != PNG_INTERLACE_NONE &&
480      interlace_type != PNG_INTERLACE_ADAM7)
481   {
482      png_warning(png_ptr, "Invalid interlace type specified");
483      interlace_type = PNG_INTERLACE_ADAM7;
484   }
485#else
486   interlace_type=PNG_INTERLACE_NONE;
487#endif
488
489   /* Save the relevent information */
490   png_ptr->bit_depth = (png_byte)bit_depth;
491   png_ptr->color_type = (png_byte)color_type;
492   png_ptr->interlaced = (png_byte)interlace_type;
493#ifdef PNG_MNG_FEATURES_SUPPORTED
494   png_ptr->filter_type = (png_byte)filter_type;
495#endif
496   png_ptr->compression_type = (png_byte)compression_type;
497   png_ptr->width = width;
498   png_ptr->height = height;
499
500   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
501   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
502   /* Set the usr info, so any transformations can modify it */
503   png_ptr->usr_width = png_ptr->width;
504   png_ptr->usr_bit_depth = png_ptr->bit_depth;
505   png_ptr->usr_channels = png_ptr->channels;
506
507   /* Pack the header information into the buffer */
508   png_save_uint_32(buf, width);
509   png_save_uint_32(buf + 4, height);
510   buf[8] = (png_byte)bit_depth;
511   buf[9] = (png_byte)color_type;
512   buf[10] = (png_byte)compression_type;
513   buf[11] = (png_byte)filter_type;
514   buf[12] = (png_byte)interlace_type;
515
516   /* Write the chunk */
517   png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
518
519   /* Initialize zlib with PNG info */
520   png_ptr->zstream.zalloc = png_zalloc;
521   png_ptr->zstream.zfree = png_zfree;
522   png_ptr->zstream.opaque = (voidpf)png_ptr;
523   if (!(png_ptr->do_filter))
524   {
525      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
526         png_ptr->bit_depth < 8)
527         png_ptr->do_filter = PNG_FILTER_NONE;
528      else
529         png_ptr->do_filter = PNG_ALL_FILTERS;
530   }
531   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
532   {
533      if (png_ptr->do_filter != PNG_FILTER_NONE)
534         png_ptr->zlib_strategy = Z_FILTERED;
535      else
536         png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
537   }
538   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
539      png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
540   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
541      png_ptr->zlib_mem_level = 8;
542   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
543      png_ptr->zlib_window_bits = 15;
544   if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
545      png_ptr->zlib_method = 8;
546   ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
547         png_ptr->zlib_method, png_ptr->zlib_window_bits,
548         png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
549   if (ret != Z_OK)
550   {
551      if (ret == Z_VERSION_ERROR) png_error(png_ptr,
552          "zlib failed to initialize compressor -- version error");
553      if (ret == Z_STREAM_ERROR) png_error(png_ptr,
554           "zlib failed to initialize compressor -- stream error");
555      if (ret == Z_MEM_ERROR) png_error(png_ptr,
556           "zlib failed to initialize compressor -- mem error");
557      png_error(png_ptr, "zlib failed to initialize compressor");
558   }
559   png_ptr->zstream.next_out = png_ptr->zbuf;
560   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
561   /* libpng is not interested in zstream.data_type */
562   /* Set it to a predefined value, to avoid its evaluation inside zlib */
563   png_ptr->zstream.data_type = Z_BINARY;
564
565   png_ptr->mode = PNG_HAVE_IHDR;
566}
567
568/* Write the palette.  We are careful not to trust png_color to be in the
569 * correct order for PNG, so people can redefine it to any convenient
570 * structure.
571 */
572void /* PRIVATE */
573png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
574{
575#ifdef PNG_USE_LOCAL_ARRAYS
576   PNG_PLTE;
577#endif
578   png_uint_32 i;
579   png_colorp pal_ptr;
580   png_byte buf[3];
581
582   png_debug(1, "in png_write_PLTE");
583
584   if ((
585#ifdef PNG_MNG_FEATURES_SUPPORTED
586        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
587#endif
588        num_pal == 0) || num_pal > 256)
589   {
590     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
591     {
592        png_error(png_ptr, "Invalid number of colors in palette");
593     }
594     else
595     {
596        png_warning(png_ptr, "Invalid number of colors in palette");
597        return;
598     }
599   }
600
601   if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
602   {
603      png_warning(png_ptr,
604        "Ignoring request to write a PLTE chunk in grayscale PNG");
605      return;
606   }
607
608   png_ptr->num_palette = (png_uint_16)num_pal;
609   png_debug1(3, "num_palette = %d", png_ptr->num_palette);
610
611   png_write_chunk_start(png_ptr, (png_bytep)png_PLTE,
612     (png_uint_32)(num_pal * 3));
613#ifdef PNG_POINTER_INDEXING_SUPPORTED
614   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
615   {
616      buf[0] = pal_ptr->red;
617      buf[1] = pal_ptr->green;
618      buf[2] = pal_ptr->blue;
619      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
620   }
621#else
622   /* This is a little slower but some buggy compilers need to do this
623    * instead
624    */
625   pal_ptr=palette;
626   for (i = 0; i < num_pal; i++)
627   {
628      buf[0] = pal_ptr[i].red;
629      buf[1] = pal_ptr[i].green;
630      buf[2] = pal_ptr[i].blue;
631      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
632   }
633#endif
634   png_write_chunk_end(png_ptr);
635   png_ptr->mode |= PNG_HAVE_PLTE;
636}
637
638/* Write an IDAT chunk */
639void /* PRIVATE */
640png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
641{
642#ifdef PNG_USE_LOCAL_ARRAYS
643   PNG_IDAT;
644#endif
645
646   png_debug(1, "in png_write_IDAT");
647
648   /* Optimize the CMF field in the zlib stream. */
649   /* This hack of the zlib stream is compliant to the stream specification. */
650   if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
651       png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
652   {
653      unsigned int z_cmf = data[0];  /* zlib compression method and flags */
654      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
655      {
656         /* Avoid memory underflows and multiplication overflows.
657          *
658          * The conditions below are practically always satisfied;
659          * however, they still must be checked.
660          */
661         if (length >= 2 &&
662             png_ptr->height < 16384 && png_ptr->width < 16384)
663         {
664            png_uint_32 uncompressed_idat_size = png_ptr->height *
665               ((png_ptr->width *
666               png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
667            unsigned int z_cinfo = z_cmf >> 4;
668            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
669            while (uncompressed_idat_size <= half_z_window_size &&
670                   half_z_window_size >= 256)
671            {
672               z_cinfo--;
673               half_z_window_size >>= 1;
674            }
675            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
676            if (data[0] != (png_byte)z_cmf)
677            {
678               data[0] = (png_byte)z_cmf;
679               data[1] &= 0xe0;
680               data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
681            }
682         }
683      }
684      else
685         png_error(png_ptr,
686            "Invalid zlib compression method or flags in IDAT");
687   }
688
689   png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
690   png_ptr->mode |= PNG_HAVE_IDAT;
691}
692
693/* Write an IEND chunk */
694void /* PRIVATE */
695png_write_IEND(png_structp png_ptr)
696{
697#ifdef PNG_USE_LOCAL_ARRAYS
698   PNG_IEND;
699#endif
700
701   png_debug(1, "in png_write_IEND");
702
703   png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
704     (png_size_t)0);
705   png_ptr->mode |= PNG_HAVE_IEND;
706}
707
708#ifdef PNG_WRITE_gAMA_SUPPORTED
709/* Write a gAMA chunk */
710#ifdef PNG_FLOATING_POINT_SUPPORTED
711void /* PRIVATE */
712png_write_gAMA(png_structp png_ptr, double file_gamma)
713{
714#ifdef PNG_USE_LOCAL_ARRAYS
715   PNG_gAMA;
716#endif
717   png_uint_32 igamma;
718   png_byte buf[4];
719
720   png_debug(1, "in png_write_gAMA");
721
722   /* file_gamma is saved in 1/100,000ths */
723   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
724   png_save_uint_32(buf, igamma);
725   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
726}
727#endif
728#ifdef PNG_FIXED_POINT_SUPPORTED
729void /* PRIVATE */
730png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
731{
732#ifdef PNG_USE_LOCAL_ARRAYS
733   PNG_gAMA;
734#endif
735   png_byte buf[4];
736
737   png_debug(1, "in png_write_gAMA");
738
739   /* file_gamma is saved in 1/100,000ths */
740   png_save_uint_32(buf, (png_uint_32)file_gamma);
741   png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
742}
743#endif
744#endif
745
746#ifdef PNG_WRITE_sRGB_SUPPORTED
747/* Write a sRGB chunk */
748void /* PRIVATE */
749png_write_sRGB(png_structp png_ptr, int srgb_intent)
750{
751#ifdef PNG_USE_LOCAL_ARRAYS
752   PNG_sRGB;
753#endif
754   png_byte buf[1];
755
756   png_debug(1, "in png_write_sRGB");
757
758   if (srgb_intent >= PNG_sRGB_INTENT_LAST)
759         png_warning(png_ptr,
760            "Invalid sRGB rendering intent specified");
761   buf[0]=(png_byte)srgb_intent;
762   png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
763}
764#endif
765
766#ifdef PNG_WRITE_iCCP_SUPPORTED
767/* Write an iCCP chunk */
768void /* PRIVATE */
769png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
770   png_charp profile, int profile_len)
771{
772#ifdef PNG_USE_LOCAL_ARRAYS
773   PNG_iCCP;
774#endif
775   png_size_t name_len;
776   png_charp new_name;
777   compression_state comp;
778   int embedded_profile_len = 0;
779
780   png_debug(1, "in png_write_iCCP");
781
782   comp.num_output_ptr = 0;
783   comp.max_output_ptr = 0;
784   comp.output_ptr = NULL;
785   comp.input = NULL;
786   comp.input_len = 0;
787
788   if ((name_len = png_check_keyword(png_ptr, name,
789      &new_name)) == 0)
790      return;
791
792   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
793      png_warning(png_ptr, "Unknown compression type in iCCP chunk");
794
795   if (profile == NULL)
796      profile_len = 0;
797
798   if (profile_len > 3)
799      embedded_profile_len =
800          ((*( (png_bytep)profile    ))<<24) |
801          ((*( (png_bytep)profile + 1))<<16) |
802          ((*( (png_bytep)profile + 2))<< 8) |
803          ((*( (png_bytep)profile + 3))    );
804
805   if (embedded_profile_len < 0)
806   {
807      png_warning(png_ptr,
808        "Embedded profile length in iCCP chunk is negative");
809      png_free(png_ptr, new_name);
810      return;
811   }
812
813   if (profile_len < embedded_profile_len)
814   {
815      png_warning(png_ptr,
816        "Embedded profile length too large in iCCP chunk");
817      png_free(png_ptr, new_name);
818      return;
819   }
820
821   if (profile_len > embedded_profile_len)
822   {
823      png_warning(png_ptr,
824        "Truncating profile to actual length in iCCP chunk");
825      profile_len = embedded_profile_len;
826   }
827
828   if (profile_len)
829      profile_len = png_text_compress(png_ptr, profile,
830        (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
831
832   /* Make sure we include the NULL after the name and the compression type */
833   png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
834          (png_uint_32)(name_len + profile_len + 2));
835   new_name[name_len + 1] = 0x00;
836   png_write_chunk_data(png_ptr, (png_bytep)new_name,
837     (png_size_t)(name_len + 2));
838
839   if (profile_len)
840      png_write_compressed_data_out(png_ptr, &comp);
841
842   png_write_chunk_end(png_ptr);
843   png_free(png_ptr, new_name);
844}
845#endif
846
847#ifdef PNG_WRITE_sPLT_SUPPORTED
848/* Write a sPLT chunk */
849void /* PRIVATE */
850png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
851{
852#ifdef PNG_USE_LOCAL_ARRAYS
853   PNG_sPLT;
854#endif
855   png_size_t name_len;
856   png_charp new_name;
857   png_byte entrybuf[10];
858   int entry_size = (spalette->depth == 8 ? 6 : 10);
859   int palette_size = entry_size * spalette->nentries;
860   png_sPLT_entryp ep;
861#ifndef PNG_POINTER_INDEXING_SUPPORTED
862   int i;
863#endif
864
865   png_debug(1, "in png_write_sPLT");
866
867   if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0)
868      return;
869
870   /* Make sure we include the NULL after the name */
871   png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
872     (png_uint_32)(name_len + 2 + palette_size));
873   png_write_chunk_data(png_ptr, (png_bytep)new_name,
874     (png_size_t)(name_len + 1));
875   png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1);
876
877   /* Loop through each palette entry, writing appropriately */
878#ifdef PNG_POINTER_INDEXING_SUPPORTED
879   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
880   {
881      if (spalette->depth == 8)
882      {
883          entrybuf[0] = (png_byte)ep->red;
884          entrybuf[1] = (png_byte)ep->green;
885          entrybuf[2] = (png_byte)ep->blue;
886          entrybuf[3] = (png_byte)ep->alpha;
887          png_save_uint_16(entrybuf + 4, ep->frequency);
888      }
889      else
890      {
891          png_save_uint_16(entrybuf + 0, ep->red);
892          png_save_uint_16(entrybuf + 2, ep->green);
893          png_save_uint_16(entrybuf + 4, ep->blue);
894          png_save_uint_16(entrybuf + 6, ep->alpha);
895          png_save_uint_16(entrybuf + 8, ep->frequency);
896      }
897      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
898   }
899#else
900   ep=spalette->entries;
901   for (i=0; i>spalette->nentries; i++)
902   {
903      if (spalette->depth == 8)
904      {
905          entrybuf[0] = (png_byte)ep[i].red;
906          entrybuf[1] = (png_byte)ep[i].green;
907          entrybuf[2] = (png_byte)ep[i].blue;
908          entrybuf[3] = (png_byte)ep[i].alpha;
909          png_save_uint_16(entrybuf + 4, ep[i].frequency);
910      }
911      else
912      {
913          png_save_uint_16(entrybuf + 0, ep[i].red);
914          png_save_uint_16(entrybuf + 2, ep[i].green);
915          png_save_uint_16(entrybuf + 4, ep[i].blue);
916          png_save_uint_16(entrybuf + 6, ep[i].alpha);
917          png_save_uint_16(entrybuf + 8, ep[i].frequency);
918      }
919      png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
920   }
921#endif
922
923   png_write_chunk_end(png_ptr);
924   png_free(png_ptr, new_name);
925}
926#endif
927
928#ifdef PNG_WRITE_sBIT_SUPPORTED
929/* Write the sBIT chunk */
930void /* PRIVATE */
931png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
932{
933#ifdef PNG_USE_LOCAL_ARRAYS
934   PNG_sBIT;
935#endif
936   png_byte buf[4];
937   png_size_t size;
938
939   png_debug(1, "in png_write_sBIT");
940
941   /* Make sure we don't depend upon the order of PNG_COLOR_8 */
942   if (color_type & PNG_COLOR_MASK_COLOR)
943   {
944      png_byte maxbits;
945
946      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
947                png_ptr->usr_bit_depth);
948      if (sbit->red == 0 || sbit->red > maxbits ||
949          sbit->green == 0 || sbit->green > maxbits ||
950          sbit->blue == 0 || sbit->blue > maxbits)
951      {
952         png_warning(png_ptr, "Invalid sBIT depth specified");
953         return;
954      }
955      buf[0] = sbit->red;
956      buf[1] = sbit->green;
957      buf[2] = sbit->blue;
958      size = 3;
959   }
960   else
961   {
962      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
963      {
964         png_warning(png_ptr, "Invalid sBIT depth specified");
965         return;
966      }
967      buf[0] = sbit->gray;
968      size = 1;
969   }
970
971   if (color_type & PNG_COLOR_MASK_ALPHA)
972   {
973      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
974      {
975         png_warning(png_ptr, "Invalid sBIT depth specified");
976         return;
977      }
978      buf[size++] = sbit->alpha;
979   }
980
981   png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
982}
983#endif
984
985#ifdef PNG_WRITE_cHRM_SUPPORTED
986/* Write the cHRM chunk */
987#ifdef PNG_FLOATING_POINT_SUPPORTED
988void /* PRIVATE */
989png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
990   double red_x, double red_y, double green_x, double green_y,
991   double blue_x, double blue_y)
992{
993#ifdef PNG_USE_LOCAL_ARRAYS
994   PNG_cHRM;
995#endif
996   png_byte buf[32];
997
998   png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y,
999      int_green_x, int_green_y, int_blue_x, int_blue_y;
1000
1001   png_debug(1, "in png_write_cHRM");
1002
1003   int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5);
1004   int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5);
1005   int_red_x   = (png_uint_32)(red_x   * 100000.0 + 0.5);
1006   int_red_y   = (png_uint_32)(red_y   * 100000.0 + 0.5);
1007   int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5);
1008   int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5);
1009   int_blue_x  = (png_uint_32)(blue_x  * 100000.0 + 0.5);
1010   int_blue_y  = (png_uint_32)(blue_y  * 100000.0 + 0.5);
1011
1012#ifdef PNG_CHECK_cHRM_SUPPORTED
1013   if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y,
1014      int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y))
1015#endif
1016   {
1017      /* Each value is saved in 1/100,000ths */
1018
1019      png_save_uint_32(buf, int_white_x);
1020      png_save_uint_32(buf + 4, int_white_y);
1021
1022      png_save_uint_32(buf + 8, int_red_x);
1023      png_save_uint_32(buf + 12, int_red_y);
1024
1025      png_save_uint_32(buf + 16, int_green_x);
1026      png_save_uint_32(buf + 20, int_green_y);
1027
1028      png_save_uint_32(buf + 24, int_blue_x);
1029      png_save_uint_32(buf + 28, int_blue_y);
1030
1031      png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1032   }
1033}
1034#endif
1035#ifdef PNG_FIXED_POINT_SUPPORTED
1036void /* PRIVATE */
1037png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
1038   png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
1039   png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
1040   png_fixed_point blue_y)
1041{
1042#ifdef PNG_USE_LOCAL_ARRAYS
1043   PNG_cHRM;
1044#endif
1045   png_byte buf[32];
1046
1047   png_debug(1, "in png_write_cHRM");
1048
1049   /* Each value is saved in 1/100,000ths */
1050#ifdef PNG_CHECK_cHRM_SUPPORTED
1051   if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y,
1052      green_x, green_y, blue_x, blue_y))
1053#endif
1054   {
1055      png_save_uint_32(buf, (png_uint_32)white_x);
1056      png_save_uint_32(buf + 4, (png_uint_32)white_y);
1057
1058      png_save_uint_32(buf + 8, (png_uint_32)red_x);
1059      png_save_uint_32(buf + 12, (png_uint_32)red_y);
1060
1061      png_save_uint_32(buf + 16, (png_uint_32)green_x);
1062      png_save_uint_32(buf + 20, (png_uint_32)green_y);
1063
1064      png_save_uint_32(buf + 24, (png_uint_32)blue_x);
1065      png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1066
1067      png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1068   }
1069}
1070#endif
1071#endif
1072
1073#ifdef PNG_WRITE_tRNS_SUPPORTED
1074/* Write the tRNS chunk */
1075void /* PRIVATE */
1076png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
1077   int num_trans, int color_type)
1078{
1079#ifdef PNG_USE_LOCAL_ARRAYS
1080   PNG_tRNS;
1081#endif
1082   png_byte buf[6];
1083
1084   png_debug(1, "in png_write_tRNS");
1085
1086   if (color_type == PNG_COLOR_TYPE_PALETTE)
1087   {
1088      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
1089      {
1090         png_warning(png_ptr, "Invalid number of transparent colors specified");
1091         return;
1092      }
1093      /* Write the chunk out as it is */
1094      png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans,
1095        (png_size_t)num_trans);
1096   }
1097   else if (color_type == PNG_COLOR_TYPE_GRAY)
1098   {
1099      /* One 16 bit value */
1100      if (tran->gray >= (1 << png_ptr->bit_depth))
1101      {
1102         png_warning(png_ptr,
1103           "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
1104         return;
1105      }
1106      png_save_uint_16(buf, tran->gray);
1107      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
1108   }
1109   else if (color_type == PNG_COLOR_TYPE_RGB)
1110   {
1111      /* Three 16 bit values */
1112      png_save_uint_16(buf, tran->red);
1113      png_save_uint_16(buf + 2, tran->green);
1114      png_save_uint_16(buf + 4, tran->blue);
1115      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1116      {
1117         png_warning(png_ptr,
1118           "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
1119         return;
1120      }
1121      png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
1122   }
1123   else
1124   {
1125      png_warning(png_ptr, "Can't write tRNS with an alpha channel");
1126   }
1127}
1128#endif
1129
1130#ifdef PNG_WRITE_bKGD_SUPPORTED
1131/* Write the background chunk */
1132void /* PRIVATE */
1133png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
1134{
1135#ifdef PNG_USE_LOCAL_ARRAYS
1136   PNG_bKGD;
1137#endif
1138   png_byte buf[6];
1139
1140   png_debug(1, "in png_write_bKGD");
1141
1142   if (color_type == PNG_COLOR_TYPE_PALETTE)
1143   {
1144      if (
1145#ifdef PNG_MNG_FEATURES_SUPPORTED
1146          (png_ptr->num_palette ||
1147          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1148#endif
1149         back->index >= png_ptr->num_palette)
1150      {
1151         png_warning(png_ptr, "Invalid background palette index");
1152         return;
1153      }
1154      buf[0] = back->index;
1155      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
1156   }
1157   else if (color_type & PNG_COLOR_MASK_COLOR)
1158   {
1159      png_save_uint_16(buf, back->red);
1160      png_save_uint_16(buf + 2, back->green);
1161      png_save_uint_16(buf + 4, back->blue);
1162      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1163      {
1164         png_warning(png_ptr,
1165           "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
1166         return;
1167      }
1168      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
1169   }
1170   else
1171   {
1172      if (back->gray >= (1 << png_ptr->bit_depth))
1173      {
1174         png_warning(png_ptr,
1175           "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
1176         return;
1177      }
1178      png_save_uint_16(buf, back->gray);
1179      png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
1180   }
1181}
1182#endif
1183
1184#ifdef PNG_WRITE_hIST_SUPPORTED
1185/* Write the histogram */
1186void /* PRIVATE */
1187png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
1188{
1189#ifdef PNG_USE_LOCAL_ARRAYS
1190   PNG_hIST;
1191#endif
1192   int i;
1193   png_byte buf[3];
1194
1195   png_debug(1, "in png_write_hIST");
1196
1197   if (num_hist > (int)png_ptr->num_palette)
1198   {
1199      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
1200         png_ptr->num_palette);
1201      png_warning(png_ptr, "Invalid number of histogram entries specified");
1202      return;
1203   }
1204
1205   png_write_chunk_start(png_ptr, (png_bytep)png_hIST,
1206     (png_uint_32)(num_hist * 2));
1207   for (i = 0; i < num_hist; i++)
1208   {
1209      png_save_uint_16(buf, hist[i]);
1210      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
1211   }
1212   png_write_chunk_end(png_ptr);
1213}
1214#endif
1215
1216#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
1217    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
1218/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
1219 * and if invalid, correct the keyword rather than discarding the entire
1220 * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
1221 * length, forbids leading or trailing whitespace, multiple internal spaces,
1222 * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
1223 *
1224 * The new_key is allocated to hold the corrected keyword and must be freed
1225 * by the calling routine.  This avoids problems with trying to write to
1226 * static keywords without having to have duplicate copies of the strings.
1227 */
1228png_size_t /* PRIVATE */
1229png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
1230{
1231   png_size_t key_len;
1232   png_charp kp, dp;
1233   int kflag;
1234   int kwarn=0;
1235
1236   png_debug(1, "in png_check_keyword");
1237
1238   *new_key = NULL;
1239
1240   if (key == NULL || (key_len = png_strlen(key)) == 0)
1241   {
1242      png_warning(png_ptr, "zero length keyword");
1243      return ((png_size_t)0);
1244   }
1245
1246   png_debug1(2, "Keyword to be checked is '%s'", key);
1247
1248   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
1249   if (*new_key == NULL)
1250   {
1251      png_warning(png_ptr, "Out of memory while procesing keyword");
1252      return ((png_size_t)0);
1253   }
1254
1255   /* Replace non-printing characters with a blank and print a warning */
1256   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
1257   {
1258      if ((png_byte)*kp < 0x20 ||
1259         ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
1260      {
1261#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
1262         char msg[40];
1263
1264         png_snprintf(msg, 40,
1265           "invalid keyword character 0x%02X", (png_byte)*kp);
1266         png_warning(png_ptr, msg);
1267#else
1268         png_warning(png_ptr, "invalid character in keyword");
1269#endif
1270         *dp = ' ';
1271      }
1272      else
1273      {
1274         *dp = *kp;
1275      }
1276   }
1277   *dp = '\0';
1278
1279   /* Remove any trailing white space. */
1280   kp = *new_key + key_len - 1;
1281   if (*kp == ' ')
1282   {
1283      png_warning(png_ptr, "trailing spaces removed from keyword");
1284
1285      while (*kp == ' ')
1286      {
1287         *(kp--) = '\0';
1288         key_len--;
1289      }
1290   }
1291
1292   /* Remove any leading white space. */
1293   kp = *new_key;
1294   if (*kp == ' ')
1295   {
1296      png_warning(png_ptr, "leading spaces removed from keyword");
1297
1298      while (*kp == ' ')
1299      {
1300         kp++;
1301         key_len--;
1302      }
1303   }
1304
1305   png_debug1(2, "Checking for multiple internal spaces in '%s'", kp);
1306
1307   /* Remove multiple internal spaces. */
1308   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
1309   {
1310      if (*kp == ' ' && kflag == 0)
1311      {
1312         *(dp++) = *kp;
1313         kflag = 1;
1314      }
1315      else if (*kp == ' ')
1316      {
1317         key_len--;
1318         kwarn=1;
1319      }
1320      else
1321      {
1322         *(dp++) = *kp;
1323         kflag = 0;
1324      }
1325   }
1326   *dp = '\0';
1327   if (kwarn)
1328      png_warning(png_ptr, "extra interior spaces removed from keyword");
1329
1330   if (key_len == 0)
1331   {
1332      png_free(png_ptr, *new_key);
1333       *new_key=NULL;
1334      png_warning(png_ptr, "Zero length keyword");
1335   }
1336
1337   if (key_len > 79)
1338   {
1339      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
1340      (*new_key)[79] = '\0';
1341      key_len = 79;
1342   }
1343
1344   return (key_len);
1345}
1346#endif
1347
1348#ifdef PNG_WRITE_tEXt_SUPPORTED
1349/* Write a tEXt chunk */
1350void /* PRIVATE */
1351png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
1352   png_size_t text_len)
1353{
1354#ifdef PNG_USE_LOCAL_ARRAYS
1355   PNG_tEXt;
1356#endif
1357   png_size_t key_len;
1358   png_charp new_key;
1359
1360   png_debug(1, "in png_write_tEXt");
1361
1362   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
1363      return;
1364
1365   if (text == NULL || *text == '\0')
1366      text_len = 0;
1367   else
1368      text_len = png_strlen(text);
1369
1370   /* Make sure we include the 0 after the key */
1371   png_write_chunk_start(png_ptr, (png_bytep)png_tEXt,
1372      (png_uint_32)(key_len + text_len + 1));
1373   /*
1374    * We leave it to the application to meet PNG-1.0 requirements on the
1375    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
1376    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
1377    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1378    */
1379   png_write_chunk_data(png_ptr, (png_bytep)new_key,
1380     (png_size_t)(key_len + 1));
1381   if (text_len)
1382      png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len);
1383
1384   png_write_chunk_end(png_ptr);
1385   png_free(png_ptr, new_key);
1386}
1387#endif
1388
1389#ifdef PNG_WRITE_zTXt_SUPPORTED
1390/* Write a compressed text chunk */
1391void /* PRIVATE */
1392png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
1393   png_size_t text_len, int compression)
1394{
1395#ifdef PNG_USE_LOCAL_ARRAYS
1396   PNG_zTXt;
1397#endif
1398   png_size_t key_len;
1399   char buf[1];
1400   png_charp new_key;
1401   compression_state comp;
1402
1403   png_debug(1, "in png_write_zTXt");
1404
1405   comp.num_output_ptr = 0;
1406   comp.max_output_ptr = 0;
1407   comp.output_ptr = NULL;
1408   comp.input = NULL;
1409   comp.input_len = 0;
1410
1411   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
1412   {
1413      png_free(png_ptr, new_key);
1414      return;
1415   }
1416
1417   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
1418   {
1419      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
1420      png_free(png_ptr, new_key);
1421      return;
1422   }
1423
1424   text_len = png_strlen(text);
1425
1426   /* Compute the compressed data; do it now for the length */
1427   text_len = png_text_compress(png_ptr, text, text_len, compression,
1428       &comp);
1429
1430   /* Write start of chunk */
1431   png_write_chunk_start(png_ptr, (png_bytep)png_zTXt,
1432     (png_uint_32)(key_len+text_len + 2));
1433   /* Write key */
1434   png_write_chunk_data(png_ptr, (png_bytep)new_key,
1435     (png_size_t)(key_len + 1));
1436   png_free(png_ptr, new_key);
1437
1438   buf[0] = (png_byte)compression;
1439   /* Write compression */
1440   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
1441   /* Write the compressed data */
1442   png_write_compressed_data_out(png_ptr, &comp);
1443
1444   /* Close the chunk */
1445   png_write_chunk_end(png_ptr);
1446}
1447#endif
1448
1449#ifdef PNG_WRITE_iTXt_SUPPORTED
1450/* Write an iTXt chunk */
1451void /* PRIVATE */
1452png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1453    png_charp lang, png_charp lang_key, png_charp text)
1454{
1455#ifdef PNG_USE_LOCAL_ARRAYS
1456   PNG_iTXt;
1457#endif
1458   png_size_t lang_len, key_len, lang_key_len, text_len;
1459   png_charp new_lang;
1460   png_charp new_key = NULL;
1461   png_byte cbuf[2];
1462   compression_state comp;
1463
1464   png_debug(1, "in png_write_iTXt");
1465
1466   comp.num_output_ptr = 0;
1467   comp.max_output_ptr = 0;
1468   comp.output_ptr = NULL;
1469   comp.input = NULL;
1470
1471   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
1472      return;
1473
1474   if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1475   {
1476      png_warning(png_ptr, "Empty language field in iTXt chunk");
1477      new_lang = NULL;
1478      lang_len = 0;
1479   }
1480
1481   if (lang_key == NULL)
1482      lang_key_len = 0;
1483   else
1484      lang_key_len = png_strlen(lang_key);
1485
1486   if (text == NULL)
1487      text_len = 0;
1488   else
1489      text_len = png_strlen(text);
1490
1491   /* Compute the compressed data; do it now for the length */
1492   text_len = png_text_compress(png_ptr, text, text_len, compression-2,
1493      &comp);
1494
1495
1496   /* Make sure we include the compression flag, the compression byte,
1497    * and the NULs after the key, lang, and lang_key parts */
1498
1499   png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
1500          (png_uint_32)(
1501        5 /* comp byte, comp flag, terminators for key, lang and lang_key */
1502        + key_len
1503        + lang_len
1504        + lang_key_len
1505        + text_len));
1506
1507   /* We leave it to the application to meet PNG-1.0 requirements on the
1508    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
1509    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
1510    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1511    */
1512   png_write_chunk_data(png_ptr, (png_bytep)new_key,
1513     (png_size_t)(key_len + 1));
1514
1515   /* Set the compression flag */
1516   if (compression == PNG_ITXT_COMPRESSION_NONE || \
1517       compression == PNG_TEXT_COMPRESSION_NONE)
1518       cbuf[0] = 0;
1519   else /* compression == PNG_ITXT_COMPRESSION_zTXt */
1520       cbuf[0] = 1;
1521   /* Set the compression method */
1522   cbuf[1] = 0;
1523   png_write_chunk_data(png_ptr, cbuf, (png_size_t)2);
1524
1525   cbuf[0] = 0;
1526   png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf),
1527     (png_size_t)(lang_len + 1));
1528   png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf),
1529     (png_size_t)(lang_key_len + 1));
1530   png_write_compressed_data_out(png_ptr, &comp);
1531
1532   png_write_chunk_end(png_ptr);
1533   png_free(png_ptr, new_key);
1534   png_free(png_ptr, new_lang);
1535}
1536#endif
1537
1538#ifdef PNG_WRITE_oFFs_SUPPORTED
1539/* Write the oFFs chunk */
1540void /* PRIVATE */
1541png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
1542   int unit_type)
1543{
1544#ifdef PNG_USE_LOCAL_ARRAYS
1545   PNG_oFFs;
1546#endif
1547   png_byte buf[9];
1548
1549   png_debug(1, "in png_write_oFFs");
1550
1551   if (unit_type >= PNG_OFFSET_LAST)
1552      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
1553
1554   png_save_int_32(buf, x_offset);
1555   png_save_int_32(buf + 4, y_offset);
1556   buf[8] = (png_byte)unit_type;
1557
1558   png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
1559}
1560#endif
1561#ifdef PNG_WRITE_pCAL_SUPPORTED
1562/* Write the pCAL chunk (described in the PNG extensions document) */
1563void /* PRIVATE */
1564png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
1565   png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
1566{
1567#ifdef PNG_USE_LOCAL_ARRAYS
1568   PNG_pCAL;
1569#endif
1570   png_size_t purpose_len, units_len, total_len;
1571   png_uint_32p params_len;
1572   png_byte buf[10];
1573   png_charp new_purpose;
1574   int i;
1575
1576   png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
1577
1578   if (type >= PNG_EQUATION_LAST)
1579      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1580
1581   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
1582   png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
1583   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1584   png_debug1(3, "pCAL units length = %d", (int)units_len);
1585   total_len = purpose_len + units_len + 10;
1586
1587   params_len = (png_uint_32p)png_malloc(png_ptr,
1588      (png_uint_32)(nparams * png_sizeof(png_uint_32)));
1589
1590   /* Find the length of each parameter, making sure we don't count the
1591      null terminator for the last parameter. */
1592   for (i = 0; i < nparams; i++)
1593   {
1594      params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
1595      png_debug2(3, "pCAL parameter %d length = %lu", i,
1596        (unsigned long) params_len[i]);
1597      total_len += (png_size_t)params_len[i];
1598   }
1599
1600   png_debug1(3, "pCAL total length = %d", (int)total_len);
1601   png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
1602   png_write_chunk_data(png_ptr, (png_bytep)new_purpose,
1603     (png_size_t)purpose_len);
1604   png_save_int_32(buf, X0);
1605   png_save_int_32(buf + 4, X1);
1606   buf[8] = (png_byte)type;
1607   buf[9] = (png_byte)nparams;
1608   png_write_chunk_data(png_ptr, buf, (png_size_t)10);
1609   png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
1610
1611   png_free(png_ptr, new_purpose);
1612
1613   for (i = 0; i < nparams; i++)
1614   {
1615      png_write_chunk_data(png_ptr, (png_bytep)params[i],
1616         (png_size_t)params_len[i]);
1617   }
1618
1619   png_free(png_ptr, params_len);
1620   png_write_chunk_end(png_ptr);
1621}
1622#endif
1623
1624#ifdef PNG_WRITE_sCAL_SUPPORTED
1625/* Write the sCAL chunk */
1626#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
1627void /* PRIVATE */
1628png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
1629{
1630#ifdef PNG_USE_LOCAL_ARRAYS
1631   PNG_sCAL;
1632#endif
1633   char buf[64];
1634   png_size_t total_len;
1635
1636   png_debug(1, "in png_write_sCAL");
1637
1638   buf[0] = (char)unit;
1639#ifdef _WIN32_WCE
1640/* sprintf() function is not supported on WindowsCE */
1641   {
1642      wchar_t wc_buf[32];
1643      size_t wc_len;
1644      swprintf(wc_buf, TEXT("%12.12e"), width);
1645      wc_len = wcslen(wc_buf);
1646      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL,
1647          NULL);
1648      total_len = wc_len + 2;
1649      swprintf(wc_buf, TEXT("%12.12e"), height);
1650      wc_len = wcslen(wc_buf);
1651      WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len,
1652         NULL, NULL);
1653      total_len += wc_len;
1654   }
1655#else
1656   png_snprintf(buf + 1, 63, "%12.12e", width);
1657   total_len = 1 + png_strlen(buf + 1) + 1;
1658   png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
1659   total_len += png_strlen(buf + total_len);
1660#endif
1661
1662   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1663   png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len);
1664}
1665#else
1666#ifdef PNG_FIXED_POINT_SUPPORTED
1667void /* PRIVATE */
1668png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1669   png_charp height)
1670{
1671#ifdef PNG_USE_LOCAL_ARRAYS
1672   PNG_sCAL;
1673#endif
1674   png_byte buf[64];
1675   png_size_t wlen, hlen, total_len;
1676
1677   png_debug(1, "in png_write_sCAL_s");
1678
1679   wlen = png_strlen(width);
1680   hlen = png_strlen(height);
1681   total_len = wlen + hlen + 2;
1682   if (total_len > 64)
1683   {
1684      png_warning(png_ptr, "Can't write sCAL (buffer too small)");
1685      return;
1686   }
1687
1688   buf[0] = (png_byte)unit;
1689   png_memcpy(buf + 1, width, wlen + 1);      /* Append the '\0' here */
1690   png_memcpy(buf + wlen + 2, height, hlen);  /* Do NOT append the '\0' here */
1691
1692   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1693   png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len);
1694}
1695#endif
1696#endif
1697#endif
1698
1699#ifdef PNG_WRITE_pHYs_SUPPORTED
1700/* Write the pHYs chunk */
1701void /* PRIVATE */
1702png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
1703   png_uint_32 y_pixels_per_unit,
1704   int unit_type)
1705{
1706#ifdef PNG_USE_LOCAL_ARRAYS
1707   PNG_pHYs;
1708#endif
1709   png_byte buf[9];
1710
1711   png_debug(1, "in png_write_pHYs");
1712
1713   if (unit_type >= PNG_RESOLUTION_LAST)
1714      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
1715
1716   png_save_uint_32(buf, x_pixels_per_unit);
1717   png_save_uint_32(buf + 4, y_pixels_per_unit);
1718   buf[8] = (png_byte)unit_type;
1719
1720   png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
1721}
1722#endif
1723
1724#ifdef PNG_WRITE_tIME_SUPPORTED
1725/* Write the tIME chunk.  Use either png_convert_from_struct_tm()
1726 * or png_convert_from_time_t(), or fill in the structure yourself.
1727 */
1728void /* PRIVATE */
1729png_write_tIME(png_structp png_ptr, png_timep mod_time)
1730{
1731#ifdef PNG_USE_LOCAL_ARRAYS
1732   PNG_tIME;
1733#endif
1734   png_byte buf[7];
1735
1736   png_debug(1, "in png_write_tIME");
1737
1738   if (mod_time->month  > 12 || mod_time->month  < 1 ||
1739       mod_time->day    > 31 || mod_time->day    < 1 ||
1740       mod_time->hour   > 23 || mod_time->second > 60)
1741   {
1742      png_warning(png_ptr, "Invalid time specified for tIME chunk");
1743      return;
1744   }
1745
1746   png_save_uint_16(buf, mod_time->year);
1747   buf[2] = mod_time->month;
1748   buf[3] = mod_time->day;
1749   buf[4] = mod_time->hour;
1750   buf[5] = mod_time->minute;
1751   buf[6] = mod_time->second;
1752
1753   png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
1754}
1755#endif
1756
1757/* Initializes the row writing capability of libpng */
1758void /* PRIVATE */
1759png_write_start_row(png_structp png_ptr)
1760{
1761#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1762   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1763
1764   /* Start of interlace block */
1765   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1766
1767   /* Offset to next interlace block */
1768   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1769
1770   /* Start of interlace block in the y direction */
1771   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1772
1773   /* Offset to next interlace block in the y direction */
1774   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1775#endif
1776
1777   png_size_t buf_size;
1778
1779   png_debug(1, "in png_write_start_row");
1780
1781   buf_size = (png_size_t)(PNG_ROWBYTES(
1782      png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1);
1783
1784   /* Set up row buffer */
1785   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr,
1786     (png_uint_32)buf_size);
1787   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
1788
1789#ifdef PNG_WRITE_FILTER_SUPPORTED
1790   /* Set up filtering buffer, if using this filter */
1791   if (png_ptr->do_filter & PNG_FILTER_SUB)
1792   {
1793      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1794         (png_uint_32)(png_ptr->rowbytes + 1));
1795      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
1796   }
1797
1798   /* We only need to keep the previous row if we are using one of these. */
1799   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
1800   {
1801      /* Set up previous row buffer */
1802      png_ptr->prev_row = (png_bytep)png_calloc(png_ptr,
1803         (png_uint_32)buf_size);
1804
1805      if (png_ptr->do_filter & PNG_FILTER_UP)
1806      {
1807         png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1808            (png_uint_32)(png_ptr->rowbytes + 1));
1809         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
1810      }
1811
1812      if (png_ptr->do_filter & PNG_FILTER_AVG)
1813      {
1814         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1815            (png_uint_32)(png_ptr->rowbytes + 1));
1816         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
1817      }
1818
1819      if (png_ptr->do_filter & PNG_FILTER_PAETH)
1820      {
1821         png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1822            (png_uint_32)(png_ptr->rowbytes + 1));
1823         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
1824      }
1825   }
1826#endif /* PNG_WRITE_FILTER_SUPPORTED */
1827
1828#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1829   /* If interlaced, we need to set up width and height of pass */
1830   if (png_ptr->interlaced)
1831   {
1832      if (!(png_ptr->transformations & PNG_INTERLACE))
1833      {
1834         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1835            png_pass_ystart[0]) / png_pass_yinc[0];
1836         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
1837            png_pass_start[0]) / png_pass_inc[0];
1838      }
1839      else
1840      {
1841         png_ptr->num_rows = png_ptr->height;
1842         png_ptr->usr_width = png_ptr->width;
1843      }
1844   }
1845   else
1846#endif
1847   {
1848      png_ptr->num_rows = png_ptr->height;
1849      png_ptr->usr_width = png_ptr->width;
1850   }
1851   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
1852   png_ptr->zstream.next_out = png_ptr->zbuf;
1853}
1854
1855/* Internal use only.  Called when finished processing a row of data. */
1856void /* PRIVATE */
1857png_write_finish_row(png_structp png_ptr)
1858{
1859#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1860   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1861
1862   /* Start of interlace block */
1863   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1864
1865   /* Offset to next interlace block */
1866   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1867
1868   /* Start of interlace block in the y direction */
1869   int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1870
1871   /* Offset to next interlace block in the y direction */
1872   int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1873#endif
1874
1875   int ret;
1876
1877   png_debug(1, "in png_write_finish_row");
1878
1879   /* Next row */
1880   png_ptr->row_number++;
1881
1882   /* See if we are done */
1883   if (png_ptr->row_number < png_ptr->num_rows)
1884      return;
1885
1886#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1887   /* If interlaced, go to next pass */
1888   if (png_ptr->interlaced)
1889   {
1890      png_ptr->row_number = 0;
1891      if (png_ptr->transformations & PNG_INTERLACE)
1892      {
1893         png_ptr->pass++;
1894      }
1895      else
1896      {
1897         /* Loop until we find a non-zero width or height pass */
1898         do
1899         {
1900            png_ptr->pass++;
1901            if (png_ptr->pass >= 7)
1902               break;
1903            png_ptr->usr_width = (png_ptr->width +
1904               png_pass_inc[png_ptr->pass] - 1 -
1905               png_pass_start[png_ptr->pass]) /
1906               png_pass_inc[png_ptr->pass];
1907            png_ptr->num_rows = (png_ptr->height +
1908               png_pass_yinc[png_ptr->pass] - 1 -
1909               png_pass_ystart[png_ptr->pass]) /
1910               png_pass_yinc[png_ptr->pass];
1911            if (png_ptr->transformations & PNG_INTERLACE)
1912               break;
1913         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
1914
1915      }
1916
1917      /* Reset the row above the image for the next pass */
1918      if (png_ptr->pass < 7)
1919      {
1920         if (png_ptr->prev_row != NULL)
1921            png_memset(png_ptr->prev_row, 0,
1922               (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
1923               png_ptr->usr_bit_depth, png_ptr->width)) + 1);
1924         return;
1925      }
1926   }
1927#endif
1928
1929   /* If we get here, we've just written the last row, so we need
1930      to flush the compressor */
1931   do
1932   {
1933      /* Tell the compressor we are done */
1934      ret = deflate(&png_ptr->zstream, Z_FINISH);
1935      /* Check for an error */
1936      if (ret == Z_OK)
1937      {
1938         /* Check to see if we need more room */
1939         if (!(png_ptr->zstream.avail_out))
1940         {
1941            png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
1942            png_ptr->zstream.next_out = png_ptr->zbuf;
1943            png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
1944         }
1945      }
1946      else if (ret != Z_STREAM_END)
1947      {
1948         if (png_ptr->zstream.msg != NULL)
1949            png_error(png_ptr, png_ptr->zstream.msg);
1950         else
1951            png_error(png_ptr, "zlib error");
1952      }
1953   } while (ret != Z_STREAM_END);
1954
1955   /* Write any extra space */
1956   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
1957   {
1958      png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
1959         png_ptr->zstream.avail_out);
1960   }
1961
1962   deflateReset(&png_ptr->zstream);
1963   png_ptr->zstream.data_type = Z_BINARY;
1964}
1965
1966#ifdef PNG_WRITE_INTERLACING_SUPPORTED
1967/* Pick out the correct pixels for the interlace pass.
1968 * The basic idea here is to go through the row with a source
1969 * pointer and a destination pointer (sp and dp), and copy the
1970 * correct pixels for the pass.  As the row gets compacted,
1971 * sp will always be >= dp, so we should never overwrite anything.
1972 * See the default: case for the easiest code to understand.
1973 */
1974void /* PRIVATE */
1975png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
1976{
1977   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1978
1979   /* Start of interlace block */
1980   int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1981
1982   /* Offset to next interlace block */
1983   int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1984
1985   png_debug(1, "in png_do_write_interlace");
1986
1987   /* We don't have to do anything on the last pass (6) */
1988#ifdef PNG_USELESS_TESTS_SUPPORTED
1989   if (row != NULL && row_info != NULL && pass < 6)
1990#else
1991   if (pass < 6)
1992#endif
1993   {
1994      /* Each pixel depth is handled separately */
1995      switch (row_info->pixel_depth)
1996      {
1997         case 1:
1998         {
1999            png_bytep sp;
2000            png_bytep dp;
2001            int shift;
2002            int d;
2003            int value;
2004            png_uint_32 i;
2005            png_uint_32 row_width = row_info->width;
2006
2007            dp = row;
2008            d = 0;
2009            shift = 7;
2010            for (i = png_pass_start[pass]; i < row_width;
2011               i += png_pass_inc[pass])
2012            {
2013               sp = row + (png_size_t)(i >> 3);
2014               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
2015               d |= (value << shift);
2016
2017               if (shift == 0)
2018               {
2019                  shift = 7;
2020                  *dp++ = (png_byte)d;
2021                  d = 0;
2022               }
2023               else
2024                  shift--;
2025
2026            }
2027            if (shift != 7)
2028               *dp = (png_byte)d;
2029            break;
2030         }
2031         case 2:
2032         {
2033            png_bytep sp;
2034            png_bytep dp;
2035            int shift;
2036            int d;
2037            int value;
2038            png_uint_32 i;
2039            png_uint_32 row_width = row_info->width;
2040
2041            dp = row;
2042            shift = 6;
2043            d = 0;
2044            for (i = png_pass_start[pass]; i < row_width;
2045               i += png_pass_inc[pass])
2046            {
2047               sp = row + (png_size_t)(i >> 2);
2048               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
2049               d |= (value << shift);
2050
2051               if (shift == 0)
2052               {
2053                  shift = 6;
2054                  *dp++ = (png_byte)d;
2055                  d = 0;
2056               }
2057               else
2058                  shift -= 2;
2059            }
2060            if (shift != 6)
2061                   *dp = (png_byte)d;
2062            break;
2063         }
2064         case 4:
2065         {
2066            png_bytep sp;
2067            png_bytep dp;
2068            int shift;
2069            int d;
2070            int value;
2071            png_uint_32 i;
2072            png_uint_32 row_width = row_info->width;
2073
2074            dp = row;
2075            shift = 4;
2076            d = 0;
2077            for (i = png_pass_start[pass]; i < row_width;
2078               i += png_pass_inc[pass])
2079            {
2080               sp = row + (png_size_t)(i >> 1);
2081               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
2082               d |= (value << shift);
2083
2084               if (shift == 0)
2085               {
2086                  shift = 4;
2087                  *dp++ = (png_byte)d;
2088                  d = 0;
2089               }
2090               else
2091                  shift -= 4;
2092            }
2093            if (shift != 4)
2094               *dp = (png_byte)d;
2095            break;
2096         }
2097         default:
2098         {
2099            png_bytep sp;
2100            png_bytep dp;
2101            png_uint_32 i;
2102            png_uint_32 row_width = row_info->width;
2103            png_size_t pixel_bytes;
2104
2105            /* Start at the beginning */
2106            dp = row;
2107            /* Find out how many bytes each pixel takes up */
2108            pixel_bytes = (row_info->pixel_depth >> 3);
2109            /* Loop through the row, only looking at the pixels that
2110               matter */
2111            for (i = png_pass_start[pass]; i < row_width;
2112               i += png_pass_inc[pass])
2113            {
2114               /* Find out where the original pixel is */
2115               sp = row + (png_size_t)i * pixel_bytes;
2116               /* Move the pixel */
2117               if (dp != sp)
2118                  png_memcpy(dp, sp, pixel_bytes);
2119               /* Next pixel */
2120               dp += pixel_bytes;
2121            }
2122            break;
2123         }
2124      }
2125      /* Set new row width */
2126      row_info->width = (row_info->width +
2127         png_pass_inc[pass] - 1 -
2128         png_pass_start[pass]) /
2129         png_pass_inc[pass];
2130         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
2131            row_info->width);
2132   }
2133}
2134#endif
2135
2136/* This filters the row, chooses which filter to use, if it has not already
2137 * been specified by the application, and then writes the row out with the
2138 * chosen filter.
2139 */
2140#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
2141#define PNG_HISHIFT 10
2142#define PNG_LOMASK ((png_uint_32)0xffffL)
2143#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2144void /* PRIVATE */
2145png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
2146{
2147   png_bytep best_row;
2148#ifdef PNG_WRITE_FILTER_SUPPORTED
2149   png_bytep prev_row, row_buf;
2150   png_uint_32 mins, bpp;
2151   png_byte filter_to_do = png_ptr->do_filter;
2152   png_uint_32 row_bytes = row_info->rowbytes;
2153#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2154   int num_p_filters = (int)png_ptr->num_prev_filters;
2155#endif
2156
2157   png_debug(1, "in png_write_find_filter");
2158
2159#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2160  if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
2161  {
2162      /* These will never be selected so we need not test them. */
2163      filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
2164  }
2165#endif
2166
2167   /* Find out how many bytes offset each pixel is */
2168   bpp = (row_info->pixel_depth + 7) >> 3;
2169
2170   prev_row = png_ptr->prev_row;
2171#endif
2172   best_row = png_ptr->row_buf;
2173#ifdef PNG_WRITE_FILTER_SUPPORTED
2174   row_buf = best_row;
2175   mins = PNG_MAXSUM;
2176
2177   /* The prediction method we use is to find which method provides the
2178    * smallest value when summing the absolute values of the distances
2179    * from zero, using anything >= 128 as negative numbers.  This is known
2180    * as the "minimum sum of absolute differences" heuristic.  Other
2181    * heuristics are the "weighted minimum sum of absolute differences"
2182    * (experimental and can in theory improve compression), and the "zlib
2183    * predictive" method (not implemented yet), which does test compressions
2184    * of lines using different filter methods, and then chooses the
2185    * (series of) filter(s) that give minimum compressed data size (VERY
2186    * computationally expensive).
2187    *
2188    * GRR 980525:  consider also
2189    *   (1) minimum sum of absolute differences from running average (i.e.,
2190    *       keep running sum of non-absolute differences & count of bytes)
2191    *       [track dispersion, too?  restart average if dispersion too large?]
2192    *  (1b) minimum sum of absolute differences from sliding average, probably
2193    *       with window size <= deflate window (usually 32K)
2194    *   (2) minimum sum of squared differences from zero or running average
2195    *       (i.e., ~ root-mean-square approach)
2196    */
2197
2198
2199   /* We don't need to test the 'no filter' case if this is the only filter
2200    * that has been chosen, as it doesn't actually do anything to the data.
2201    */
2202   if ((filter_to_do & PNG_FILTER_NONE) &&
2203       filter_to_do != PNG_FILTER_NONE)
2204   {
2205      png_bytep rp;
2206      png_uint_32 sum = 0;
2207      png_uint_32 i;
2208      int v;
2209
2210      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
2211      {
2212         v = *rp;
2213         sum += (v < 128) ? v : 256 - v;
2214      }
2215
2216#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2217      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2218      {
2219         png_uint_32 sumhi, sumlo;
2220         int j;
2221         sumlo = sum & PNG_LOMASK;
2222         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
2223
2224         /* Reduce the sum if we match any of the previous rows */
2225         for (j = 0; j < num_p_filters; j++)
2226         {
2227            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
2228            {
2229               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
2230                  PNG_WEIGHT_SHIFT;
2231               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
2232                  PNG_WEIGHT_SHIFT;
2233            }
2234         }
2235
2236         /* Factor in the cost of this filter (this is here for completeness,
2237          * but it makes no sense to have a "cost" for the NONE filter, as
2238          * it has the minimum possible computational cost - none).
2239          */
2240         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
2241            PNG_COST_SHIFT;
2242         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
2243            PNG_COST_SHIFT;
2244
2245         if (sumhi > PNG_HIMASK)
2246            sum = PNG_MAXSUM;
2247         else
2248            sum = (sumhi << PNG_HISHIFT) + sumlo;
2249      }
2250#endif
2251      mins = sum;
2252   }
2253
2254   /* Sub filter */
2255   if (filter_to_do == PNG_FILTER_SUB)
2256   /* It's the only filter so no testing is needed */
2257   {
2258      png_bytep rp, lp, dp;
2259      png_uint_32 i;
2260      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
2261           i++, rp++, dp++)
2262      {
2263         *dp = *rp;
2264      }
2265      for (lp = row_buf + 1; i < row_bytes;
2266         i++, rp++, lp++, dp++)
2267      {
2268         *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
2269      }
2270      best_row = png_ptr->sub_row;
2271   }
2272
2273   else if (filter_to_do & PNG_FILTER_SUB)
2274   {
2275      png_bytep rp, dp, lp;
2276      png_uint_32 sum = 0, lmins = mins;
2277      png_uint_32 i;
2278      int v;
2279
2280#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2281      /* We temporarily increase the "minimum sum" by the factor we
2282       * would reduce the sum of this filter, so that we can do the
2283       * early exit comparison without scaling the sum each time.
2284       */
2285      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2286      {
2287         int j;
2288         png_uint_32 lmhi, lmlo;
2289         lmlo = lmins & PNG_LOMASK;
2290         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
2291
2292         for (j = 0; j < num_p_filters; j++)
2293         {
2294            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
2295            {
2296               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
2297                  PNG_WEIGHT_SHIFT;
2298               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
2299                  PNG_WEIGHT_SHIFT;
2300            }
2301         }
2302
2303         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
2304            PNG_COST_SHIFT;
2305         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
2306            PNG_COST_SHIFT;
2307
2308         if (lmhi > PNG_HIMASK)
2309            lmins = PNG_MAXSUM;
2310         else
2311            lmins = (lmhi << PNG_HISHIFT) + lmlo;
2312      }
2313#endif
2314
2315      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
2316           i++, rp++, dp++)
2317      {
2318         v = *dp = *rp;
2319
2320         sum += (v < 128) ? v : 256 - v;
2321      }
2322      for (lp = row_buf + 1; i < row_bytes;
2323         i++, rp++, lp++, dp++)
2324      {
2325         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
2326
2327         sum += (v < 128) ? v : 256 - v;
2328
2329         if (sum > lmins)  /* We are already worse, don't continue. */
2330            break;
2331      }
2332
2333#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2334      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2335      {
2336         int j;
2337         png_uint_32 sumhi, sumlo;
2338         sumlo = sum & PNG_LOMASK;
2339         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
2340
2341         for (j = 0; j < num_p_filters; j++)
2342         {
2343            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
2344            {
2345               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
2346                  PNG_WEIGHT_SHIFT;
2347               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
2348                  PNG_WEIGHT_SHIFT;
2349            }
2350         }
2351
2352         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
2353            PNG_COST_SHIFT;
2354         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
2355            PNG_COST_SHIFT;
2356
2357         if (sumhi > PNG_HIMASK)
2358            sum = PNG_MAXSUM;
2359         else
2360            sum = (sumhi << PNG_HISHIFT) + sumlo;
2361      }
2362#endif
2363
2364      if (sum < mins)
2365      {
2366         mins = sum;
2367         best_row = png_ptr->sub_row;
2368      }
2369   }
2370
2371   /* Up filter */
2372   if (filter_to_do == PNG_FILTER_UP)
2373   {
2374      png_bytep rp, dp, pp;
2375      png_uint_32 i;
2376
2377      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2378           pp = prev_row + 1; i < row_bytes;
2379           i++, rp++, pp++, dp++)
2380      {
2381         *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
2382      }
2383      best_row = png_ptr->up_row;
2384   }
2385
2386   else if (filter_to_do & PNG_FILTER_UP)
2387   {
2388      png_bytep rp, dp, pp;
2389      png_uint_32 sum = 0, lmins = mins;
2390      png_uint_32 i;
2391      int v;
2392
2393
2394#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2395      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2396      {
2397         int j;
2398         png_uint_32 lmhi, lmlo;
2399         lmlo = lmins & PNG_LOMASK;
2400         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
2401
2402         for (j = 0; j < num_p_filters; j++)
2403         {
2404            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
2405            {
2406               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
2407                  PNG_WEIGHT_SHIFT;
2408               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
2409                  PNG_WEIGHT_SHIFT;
2410            }
2411         }
2412
2413         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
2414            PNG_COST_SHIFT;
2415         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
2416            PNG_COST_SHIFT;
2417
2418         if (lmhi > PNG_HIMASK)
2419            lmins = PNG_MAXSUM;
2420         else
2421            lmins = (lmhi << PNG_HISHIFT) + lmlo;
2422      }
2423#endif
2424
2425      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2426           pp = prev_row + 1; i < row_bytes; i++)
2427      {
2428         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2429
2430         sum += (v < 128) ? v : 256 - v;
2431
2432         if (sum > lmins)  /* We are already worse, don't continue. */
2433            break;
2434      }
2435
2436#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2437      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2438      {
2439         int j;
2440         png_uint_32 sumhi, sumlo;
2441         sumlo = sum & PNG_LOMASK;
2442         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
2443
2444         for (j = 0; j < num_p_filters; j++)
2445         {
2446            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
2447            {
2448               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
2449                  PNG_WEIGHT_SHIFT;
2450               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
2451                  PNG_WEIGHT_SHIFT;
2452            }
2453         }
2454
2455         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
2456            PNG_COST_SHIFT;
2457         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
2458            PNG_COST_SHIFT;
2459
2460         if (sumhi > PNG_HIMASK)
2461            sum = PNG_MAXSUM;
2462         else
2463            sum = (sumhi << PNG_HISHIFT) + sumlo;
2464      }
2465#endif
2466
2467      if (sum < mins)
2468      {
2469         mins = sum;
2470         best_row = png_ptr->up_row;
2471      }
2472   }
2473
2474   /* Avg filter */
2475   if (filter_to_do == PNG_FILTER_AVG)
2476   {
2477      png_bytep rp, dp, pp, lp;
2478      png_uint_32 i;
2479      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2480           pp = prev_row + 1; i < bpp; i++)
2481      {
2482         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2483      }
2484      for (lp = row_buf + 1; i < row_bytes; i++)
2485      {
2486         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
2487                 & 0xff);
2488      }
2489      best_row = png_ptr->avg_row;
2490   }
2491
2492   else if (filter_to_do & PNG_FILTER_AVG)
2493   {
2494      png_bytep rp, dp, pp, lp;
2495      png_uint_32 sum = 0, lmins = mins;
2496      png_uint_32 i;
2497      int v;
2498
2499#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2500      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2501      {
2502         int j;
2503         png_uint_32 lmhi, lmlo;
2504         lmlo = lmins & PNG_LOMASK;
2505         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
2506
2507         for (j = 0; j < num_p_filters; j++)
2508         {
2509            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
2510            {
2511               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
2512                  PNG_WEIGHT_SHIFT;
2513               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
2514                  PNG_WEIGHT_SHIFT;
2515            }
2516         }
2517
2518         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
2519            PNG_COST_SHIFT;
2520         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
2521            PNG_COST_SHIFT;
2522
2523         if (lmhi > PNG_HIMASK)
2524            lmins = PNG_MAXSUM;
2525         else
2526            lmins = (lmhi << PNG_HISHIFT) + lmlo;
2527      }
2528#endif
2529
2530      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2531           pp = prev_row + 1; i < bpp; i++)
2532      {
2533         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2534
2535         sum += (v < 128) ? v : 256 - v;
2536      }
2537      for (lp = row_buf + 1; i < row_bytes; i++)
2538      {
2539         v = *dp++ =
2540          (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
2541
2542         sum += (v < 128) ? v : 256 - v;
2543
2544         if (sum > lmins)  /* We are already worse, don't continue. */
2545            break;
2546      }
2547
2548#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2549      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2550      {
2551         int j;
2552         png_uint_32 sumhi, sumlo;
2553         sumlo = sum & PNG_LOMASK;
2554         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
2555
2556         for (j = 0; j < num_p_filters; j++)
2557         {
2558            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
2559            {
2560               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
2561                  PNG_WEIGHT_SHIFT;
2562               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
2563                  PNG_WEIGHT_SHIFT;
2564            }
2565         }
2566
2567         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
2568            PNG_COST_SHIFT;
2569         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
2570            PNG_COST_SHIFT;
2571
2572         if (sumhi > PNG_HIMASK)
2573            sum = PNG_MAXSUM;
2574         else
2575            sum = (sumhi << PNG_HISHIFT) + sumlo;
2576      }
2577#endif
2578
2579      if (sum < mins)
2580      {
2581         mins = sum;
2582         best_row = png_ptr->avg_row;
2583      }
2584   }
2585
2586   /* Paeth filter */
2587   if (filter_to_do == PNG_FILTER_PAETH)
2588   {
2589      png_bytep rp, dp, pp, cp, lp;
2590      png_uint_32 i;
2591      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2592           pp = prev_row + 1; i < bpp; i++)
2593      {
2594         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2595      }
2596
2597      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2598      {
2599         int a, b, c, pa, pb, pc, p;
2600
2601         b = *pp++;
2602         c = *cp++;
2603         a = *lp++;
2604
2605         p = b - c;
2606         pc = a - c;
2607
2608#ifdef PNG_USE_ABS
2609         pa = abs(p);
2610         pb = abs(pc);
2611         pc = abs(p + pc);
2612#else
2613         pa = p < 0 ? -p : p;
2614         pb = pc < 0 ? -pc : pc;
2615         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2616#endif
2617
2618         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2619
2620         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2621      }
2622      best_row = png_ptr->paeth_row;
2623   }
2624
2625   else if (filter_to_do & PNG_FILTER_PAETH)
2626   {
2627      png_bytep rp, dp, pp, cp, lp;
2628      png_uint_32 sum = 0, lmins = mins;
2629      png_uint_32 i;
2630      int v;
2631
2632#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2633      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2634      {
2635         int j;
2636         png_uint_32 lmhi, lmlo;
2637         lmlo = lmins & PNG_LOMASK;
2638         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
2639
2640         for (j = 0; j < num_p_filters; j++)
2641         {
2642            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
2643            {
2644               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
2645                  PNG_WEIGHT_SHIFT;
2646               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
2647                  PNG_WEIGHT_SHIFT;
2648            }
2649         }
2650
2651         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2652            PNG_COST_SHIFT;
2653         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2654            PNG_COST_SHIFT;
2655
2656         if (lmhi > PNG_HIMASK)
2657            lmins = PNG_MAXSUM;
2658         else
2659            lmins = (lmhi << PNG_HISHIFT) + lmlo;
2660      }
2661#endif
2662
2663      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2664           pp = prev_row + 1; i < bpp; i++)
2665      {
2666         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2667
2668         sum += (v < 128) ? v : 256 - v;
2669      }
2670
2671      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2672      {
2673         int a, b, c, pa, pb, pc, p;
2674
2675         b = *pp++;
2676         c = *cp++;
2677         a = *lp++;
2678
2679#ifndef PNG_SLOW_PAETH
2680         p = b - c;
2681         pc = a - c;
2682#ifdef PNG_USE_ABS
2683         pa = abs(p);
2684         pb = abs(pc);
2685         pc = abs(p + pc);
2686#else
2687         pa = p < 0 ? -p : p;
2688         pb = pc < 0 ? -pc : pc;
2689         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2690#endif
2691         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2692#else /* PNG_SLOW_PAETH */
2693         p = a + b - c;
2694         pa = abs(p - a);
2695         pb = abs(p - b);
2696         pc = abs(p - c);
2697         if (pa <= pb && pa <= pc)
2698            p = a;
2699         else if (pb <= pc)
2700            p = b;
2701         else
2702            p = c;
2703#endif /* PNG_SLOW_PAETH */
2704
2705         v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2706
2707         sum += (v < 128) ? v : 256 - v;
2708
2709         if (sum > lmins)  /* We are already worse, don't continue. */
2710            break;
2711      }
2712
2713#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2714      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2715      {
2716         int j;
2717         png_uint_32 sumhi, sumlo;
2718         sumlo = sum & PNG_LOMASK;
2719         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
2720
2721         for (j = 0; j < num_p_filters; j++)
2722         {
2723            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
2724            {
2725               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
2726                  PNG_WEIGHT_SHIFT;
2727               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
2728                  PNG_WEIGHT_SHIFT;
2729            }
2730         }
2731
2732         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2733            PNG_COST_SHIFT;
2734         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2735            PNG_COST_SHIFT;
2736
2737         if (sumhi > PNG_HIMASK)
2738            sum = PNG_MAXSUM;
2739         else
2740            sum = (sumhi << PNG_HISHIFT) + sumlo;
2741      }
2742#endif
2743
2744      if (sum < mins)
2745      {
2746         best_row = png_ptr->paeth_row;
2747      }
2748   }
2749#endif /* PNG_WRITE_FILTER_SUPPORTED */
2750   /* Do the actual writing of the filtered row data from the chosen filter. */
2751
2752   png_write_filtered_row(png_ptr, best_row);
2753
2754#ifdef PNG_WRITE_FILTER_SUPPORTED
2755#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
2756   /* Save the type of filter we picked this time for future calculations */
2757   if (png_ptr->num_prev_filters > 0)
2758   {
2759      int j;
2760      for (j = 1; j < num_p_filters; j++)
2761      {
2762         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
2763      }
2764      png_ptr->prev_filters[j] = best_row[0];
2765   }
2766#endif
2767#endif /* PNG_WRITE_FILTER_SUPPORTED */
2768}
2769
2770
2771/* Do the actual writing of a previously filtered row. */
2772void /* PRIVATE */
2773png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
2774{
2775   png_debug(1, "in png_write_filtered_row");
2776
2777   png_debug1(2, "filter = %d", filtered_row[0]);
2778   /* Set up the zlib input buffer */
2779
2780   png_ptr->zstream.next_in = filtered_row;
2781   png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
2782   /* Repeat until we have compressed all the data */
2783   do
2784   {
2785      int ret; /* Return of zlib */
2786
2787      /* Compress the data */
2788      ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
2789      /* Check for compression errors */
2790      if (ret != Z_OK)
2791      {
2792         if (png_ptr->zstream.msg != NULL)
2793            png_error(png_ptr, png_ptr->zstream.msg);
2794         else
2795            png_error(png_ptr, "zlib error");
2796      }
2797
2798      /* See if it is time to write another IDAT */
2799      if (!(png_ptr->zstream.avail_out))
2800      {
2801         /* Write the IDAT and reset the zlib output buffer */
2802         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
2803         png_ptr->zstream.next_out = png_ptr->zbuf;
2804         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
2805      }
2806   /* Repeat until all data has been compressed */
2807   } while (png_ptr->zstream.avail_in);
2808
2809   /* Swap the current and previous rows */
2810   if (png_ptr->prev_row != NULL)
2811   {
2812      png_bytep tptr;
2813
2814      tptr = png_ptr->prev_row;
2815      png_ptr->prev_row = png_ptr->row_buf;
2816      png_ptr->row_buf = tptr;
2817   }
2818
2819   /* Finish row - updates counters and flushes zlib if last row */
2820   png_write_finish_row(png_ptr);
2821
2822#ifdef PNG_WRITE_FLUSH_SUPPORTED
2823   png_ptr->flush_rows++;
2824
2825   if (png_ptr->flush_dist > 0 &&
2826       png_ptr->flush_rows >= png_ptr->flush_dist)
2827   {
2828      png_write_flush(png_ptr);
2829   }
2830#endif
2831}
2832#endif /* PNG_WRITE_SUPPORTED */
2833