• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
23 void PNGAPI
png_save_uint_32(png_bytep buf,png_uint_32 i)24 png_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  */
36 void PNGAPI
png_save_int_32(png_bytep buf,png_int_32 i)37 png_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  */
49 void PNGAPI
png_save_uint_16(png_bytep buf,unsigned int i)50 png_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  */
62 void /* PRIVATE */
png_write_sig(png_structp png_ptr)63 png_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  */
83 void PNGAPI
png_write_chunk(png_structp png_ptr,png_bytep chunk_name,png_bytep data,png_size_t length)84 png_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  */
98 void PNGAPI
png_write_chunk_start(png_structp png_ptr,png_bytep chunk_name,png_uint_32 length)99 png_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  */
127 void PNGAPI
png_write_chunk_data(png_structp png_ptr,png_bytep data,png_size_t length)128 png_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(). */
144 void PNGAPI
png_write_chunk_end(png_structp png_ptr)145 png_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 
164 typedef 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 */
174 static int /* PRIVATE */
png_text_compress(png_structp png_ptr,png_charp text,png_size_t text_len,int compression,compression_state * comp)175 png_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 */
352 static void /* PRIVATE */
png_write_compressed_data_out(png_structp png_ptr,compression_state * comp)353 png_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  */
391 void /* PRIVATE */
png_write_IHDR(png_structp png_ptr,png_uint_32 width,png_uint_32 height,int bit_depth,int color_type,int compression_type,int filter_type,int interlace_type)392 png_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  */
572 void /* PRIVATE */
png_write_PLTE(png_structp png_ptr,png_colorp palette,png_uint_32 num_pal)573 png_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 */
639 void /* PRIVATE */
png_write_IDAT(png_structp png_ptr,png_bytep data,png_size_t length)640 png_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 */
694 void /* PRIVATE */
png_write_IEND(png_structp png_ptr)695 png_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
711 void /* PRIVATE */
png_write_gAMA(png_structp png_ptr,double file_gamma)712 png_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
729 void /* PRIVATE */
png_write_gAMA_fixed(png_structp png_ptr,png_fixed_point file_gamma)730 png_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 */
748 void /* PRIVATE */
png_write_sRGB(png_structp png_ptr,int srgb_intent)749 png_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 */
768 void /* PRIVATE */
png_write_iCCP(png_structp png_ptr,png_charp name,int compression_type,png_charp profile,int profile_len)769 png_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 */
849 void /* PRIVATE */
png_write_sPLT(png_structp png_ptr,png_sPLT_tp spalette)850 png_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 */
930 void /* PRIVATE */
png_write_sBIT(png_structp png_ptr,png_color_8p sbit,int color_type)931 png_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
988 void /* PRIVATE */
png_write_cHRM(png_structp png_ptr,double white_x,double white_y,double red_x,double red_y,double green_x,double green_y,double blue_x,double blue_y)989 png_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
1036 void /* PRIVATE */
png_write_cHRM_fixed(png_structp png_ptr,png_fixed_point white_x,png_fixed_point white_y,png_fixed_point red_x,png_fixed_point red_y,png_fixed_point green_x,png_fixed_point green_y,png_fixed_point blue_x,png_fixed_point blue_y)1037 png_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 */
1075 void /* PRIVATE */
png_write_tRNS(png_structp png_ptr,png_bytep trans,png_color_16p tran,int num_trans,int color_type)1076 png_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 */
1132 void /* PRIVATE */
png_write_bKGD(png_structp png_ptr,png_color_16p back,int color_type)1133 png_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 */
1186 void /* PRIVATE */
png_write_hIST(png_structp png_ptr,png_uint_16p hist,int num_hist)1187 png_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  */
1228 png_size_t /* PRIVATE */
png_check_keyword(png_structp png_ptr,png_charp key,png_charpp new_key)1229 png_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 */
1350 void /* PRIVATE */
png_write_tEXt(png_structp png_ptr,png_charp key,png_charp text,png_size_t text_len)1351 png_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 */
1391 void /* PRIVATE */
png_write_zTXt(png_structp png_ptr,png_charp key,png_charp text,png_size_t text_len,int compression)1392 png_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 */
1451 void /* PRIVATE */
png_write_iTXt(png_structp png_ptr,int compression,png_charp key,png_charp lang,png_charp lang_key,png_charp text)1452 png_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 */
1540 void /* PRIVATE */
png_write_oFFs(png_structp png_ptr,png_int_32 x_offset,png_int_32 y_offset,int unit_type)1541 png_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) */
1563 void /* PRIVATE */
png_write_pCAL(png_structp png_ptr,png_charp purpose,png_int_32 X0,png_int_32 X1,int type,int nparams,png_charp units,png_charpp params)1564 png_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)
1627 void /* PRIVATE */
png_write_sCAL(png_structp png_ptr,int unit,double width,double height)1628 png_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
1667 void /* PRIVATE */
png_write_sCAL_s(png_structp png_ptr,int unit,png_charp width,png_charp height)1668 png_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 */
1701 void /* PRIVATE */
png_write_pHYs(png_structp png_ptr,png_uint_32 x_pixels_per_unit,png_uint_32 y_pixels_per_unit,int unit_type)1702 png_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  */
1728 void /* PRIVATE */
png_write_tIME(png_structp png_ptr,png_timep mod_time)1729 png_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 */
1758 void /* PRIVATE */
png_write_start_row(png_structp png_ptr)1759 png_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. */
1856 void /* PRIVATE */
png_write_finish_row(png_structp png_ptr)1857 png_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  */
1974 void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info,png_bytep row,int pass)1975 png_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))
2144 void /* PRIVATE */
png_write_find_filter(png_structp png_ptr,png_row_infop row_info)2145 png_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. */
2772 void /* PRIVATE */
png_write_filtered_row(png_structp png_ptr,png_bytep filtered_row)2773 png_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