/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/png/pngwutil.c
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/png/pngwutil.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22