2 ===================================================================
6 If you modify libpng you may insert additional notices immediately following
9 +This modified version of libpng code adds animated PNG support and is
10 +released under the libpng license described below. The modifications are
11 +Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
12 +and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
13 +surrounding them in the modified libpng source files.
15 This code is released under the libpng license.
17 libpng versions 1.0.7, July 1, 2000 through 1.6.30, June 28, 2017 are
19 ===================================================================
24 else if (chunk_name == png_IDAT)
26 +#ifdef PNG_READ_APNG_SUPPORTED
27 + png_have_info(png_ptr, info_ptr);
29 png_ptr->idat_size = length;
33 png_handle_iTXt(png_ptr, info_ptr, length);
36 +#ifdef PNG_READ_APNG_SUPPORTED
37 + else if (chunk_name == png_acTL)
38 + png_handle_acTL(png_ptr, info_ptr, length);
40 + else if (chunk_name == png_fcTL)
41 + png_handle_fcTL(png_ptr, info_ptr, length);
43 + else if (chunk_name == png_fdAT)
44 + png_handle_fdAT(png_ptr, info_ptr, length);
48 png_handle_unknown(png_ptr, info_ptr, length,
49 PNG_HANDLE_CHUNK_AS_DEFAULT);
52 #endif /* SEQUENTIAL_READ */
54 +#ifdef PNG_READ_APNG_SUPPORTED
56 +png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
58 + png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
60 + png_debug(0, "Reading frame head");
62 + if ((png_ptr->mode & PNG_HAVE_acTL) == 0)
63 + png_error(png_ptr, "attempt to png_read_frame_head() but "
66 + /* do nothing for the main IDAT */
67 + if (png_ptr->num_frames_read == 0)
70 + png_read_reset(png_ptr);
71 + png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
72 + png_ptr->mode &= ~PNG_HAVE_fcTL;
74 + have_chunk_after_DAT = 0;
77 + png_uint_32 length = png_read_chunk_header(png_ptr);
79 + if (png_ptr->chunk_name == png_IDAT)
81 + /* discard trailing IDATs for the first frame */
82 + if (have_chunk_after_DAT != 0 || png_ptr->num_frames_read > 1)
83 + png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
84 + png_crc_finish(png_ptr, length);
87 + else if (png_ptr->chunk_name == png_fcTL)
89 + png_handle_fcTL(png_ptr, info_ptr, length);
90 + have_chunk_after_DAT = 1;
93 + else if (png_ptr->chunk_name == png_fdAT)
95 + png_ensure_sequence_number(png_ptr, length);
97 + /* discard trailing fdATs for frames other than the first */
98 + if (have_chunk_after_DAT == 0 && png_ptr->num_frames_read > 1)
99 + png_crc_finish(png_ptr, length - 4);
100 + else if (png_ptr->mode & PNG_HAVE_fcTL)
102 + png_ptr->idat_size = length - 4;
103 + png_ptr->mode |= PNG_HAVE_IDAT;
108 + png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
112 + png_warning(png_ptr, "Skipped (ignored) a chunk "
113 + "between APNG chunks");
114 + png_crc_finish(png_ptr, length);
118 +#endif /* READ_APNG */
120 /* Optional call to update the users info_ptr structure */
122 png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
124 ===================================================================
127 @@ -1216,4 +1216,166 @@
131 +#ifdef PNG_APNG_SUPPORTED
133 +png_get_acTL(png_structp png_ptr, png_infop info_ptr,
134 + png_uint_32 *num_frames, png_uint_32 *num_plays)
136 + png_debug1(1, "in %s retrieval function", "acTL");
138 + if (png_ptr != NULL && info_ptr != NULL &&
139 + (info_ptr->valid & PNG_INFO_acTL) != 0 &&
140 + num_frames != NULL && num_plays != NULL)
142 + *num_frames = info_ptr->num_frames;
143 + *num_plays = info_ptr->num_plays;
151 +png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
153 + png_debug(1, "in png_get_num_frames()");
155 + if (png_ptr != NULL && info_ptr != NULL)
156 + return (info_ptr->num_frames);
161 +png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
163 + png_debug(1, "in png_get_num_plays()");
165 + if (png_ptr != NULL && info_ptr != NULL)
166 + return (info_ptr->num_plays);
171 +png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
172 + png_uint_32 *width, png_uint_32 *height,
173 + png_uint_32 *x_offset, png_uint_32 *y_offset,
174 + png_uint_16 *delay_num, png_uint_16 *delay_den,
175 + png_byte *dispose_op, png_byte *blend_op)
177 + png_debug1(1, "in %s retrieval function", "fcTL");
179 + if (png_ptr != NULL && info_ptr != NULL &&
180 + (info_ptr->valid & PNG_INFO_fcTL) != 0 &&
181 + width != NULL && height != NULL &&
182 + x_offset != NULL && y_offset != NULL &&
183 + delay_num != NULL && delay_den != NULL &&
184 + dispose_op != NULL && blend_op != NULL)
186 + *width = info_ptr->next_frame_width;
187 + *height = info_ptr->next_frame_height;
188 + *x_offset = info_ptr->next_frame_x_offset;
189 + *y_offset = info_ptr->next_frame_y_offset;
190 + *delay_num = info_ptr->next_frame_delay_num;
191 + *delay_den = info_ptr->next_frame_delay_den;
192 + *dispose_op = info_ptr->next_frame_dispose_op;
193 + *blend_op = info_ptr->next_frame_blend_op;
201 +png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
203 + png_debug(1, "in png_get_next_frame_width()");
205 + if (png_ptr != NULL && info_ptr != NULL)
206 + return (info_ptr->next_frame_width);
211 +png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
213 + png_debug(1, "in png_get_next_frame_height()");
215 + if (png_ptr != NULL && info_ptr != NULL)
216 + return (info_ptr->next_frame_height);
221 +png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
223 + png_debug(1, "in png_get_next_frame_x_offset()");
225 + if (png_ptr != NULL && info_ptr != NULL)
226 + return (info_ptr->next_frame_x_offset);
231 +png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
233 + png_debug(1, "in png_get_next_frame_y_offset()");
235 + if (png_ptr != NULL && info_ptr != NULL)
236 + return (info_ptr->next_frame_y_offset);
241 +png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
243 + png_debug(1, "in png_get_next_frame_delay_num()");
245 + if (png_ptr != NULL && info_ptr != NULL)
246 + return (info_ptr->next_frame_delay_num);
251 +png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
253 + png_debug(1, "in png_get_next_frame_delay_den()");
255 + if (png_ptr != NULL && info_ptr != NULL)
256 + return (info_ptr->next_frame_delay_den);
261 +png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
263 + png_debug(1, "in png_get_next_frame_dispose_op()");
265 + if (png_ptr != NULL && info_ptr != NULL)
266 + return (info_ptr->next_frame_dispose_op);
271 +png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
273 + png_debug(1, "in png_get_next_frame_blend_op()");
275 + if (png_ptr != NULL && info_ptr != NULL)
276 + return (info_ptr->next_frame_blend_op);
281 +png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
283 + png_debug(1, "in png_first_frame_is_hidden()");
285 + if (png_ptr != NULL)
286 + return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
288 + PNG_UNUSED(info_ptr)
293 #endif /* READ || WRITE */
295 ===================================================================
298 @@ -776,17 +776,21 @@
301 return PNG_STRING_NEWLINE \
302 - "libpng version 1.6.30 - June 28, 2017" PNG_STRING_NEWLINE \
303 + "libpng version 1.6.30+apng - June 28, 2017" PNG_STRING_NEWLINE \
304 "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
306 "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
307 "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
308 - PNG_STRING_NEWLINE;
309 + PNG_STRING_NEWLINE \
310 + "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
311 + "Portions Copyright (c) 2008-2017 Max Stepin" PNG_STRING_NEWLINE ;
313 - return "libpng version 1.6.30 - June 28, 2017\
314 + return "libpng version 1.6.30+apng - June 28, 2017\
315 Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
316 Copyright (c) 1996-1997 Andreas Dilger\
317 - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
318 + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
319 + Portions Copyright (c) 2006-2007 Andrew Smith\
320 + Portions Copyright (c) 2008-2017 Max Stepin";
325 ===================================================================
329 * If you modify libpng you may insert additional notices immediately following
332 + * This modified version of libpng code adds animated PNG support and is
333 + * released under the libpng license described below. The modifications are
334 + * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
335 + * and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
336 + * surrounding them in the modified libpng source files.
338 * This code is released under the libpng license.
340 * libpng versions 1.0.7, July 1, 2000 through 1.6.30, June 28, 2017 are
344 /* Version information for png.h - this should match the version in png.c */
345 -#define PNG_LIBPNG_VER_STRING "1.6.30"
346 -#define PNG_HEADER_VERSION_STRING " libpng version 1.6.30 - June 28, 2017\n"
347 +#define PNG_LIBPNG_VER_STRING "1.6.30+apng"
348 +#define PNG_HEADER_VERSION_STRING \
349 + " libpng version 1.6.30+apng - June 28, 2017\n"
351 #define PNG_LIBPNG_VER_SONUM 16
352 #define PNG_LIBPNG_VER_DLLNUM 16
354 # include "pnglibconf.h"
357 +#define PNG_APNG_SUPPORTED
358 +#define PNG_READ_APNG_SUPPORTED
359 +#define PNG_WRITE_APNG_SUPPORTED
361 #ifndef PNG_VERSION_INFO_ONLY
362 /* Machine specific configuration. */
363 # include "pngconf.h"
365 * See pngconf.h for base types that vary by machine/system
368 +#ifdef PNG_APNG_SUPPORTED
369 +/* dispose_op flags from inside fcTL */
370 +#define PNG_DISPOSE_OP_NONE 0x00
371 +#define PNG_DISPOSE_OP_BACKGROUND 0x01
372 +#define PNG_DISPOSE_OP_PREVIOUS 0x02
374 +/* blend_op flags from inside fcTL */
375 +#define PNG_BLEND_OP_SOURCE 0x00
376 +#define PNG_BLEND_OP_OVER 0x01
379 /* This triggers a compiler error in png.c, if png.c and png.h
380 * do not agree upon the version number.
383 #define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */
384 #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
385 #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
386 +#ifdef PNG_APNG_SUPPORTED
387 +#define PNG_INFO_acTL 0x10000U
388 +#define PNG_INFO_fcTL 0x20000U
391 /* This is used for the transformation routines, as some of them
392 * change these values for the row. It also should enable using
394 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
395 typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
396 typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
397 +#ifdef PNG_APNG_SUPPORTED
398 +typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
402 /* The following callback receives png_uint_32 row_number, int pass for the
403 * png_bytep data of the row. When transforming an interlaced image the
404 @@ -3245,6 +3275,75 @@
405 * END OF HARDWARE AND SOFTWARE OPTIONS
406 ******************************************************************************/
408 +#ifdef PNG_APNG_SUPPORTED
409 +PNG_EXPORT(246, png_uint_32, png_get_acTL, (png_structp png_ptr,
410 + png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
412 +PNG_EXPORT(247, png_uint_32, png_set_acTL, (png_structp png_ptr,
413 + png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
415 +PNG_EXPORT(248, png_uint_32, png_get_num_frames, (png_structp png_ptr,
416 + png_infop info_ptr));
418 +PNG_EXPORT(249, png_uint_32, png_get_num_plays, (png_structp png_ptr,
419 + png_infop info_ptr));
421 +PNG_EXPORT(250, png_uint_32, png_get_next_frame_fcTL,
422 + (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
423 + png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
424 + png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
425 + png_byte *blend_op));
427 +PNG_EXPORT(251, png_uint_32, png_set_next_frame_fcTL,
428 + (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
429 + png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
430 + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
431 + png_byte blend_op));
433 +PNG_EXPORT(252, png_uint_32, png_get_next_frame_width,
434 + (png_structp png_ptr, png_infop info_ptr));
435 +PNG_EXPORT(253, png_uint_32, png_get_next_frame_height,
436 + (png_structp png_ptr, png_infop info_ptr));
437 +PNG_EXPORT(254, png_uint_32, png_get_next_frame_x_offset,
438 + (png_structp png_ptr, png_infop info_ptr));
439 +PNG_EXPORT(255, png_uint_32, png_get_next_frame_y_offset,
440 + (png_structp png_ptr, png_infop info_ptr));
441 +PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_num,
442 + (png_structp png_ptr, png_infop info_ptr));
443 +PNG_EXPORT(257, png_uint_16, png_get_next_frame_delay_den,
444 + (png_structp png_ptr, png_infop info_ptr));
445 +PNG_EXPORT(258, png_byte, png_get_next_frame_dispose_op,
446 + (png_structp png_ptr, png_infop info_ptr));
447 +PNG_EXPORT(259, png_byte, png_get_next_frame_blend_op,
448 + (png_structp png_ptr, png_infop info_ptr));
449 +PNG_EXPORT(260, png_byte, png_get_first_frame_is_hidden,
450 + (png_structp png_ptr, png_infop info_ptr));
451 +PNG_EXPORT(261, png_uint_32, png_set_first_frame_is_hidden,
452 + (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
454 +#ifdef PNG_READ_APNG_SUPPORTED
455 +PNG_EXPORT(262, void, png_read_frame_head, (png_structp png_ptr,
456 + png_infop info_ptr));
457 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
458 +PNG_EXPORT(263, void, png_set_progressive_frame_fn, (png_structp png_ptr,
459 + png_progressive_frame_ptr frame_info_fn,
460 + png_progressive_frame_ptr frame_end_fn));
461 +#endif /* PROGRESSIVE_READ */
462 +#endif /* READ_APNG */
464 +#ifdef PNG_WRITE_APNG_SUPPORTED
465 +PNG_EXPORT(264, void, png_write_frame_head, (png_structp png_ptr,
466 + png_infop info_ptr, png_bytepp row_pointers,
467 + png_uint_32 width, png_uint_32 height,
468 + png_uint_32 x_offset, png_uint_32 y_offset,
469 + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
470 + png_byte blend_op));
472 +PNG_EXPORT(265, void, png_write_frame_tail, (png_structp png_ptr,
473 + png_infop info_ptr));
474 +#endif /* WRITE_APNG */
477 /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
478 * defs, and in scripts/symbols.def.
480 @@ -3253,7 +3352,11 @@
481 * one to use is one more than this.)
483 #ifdef PNG_EXPORT_LAST_ORDINAL
484 +#ifdef PNG_APNG_SUPPORTED
485 + PNG_EXPORT_LAST_ORDINAL(265);
487 PNG_EXPORT_LAST_ORDINAL(245);
493 ===================================================================
497 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
498 /* 0x4000U (unused) */
499 #define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
500 +#ifdef PNG_APNG_SUPPORTED
501 +#define PNG_HAVE_acTL 0x10000U
502 +#define PNG_HAVE_fcTL 0x20000U
505 /* Flags for the transformations the PNG library does on the image data */
506 #define PNG_BGR 0x0001U
508 #define png_tRNS PNG_U32(116, 82, 78, 83)
509 #define png_zTXt PNG_U32(122, 84, 88, 116)
511 +#ifdef PNG_APNG_SUPPORTED
512 +#define png_acTL PNG_U32( 97, 99, 84, 76)
513 +#define png_fcTL PNG_U32(102, 99, 84, 76)
514 +#define png_fdAT PNG_U32(102, 100, 65, 84)
516 +/* For png_struct.apng_flags: */
517 +#define PNG_FIRST_FRAME_HIDDEN 0x0001U
518 +#define PNG_APNG_APP 0x0002U
521 /* The following will work on (signed char*) strings, whereas the get_uint_32
522 * macro will fail on top-bit-set values because of the sign extension.
524 @@ -1598,6 +1612,49 @@
526 #endif /* PROGRESSIVE_READ */
528 +#ifdef PNG_APNG_SUPPORTED
529 +PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
530 + png_uint_32 width, png_uint_32 height,
531 + png_uint_32 x_offset, png_uint_32 y_offset,
532 + png_uint_16 delay_num, png_uint_16 delay_den,
533 + png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
535 +#ifdef PNG_READ_APNG_SUPPORTED
536 +PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr,
537 + png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
538 +PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr,
539 + png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
540 +PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr,
541 + png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
542 +PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr,
543 + png_infop info_ptr),PNG_EMPTY);
544 +PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
545 + png_uint_32 length),PNG_EMPTY);
546 +PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
547 +PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
548 + png_infop info_ptr),PNG_EMPTY);
549 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
550 +PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),
552 +#endif /* PROGRESSIVE_READ */
553 +#endif /* READ_APNG */
555 +#ifdef PNG_WRITE_APNG_SUPPORTED
556 +PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
557 + png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
558 +PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
559 + png_uint_32 width, png_uint_32 height,
560 + png_uint_32 x_offset, png_uint_32 y_offset,
561 + png_uint_16 delay_num, png_uint_16 delay_den,
562 + png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
563 +PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
564 + png_const_bytep data, png_size_t length),PNG_EMPTY);
565 +PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
566 +PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
567 + png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
568 +#endif /* WRITE_APNG */
571 /* Added at libpng version 1.6.0 */
572 #ifdef PNG_GAMMA_SUPPORTED
573 PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,
575 ===================================================================
579 png_bytepp row_pointers; /* the image bits */
582 +#ifdef PNG_APNG_SUPPORTED
583 + png_uint_32 num_frames; /* including default image */
584 + png_uint_32 num_plays;
585 + png_uint_32 next_frame_width;
586 + png_uint_32 next_frame_height;
587 + png_uint_32 next_frame_x_offset;
588 + png_uint_32 next_frame_y_offset;
589 + png_uint_16 next_frame_delay_num;
590 + png_uint_16 next_frame_delay_den;
591 + png_byte next_frame_dispose_op;
592 + png_byte next_frame_blend_op;
596 #endif /* PNGINFO_H */
598 ===================================================================
602 png_byte filter_type;
605 +#ifdef PNG_APNG_SUPPORTED
606 + png_uint_32 apng_flags;
607 + png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
608 + png_uint_32 first_frame_width;
609 + png_uint_32 first_frame_height;
611 +#ifdef PNG_READ_APNG_SUPPORTED
612 + png_uint_32 num_frames_read; /* incremented after all image data of */
613 + /* a frame is read */
614 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
615 + png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
616 + png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
620 +#ifdef PNG_WRITE_APNG_SUPPORTED
621 + png_uint_32 num_frames_to_write;
622 + png_uint_32 num_frames_written;
626 /* New members added in libpng-1.2.0 */
628 /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
630 ===================================================================
634 * the application continues writing the PNG. So check the 'invalid'
637 +#ifdef PNG_WRITE_APNG_SUPPORTED
638 + if ((info_ptr->valid & PNG_INFO_acTL) != 0)
639 + png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
641 #ifdef PNG_GAMMA_SUPPORTED
642 # ifdef PNG_WRITE_gAMA_SUPPORTED
643 if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
645 if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
646 png_error(png_ptr, "No IDATs written into file");
648 +#ifdef PNG_WRITE_APNG_SUPPORTED
649 + if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
650 + png_error(png_ptr, "Not enough frames written");
653 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
654 if (png_ptr->num_palette_max > png_ptr->num_palette)
655 png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
656 @@ -2382,4 +2391,42 @@
658 #endif /* SIMPLIFIED_WRITE_STDIO */
659 #endif /* SIMPLIFIED_WRITE */
661 +#ifdef PNG_WRITE_APNG_SUPPORTED
663 +png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
664 + png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
665 + png_uint_32 x_offset, png_uint_32 y_offset,
666 + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
669 + png_debug(1, "in png_write_frame_head");
671 + /* there is a chance this has been set after png_write_info was called,
672 + * so it would be set but not written. is there a way to be sure? */
673 + if ((info_ptr->valid & PNG_INFO_acTL) == 0)
674 + png_error(png_ptr, "png_write_frame_head(): acTL not set");
676 + png_write_reset(png_ptr);
678 + png_write_reinit(png_ptr, info_ptr, width, height);
680 + if ((png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) == 0 ||
681 + png_ptr->num_frames_written != 0)
682 + png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
683 + delay_num, delay_den, dispose_op, blend_op);
685 + PNG_UNUSED(row_pointers)
689 +png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
691 + png_debug(1, "in png_write_frame_tail");
693 + png_ptr->num_frames_written++;
695 + PNG_UNUSED(info_ptr)
697 +#endif /* WRITE_APNG */
700 ===================================================================
705 chunk_name = png_ptr->chunk_name;
707 +#ifdef PNG_READ_APNG_SUPPORTED
708 + if (png_ptr->num_frames_read > 0 &&
709 + png_ptr->num_frames_read < info_ptr->num_frames)
711 + if (chunk_name == png_IDAT)
713 + /* Discard trailing IDATs for the first frame */
714 + if ((png_ptr->mode & PNG_HAVE_fcTL) != 0 ||
715 + png_ptr->num_frames_read > 1)
716 + png_error(png_ptr, "out of place IDAT");
718 + PNG_PUSH_SAVE_BUFFER_IF_FULL
719 + png_crc_finish(png_ptr, png_ptr->push_length);
720 + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
723 + else if (chunk_name == png_fdAT)
725 + PNG_PUSH_SAVE_BUFFER_IF_LT(4)
726 + png_ensure_sequence_number(png_ptr, 4);
728 + if ((png_ptr->mode & PNG_HAVE_fcTL) == 0)
730 + /* Discard trailing fdATs for frames other than the first */
731 + if (png_ptr->num_frames_read < 2)
732 + png_error(png_ptr, "out of place fdAT");
734 + PNG_PUSH_SAVE_BUFFER_IF_FULL
735 + png_crc_finish(png_ptr, png_ptr->push_length);
736 + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
741 + /* frame data follows */
742 + png_ptr->idat_size = png_ptr->push_length - 4;
743 + png_ptr->mode |= PNG_HAVE_IDAT;
744 + png_ptr->process_mode = PNG_READ_IDAT_MODE;
748 + else if (chunk_name == png_fcTL)
750 + PNG_PUSH_SAVE_BUFFER_IF_FULL
751 + png_read_reset(png_ptr);
752 + png_ptr->mode &= ~PNG_HAVE_fcTL;
754 + png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
756 + if ((png_ptr->mode & PNG_HAVE_fcTL) == 0)
757 + png_error(png_ptr, "missing required fcTL chunk");
759 + png_read_reinit(png_ptr, info_ptr);
760 + png_progressive_read_reset(png_ptr);
762 + if (png_ptr->frame_info_fn != NULL)
763 + (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
765 + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
768 + else if (chunk_name == png_IEND)
770 + PNG_PUSH_SAVE_BUFFER_IF_FULL
771 + png_warning(png_ptr, "Number of actual frames fewer than expected");
772 + png_crc_finish(png_ptr, png_ptr->push_length);
773 + png_ptr->process_mode = PNG_READ_DONE_MODE;
774 + png_push_have_end(png_ptr, info_ptr);
779 + PNG_PUSH_SAVE_BUFFER_IF_FULL
780 + png_warning(png_ptr, "Skipped (ignored) a chunk "
781 + "between APNG chunks");
782 + png_crc_finish(png_ptr, png_ptr->push_length);
783 + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
788 +#endif /* READ_APNG */
790 if (chunk_name == png_IDAT)
792 if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
795 else if (chunk_name == png_IDAT)
797 +#ifdef PNG_READ_APNG_SUPPORTED
798 + png_have_info(png_ptr, info_ptr);
800 png_ptr->idat_size = png_ptr->push_length;
801 png_ptr->process_mode = PNG_READ_IDAT_MODE;
802 png_push_have_info(png_ptr, info_ptr);
807 +#ifdef PNG_READ_APNG_SUPPORTED
808 + else if (chunk_name == png_acTL)
810 + PNG_PUSH_SAVE_BUFFER_IF_FULL
811 + png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
814 + else if (chunk_name == png_fcTL)
816 + PNG_PUSH_SAVE_BUFFER_IF_FULL
817 + png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
820 +#endif /* READ_APNG */
823 PNG_PUSH_SAVE_BUFFER_IF_FULL
825 png_byte chunk_tag[4];
827 /* TODO: this code can be commoned up with the same code in push_read */
828 +#ifdef PNG_READ_APNG_SUPPORTED
829 + PNG_PUSH_SAVE_BUFFER_IF_LT(12)
831 PNG_PUSH_SAVE_BUFFER_IF_LT(8)
833 png_push_fill_buffer(png_ptr, chunk_length, 4);
834 png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
835 png_reset_crc(png_ptr);
836 @@ -546,17 +650,60 @@
837 png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
838 png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
840 +#ifdef PNG_READ_APNG_SUPPORTED
841 + if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
843 + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) != 0)
845 + png_ptr->process_mode = PNG_READ_CHUNK_MODE;
846 + if (png_ptr->frame_end_fn != NULL)
847 + (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
848 + png_ptr->num_frames_read++;
853 + if (png_ptr->chunk_name == png_IEND)
854 + png_error(png_ptr, "Not enough image data");
855 + PNG_PUSH_SAVE_BUFFER_IF_FULL
856 + png_warning(png_ptr, "Skipping (ignoring) a chunk between "
858 + png_crc_finish(png_ptr, png_ptr->push_length);
859 + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
865 +#ifdef PNG_READ_APNG_SUPPORTED
866 + if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
868 if (png_ptr->chunk_name != png_IDAT)
871 png_ptr->process_mode = PNG_READ_CHUNK_MODE;
873 if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
874 png_error(png_ptr, "Not enough compressed data");
876 +#ifdef PNG_READ_APNG_SUPPORTED
877 + if (png_ptr->frame_end_fn != NULL)
878 + (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
879 + png_ptr->num_frames_read++;
885 png_ptr->idat_size = png_ptr->push_length;
887 +#ifdef PNG_READ_APNG_SUPPORTED
888 + if (png_ptr->num_frames_read > 0)
890 + png_ensure_sequence_number(png_ptr, 4);
891 + png_ptr->idat_size -= 4;
896 if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
898 if (!(buffer_length > 0) || buffer == NULL)
899 png_error(png_ptr, "No IDAT data (internal error)");
901 +#ifdef PNG_READ_APNG_SUPPORTED
902 + /* If the app is not APNG-aware, decode only the first frame */
903 + if ((png_ptr->apng_flags & PNG_APNG_APP) == 0 &&
904 + png_ptr->num_frames_read > 0)
906 + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
911 /* This routine must process all the data it has been given
912 * before returning, calling the row callback as required to
913 * handle the uncompressed results.
914 @@ -1084,6 +1241,18 @@
915 png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
918 +#ifdef PNG_READ_APNG_SUPPORTED
920 +png_set_progressive_frame_fn(png_structp png_ptr,
921 + png_progressive_frame_ptr frame_info_fn,
922 + png_progressive_frame_ptr frame_end_fn)
924 + png_ptr->frame_info_fn = frame_info_fn;
925 + png_ptr->frame_end_fn = frame_end_fn;
926 + png_ptr->apng_flags |= PNG_APNG_APP;
931 png_get_progressive_ptr(png_const_structrp png_ptr)
934 ===================================================================
938 info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
940 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
942 +#ifdef PNG_APNG_SUPPORTED
943 + /* for non-animated png. this may be overwritten from an acTL chunk later */
944 + info_ptr->num_frames = 1;
948 #ifdef PNG_oFFs_SUPPORTED
949 @@ -1111,6 +1116,146 @@
953 +#ifdef PNG_APNG_SUPPORTED
955 +png_set_acTL(png_structp png_ptr, png_infop info_ptr,
956 + png_uint_32 num_frames, png_uint_32 num_plays)
958 + png_debug1(1, "in %s storage function", "acTL");
960 + if (png_ptr == NULL || info_ptr == NULL)
962 + png_warning(png_ptr,
963 + "Call to png_set_acTL() with NULL png_ptr "
964 + "or info_ptr ignored");
967 + if (num_frames == 0)
969 + png_warning(png_ptr,
970 + "Ignoring attempt to set acTL with num_frames zero");
973 + if (num_frames > PNG_UINT_31_MAX)
975 + png_warning(png_ptr,
976 + "Ignoring attempt to set acTL with num_frames > 2^31-1");
979 + if (num_plays > PNG_UINT_31_MAX)
981 + png_warning(png_ptr,
982 + "Ignoring attempt to set acTL with num_plays > 2^31-1");
986 + info_ptr->num_frames = num_frames;
987 + info_ptr->num_plays = num_plays;
989 + info_ptr->valid |= PNG_INFO_acTL;
994 +/* delay_num and delay_den can hold any 16-bit values including zero */
996 +png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
997 + png_uint_32 width, png_uint_32 height,
998 + png_uint_32 x_offset, png_uint_32 y_offset,
999 + png_uint_16 delay_num, png_uint_16 delay_den,
1000 + png_byte dispose_op, png_byte blend_op)
1002 + png_debug1(1, "in %s storage function", "fcTL");
1004 + if (png_ptr == NULL || info_ptr == NULL)
1006 + png_warning(png_ptr,
1007 + "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
1012 + png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1013 + delay_num, delay_den, dispose_op, blend_op);
1015 + if (blend_op == PNG_BLEND_OP_OVER)
1017 + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0 &&
1018 + png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == 0)
1020 + png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
1021 + "and wasteful for opaque images, ignored");
1022 + blend_op = PNG_BLEND_OP_SOURCE;
1026 + info_ptr->next_frame_width = width;
1027 + info_ptr->next_frame_height = height;
1028 + info_ptr->next_frame_x_offset = x_offset;
1029 + info_ptr->next_frame_y_offset = y_offset;
1030 + info_ptr->next_frame_delay_num = delay_num;
1031 + info_ptr->next_frame_delay_den = delay_den;
1032 + info_ptr->next_frame_dispose_op = dispose_op;
1033 + info_ptr->next_frame_blend_op = blend_op;
1035 + info_ptr->valid |= PNG_INFO_fcTL;
1041 +png_ensure_fcTL_is_valid(png_structp png_ptr,
1042 + png_uint_32 width, png_uint_32 height,
1043 + png_uint_32 x_offset, png_uint_32 y_offset,
1044 + png_uint_16 delay_num, png_uint_16 delay_den,
1045 + png_byte dispose_op, png_byte blend_op)
1047 + if (width == 0 || width > PNG_UINT_31_MAX)
1048 + png_error(png_ptr, "invalid width in fcTL (0 or > 2^31-1)");
1049 + if (height == 0 || height > PNG_UINT_31_MAX)
1050 + png_error(png_ptr, "invalid height in fcTL (0 or > 2^31-1)");
1051 + if (x_offset > PNG_UINT_31_MAX)
1052 + png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
1053 + if (y_offset > PNG_UINT_31_MAX)
1054 + png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
1055 + if (width + x_offset > png_ptr->first_frame_width ||
1056 + height + y_offset > png_ptr->first_frame_height)
1057 + png_error(png_ptr, "dimensions of a frame are greater than "
1058 + "the ones in IHDR");
1060 + if (dispose_op != PNG_DISPOSE_OP_NONE &&
1061 + dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
1062 + dispose_op != PNG_DISPOSE_OP_PREVIOUS)
1063 + png_error(png_ptr, "invalid dispose_op in fcTL");
1065 + if (blend_op != PNG_BLEND_OP_SOURCE &&
1066 + blend_op != PNG_BLEND_OP_OVER)
1067 + png_error(png_ptr, "invalid blend_op in fcTL");
1069 + PNG_UNUSED(delay_num)
1070 + PNG_UNUSED(delay_den)
1074 +png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
1075 + png_byte is_hidden)
1077 + png_debug(1, "in png_first_frame_is_hidden()");
1079 + if (png_ptr == NULL)
1082 + if (is_hidden != 0)
1083 + png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
1085 + png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
1087 + PNG_UNUSED(info_ptr)
1093 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1095 check_location(png_const_structrp png_ptr, int location)
1097 ===================================================================
1100 @@ -861,6 +861,11 @@
1101 filter_type = buf[11];
1102 interlace_type = buf[12];
1104 +#ifdef PNG_READ_APNG_SUPPORTED
1105 + png_ptr->first_frame_width = width;
1106 + png_ptr->first_frame_height = height;
1109 /* Set internal variables */
1110 png_ptr->width = width;
1111 png_ptr->height = height;
1112 @@ -2764,6 +2769,180 @@
1116 +#ifdef PNG_READ_APNG_SUPPORTED
1118 +png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1121 + png_uint_32 num_frames;
1122 + png_uint_32 num_plays;
1123 + png_uint_32 didSet;
1125 + png_debug(1, "in png_handle_acTL");
1127 + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
1129 + png_error(png_ptr, "Missing IHDR before acTL");
1131 + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
1133 + png_warning(png_ptr, "Invalid acTL after IDAT skipped");
1134 + png_crc_finish(png_ptr, length);
1137 + else if ((png_ptr->mode & PNG_HAVE_acTL) != 0)
1139 + png_warning(png_ptr, "Duplicate acTL skipped");
1140 + png_crc_finish(png_ptr, length);
1143 + else if (length != 8)
1145 + png_warning(png_ptr, "acTL with invalid length skipped");
1146 + png_crc_finish(png_ptr, length);
1150 + png_crc_read(png_ptr, data, 8);
1151 + png_crc_finish(png_ptr, 0);
1153 + num_frames = png_get_uint_31(png_ptr, data);
1154 + num_plays = png_get_uint_31(png_ptr, data + 4);
1156 + /* the set function will do error checking on num_frames */
1157 + didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
1159 + png_ptr->mode |= PNG_HAVE_acTL;
1163 +png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1165 + png_byte data[22];
1166 + png_uint_32 width;
1167 + png_uint_32 height;
1168 + png_uint_32 x_offset;
1169 + png_uint_32 y_offset;
1170 + png_uint_16 delay_num;
1171 + png_uint_16 delay_den;
1172 + png_byte dispose_op;
1173 + png_byte blend_op;
1175 + png_debug(1, "in png_handle_fcTL");
1177 + png_ensure_sequence_number(png_ptr, length);
1179 + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
1181 + png_error(png_ptr, "Missing IHDR before fcTL");
1183 + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
1185 + /* for any frames other then the first this message may be misleading,
1186 + * but correct. PNG_HAVE_IDAT is unset before the frame head is read
1187 + * i can't think of a better message */
1188 + png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
1189 + png_crc_finish(png_ptr, length-4);
1192 + else if ((png_ptr->mode & PNG_HAVE_fcTL) != 0)
1194 + png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
1195 + png_crc_finish(png_ptr, length-4);
1198 + else if (length != 26)
1200 + png_warning(png_ptr, "fcTL with invalid length skipped");
1201 + png_crc_finish(png_ptr, length-4);
1205 + png_crc_read(png_ptr, data, 22);
1206 + png_crc_finish(png_ptr, 0);
1208 + width = png_get_uint_31(png_ptr, data);
1209 + height = png_get_uint_31(png_ptr, data + 4);
1210 + x_offset = png_get_uint_31(png_ptr, data + 8);
1211 + y_offset = png_get_uint_31(png_ptr, data + 12);
1212 + delay_num = png_get_uint_16(data + 16);
1213 + delay_den = png_get_uint_16(data + 18);
1214 + dispose_op = data[20];
1215 + blend_op = data[21];
1217 + if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
1219 + png_warning(png_ptr, "fcTL for the first frame must have zero offset");
1223 + if (info_ptr != NULL)
1225 + if (png_ptr->num_frames_read == 0 &&
1226 + (width != info_ptr->width || height != info_ptr->height))
1228 + png_warning(png_ptr, "size in first frame's fcTL must match "
1229 + "the size in IHDR");
1233 + /* The set function will do more error checking */
1234 + png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
1235 + x_offset, y_offset, delay_num, delay_den,
1236 + dispose_op, blend_op);
1238 + png_read_reinit(png_ptr, info_ptr);
1240 + png_ptr->mode |= PNG_HAVE_fcTL;
1245 +png_have_info(png_structp png_ptr, png_infop info_ptr)
1247 + if ((info_ptr->valid & PNG_INFO_acTL) != 0 &&
1248 + (info_ptr->valid & PNG_INFO_fcTL) == 0)
1250 + png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
1251 + info_ptr->num_frames++;
1256 +png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1258 + png_ensure_sequence_number(png_ptr, length);
1260 + /* This function is only called from png_read_end(), png_read_info(),
1261 + * and png_push_read_chunk() which means that:
1262 + * - the user doesn't want to read this frame
1263 + * - or this is an out-of-place fdAT
1264 + * in either case it is safe to ignore the chunk with a warning */
1265 + png_warning(png_ptr, "ignoring fdAT chunk");
1266 + png_crc_finish(png_ptr, length - 4);
1267 + PNG_UNUSED(info_ptr)
1271 +png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
1274 + png_uint_32 sequence_number;
1277 + png_error(png_ptr, "invalid fcTL or fdAT chunk found");
1279 + png_crc_read(png_ptr, data, 4);
1280 + sequence_number = png_get_uint_31(png_ptr, data);
1282 + if (sequence_number != png_ptr->next_seq_num)
1283 + png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
1286 + png_ptr->next_seq_num++;
1288 +#endif /* READ_APNG */
1290 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1291 /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
1293 @@ -4032,6 +4211,38 @@
1297 +#ifdef PNG_READ_APNG_SUPPORTED
1298 + png_uint_32 bytes_to_skip = 0;
1300 + while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
1302 + png_crc_finish(png_ptr, bytes_to_skip);
1303 + bytes_to_skip = 0;
1305 + png_ptr->idat_size = png_read_chunk_header(png_ptr);
1306 + if (png_ptr->num_frames_read == 0)
1308 + if (png_ptr->chunk_name != png_IDAT)
1309 + png_error(png_ptr, "Not enough image data");
1313 + if (png_ptr->chunk_name == png_IEND)
1314 + png_error(png_ptr, "Not enough image data");
1315 + if (png_ptr->chunk_name != png_fdAT)
1317 + png_warning(png_ptr, "Skipped (ignored) a chunk "
1318 + "between APNG chunks");
1319 + bytes_to_skip = png_ptr->idat_size;
1323 + png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
1325 + png_ptr->idat_size -= 4;
1329 while (png_ptr->idat_size == 0)
1331 png_crc_finish(png_ptr, 0);
1332 @@ -4043,6 +4254,7 @@
1333 if (png_ptr->chunk_name != png_IDAT)
1334 png_error(png_ptr, "Not enough image data");
1336 +#endif /* READ_APNG */
1338 avail_in = png_ptr->IDAT_read_size;
1340 @@ -4106,6 +4318,9 @@
1342 png_ptr->mode |= PNG_AFTER_IDAT;
1343 png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
1344 +#ifdef PNG_READ_APNG_SUPPORTED
1345 + png_ptr->num_frames_read++;
1348 if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
1349 png_chunk_benign_error(png_ptr, "Extra compressed data");
1350 @@ -4544,4 +4759,80 @@
1352 png_ptr->flags |= PNG_FLAG_ROW_INIT;
1355 +#ifdef PNG_READ_APNG_SUPPORTED
1356 +/* This function is to be called after the main IDAT set has been read and
1357 + * before a new IDAT is read. It resets some parts of png_ptr
1358 + * to make them usable by the read functions again */
1360 +png_read_reset(png_structp png_ptr)
1362 + png_ptr->mode &= ~PNG_HAVE_IDAT;
1363 + png_ptr->mode &= ~PNG_AFTER_IDAT;
1364 + png_ptr->row_number = 0;
1365 + png_ptr->pass = 0;
1369 +png_read_reinit(png_structp png_ptr, png_infop info_ptr)
1371 + png_ptr->width = info_ptr->next_frame_width;
1372 + png_ptr->height = info_ptr->next_frame_height;
1373 + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
1374 + png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
1376 + if (png_ptr->prev_row != NULL)
1377 + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
1380 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
1381 +/* same as png_read_reset() but for the progressive reader */
1383 +png_progressive_read_reset(png_structp png_ptr)
1385 +#ifdef PNG_READ_INTERLACING_SUPPORTED
1386 + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1388 + /* Start of interlace block */
1389 + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
1391 + /* Offset to next interlace block */
1392 + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
1394 + /* Start of interlace block in the y direction */
1395 + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
1397 + /* Offset to next interlace block in the y direction */
1398 + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
1400 + if (png_ptr->interlaced != 0)
1402 + if ((png_ptr->transformations & PNG_INTERLACE) == 0)
1403 + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1404 + png_pass_ystart[0]) / png_pass_yinc[0];
1406 + png_ptr->num_rows = png_ptr->height;
1408 + png_ptr->iwidth = (png_ptr->width +
1409 + png_pass_inc[png_ptr->pass] - 1 -
1410 + png_pass_start[png_ptr->pass]) /
1411 + png_pass_inc[png_ptr->pass];
1414 +#endif /* READ_INTERLACING */
1416 + png_ptr->num_rows = png_ptr->height;
1417 + png_ptr->iwidth = png_ptr->width;
1419 + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
1420 + if (inflateReset(&(png_ptr->zstream)) != Z_OK)
1421 + png_error(png_ptr, "inflateReset failed");
1422 + png_ptr->zstream.avail_in = 0;
1423 + png_ptr->zstream.next_in = 0;
1424 + png_ptr->zstream.next_out = png_ptr->row_buf;
1425 + png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
1426 + png_ptr->iwidth) + 1;
1428 +#endif /* PROGRESSIVE_READ */
1429 +#endif /* READ_APNG */
1432 ===================================================================
1435 @@ -822,6 +822,11 @@
1436 /* Write the chunk */
1437 png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
1439 +#ifdef PNG_WRITE_APNG_SUPPORTED
1440 + png_ptr->first_frame_width = width;
1441 + png_ptr->first_frame_height = height;
1444 if ((png_ptr->do_filter) == PNG_NO_FILTERS)
1446 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1447 @@ -1004,7 +1009,17 @@
1451 +#ifdef PNG_WRITE_APNG_SUPPORTED
1453 + if (png_ptr->num_frames_written == 0)
1455 png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1456 +#ifdef PNG_WRITE_APNG_SUPPORTED
1458 + png_write_fdAT(png_ptr, data, size);
1460 +#endif /* WRITE_APNG */
1462 png_ptr->mode |= PNG_HAVE_IDAT;
1464 png_ptr->zstream.next_out = data;
1465 @@ -1051,7 +1066,17 @@
1469 +#ifdef PNG_WRITE_APNG_SUPPORTED
1471 + if (png_ptr->num_frames_written == 0)
1473 png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1474 +#ifdef PNG_WRITE_APNG_SUPPORTED
1476 + png_write_fdAT(png_ptr, data, size);
1478 +#endif /* WRITE_APNG */
1480 png_ptr->zstream.avail_out = 0;
1481 png_ptr->zstream.next_out = NULL;
1482 png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
1483 @@ -1865,6 +1890,82 @@
1487 +#ifdef PNG_WRITE_APNG_SUPPORTED
1489 +png_write_acTL(png_structp png_ptr,
1490 + png_uint_32 num_frames, png_uint_32 num_plays)
1494 + png_debug(1, "in png_write_acTL");
1496 + png_ptr->num_frames_to_write = num_frames;
1498 + if ((png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) != 0)
1501 + png_save_uint_32(buf, num_frames);
1502 + png_save_uint_32(buf + 4, num_plays);
1504 + png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
1508 +png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
1509 + png_uint_32 x_offset, png_uint_32 y_offset,
1510 + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
1511 + png_byte blend_op)
1515 + png_debug(1, "in png_write_fcTL");
1517 + if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
1518 + png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
1519 + if (png_ptr->num_frames_written == 0 &&
1520 + (width != png_ptr->first_frame_width ||
1521 + height != png_ptr->first_frame_height))
1522 + png_error(png_ptr, "width and/or height in the first frame's fcTL "
1523 + "don't match the ones in IHDR");
1525 + /* more error checking */
1526 + png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1527 + delay_num, delay_den, dispose_op, blend_op);
1529 + png_save_uint_32(buf, png_ptr->next_seq_num);
1530 + png_save_uint_32(buf + 4, width);
1531 + png_save_uint_32(buf + 8, height);
1532 + png_save_uint_32(buf + 12, x_offset);
1533 + png_save_uint_32(buf + 16, y_offset);
1534 + png_save_uint_16(buf + 20, delay_num);
1535 + png_save_uint_16(buf + 22, delay_den);
1536 + buf[24] = dispose_op;
1537 + buf[25] = blend_op;
1539 + png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
1541 + png_ptr->next_seq_num++;
1545 +png_write_fdAT(png_structp png_ptr,
1546 + png_const_bytep data, png_size_t length)
1550 + png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
1552 + png_save_uint_32(buf, png_ptr->next_seq_num);
1553 + png_write_chunk_data(png_ptr, buf, 4);
1555 + png_write_chunk_data(png_ptr, data, length);
1557 + png_write_chunk_end(png_ptr);
1559 + png_ptr->next_seq_num++;
1561 +#endif /* WRITE_APNG */
1563 /* Initializes the row writing capability of libpng */
1565 png_write_start_row(png_structrp png_ptr)
1566 @@ -2759,4 +2860,39 @@
1568 #endif /* WRITE_FLUSH */
1571 +#ifdef PNG_WRITE_APNG_SUPPORTED
1573 +png_write_reset(png_structp png_ptr)
1575 + png_ptr->row_number = 0;
1576 + png_ptr->pass = 0;
1577 + png_ptr->mode &= ~PNG_HAVE_IDAT;
1581 +png_write_reinit(png_structp png_ptr, png_infop info_ptr,
1582 + png_uint_32 width, png_uint_32 height)
1584 + if (png_ptr->num_frames_written == 0 &&
1585 + (width != png_ptr->first_frame_width ||
1586 + height != png_ptr->first_frame_height))
1587 + png_error(png_ptr, "width and/or height in the first frame's fcTL "
1588 + "don't match the ones in IHDR");
1589 + if (width > png_ptr->first_frame_width ||
1590 + height > png_ptr->first_frame_height)
1591 + png_error(png_ptr, "width and/or height for a frame greater than "
1592 + "the ones in IHDR");
1594 + png_set_IHDR(png_ptr, info_ptr, width, height,
1595 + info_ptr->bit_depth, info_ptr->color_type,
1596 + info_ptr->interlace_type, info_ptr->compression_type,
1597 + info_ptr->filter_type);
1599 + png_ptr->width = width;
1600 + png_ptr->height = height;
1601 + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
1602 + png_ptr->usr_width = png_ptr->width;
1604 +#endif /* WRITE_APNG */
1606 Index: scripts/symbols.def
1607 ===================================================================
1608 --- scripts/symbols.def
1609 +++ scripts/symbols.def
1610 @@ -250,3 +250,23 @@
1611 png_get_palette_max @243
1613 png_image_write_to_memory @245
1616 + png_get_num_frames @248
1617 + png_get_num_plays @249
1618 + png_get_next_frame_fcTL @250
1619 + png_set_next_frame_fcTL @251
1620 + png_get_next_frame_width @252
1621 + png_get_next_frame_height @253
1622 + png_get_next_frame_x_offset @254
1623 + png_get_next_frame_y_offset @255
1624 + png_get_next_frame_delay_num @256
1625 + png_get_next_frame_delay_den @257
1626 + png_get_next_frame_dispose_op @258
1627 + png_get_next_frame_blend_op @259
1628 + png_get_first_frame_is_hidden @260
1629 + png_set_first_frame_is_hidden @261
1630 + png_read_frame_head @262
1631 + png_set_progressive_frame_fn @263
1632 + png_write_frame_head @264
1633 + png_write_frame_tail @265