source: trunk/third/libpng/pngwutil.c @ 18166

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