commit e947a90
hovercats
·
2024-04-15 16:28:34 +0000 UTC
parent b7fb955
libnpg: remove patch
4 files changed,
+0,
-1745
+0,
-2
1@@ -1,7 +1,5 @@
2 #!/bin/sh -e
3
4-patch -p1 < apng.patch
5-
6 ./configure \
7 --prefix=/usr
8
+0,
-1
1@@ -1,2 +1 @@
2 0dea43749579a69fcc15438f98d49f8222e75cb83020bbdfefabcbee3e0df13e77
3-863a91028e401842ec2b61710246b0bd7515d5e5ea24547c25c7874b754c6ae1d7
+0,
-1741
1@@ -1,1741 +0,0 @@
2-diff --git a/png.h b/png.h
3-index cfc4841..da4608a 100644
4---- a/png.h
5-+++ b/png.h
6-@@ -330,6 +330,10 @@
7- # include "pnglibconf.h"
8- #endif
9-
10-+#define PNG_APNG_SUPPORTED
11-+#define PNG_READ_APNG_SUPPORTED
12-+#define PNG_WRITE_APNG_SUPPORTED
13-+
14- #ifndef PNG_VERSION_INFO_ONLY
15- /* Machine specific configuration. */
16- # include "pngconf.h"
17-@@ -425,6 +429,17 @@ extern "C" {
18- * See pngconf.h for base types that vary by machine/system
19- */
20-
21-+#ifdef PNG_APNG_SUPPORTED
22-+/* dispose_op flags from inside fcTL */
23-+#define PNG_DISPOSE_OP_NONE 0x00U
24-+#define PNG_DISPOSE_OP_BACKGROUND 0x01U
25-+#define PNG_DISPOSE_OP_PREVIOUS 0x02U
26-+
27-+/* blend_op flags from inside fcTL */
28-+#define PNG_BLEND_OP_SOURCE 0x00U
29-+#define PNG_BLEND_OP_OVER 0x01U
30-+#endif /* PNG_APNG_SUPPORTED */
31-+
32- /* This triggers a compiler error in png.c, if png.c and png.h
33- * do not agree upon the version number.
34- */
35-@@ -746,6 +761,10 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
36- #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
37- #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
38- #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
39-+#ifdef PNG_APNG_SUPPORTED
40-+#define PNG_INFO_acTL 0x20000U
41-+#define PNG_INFO_fcTL 0x40000U
42-+#endif
43-
44- /* This is used for the transformation routines, as some of them
45- * change these values for the row. It also should enable using
46-@@ -783,6 +802,10 @@ typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
47- #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
48- typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
49- typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
50-+#ifdef PNG_APNG_SUPPORTED
51-+typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
52-+ png_uint_32));
53-+#endif
54-
55- /* The following callback receives png_uint_32 row_number, int pass for the
56- * png_bytep data of the row. When transforming an interlaced image the
57-@@ -3226,6 +3249,74 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
58- /*******************************************************************************
59- * END OF HARDWARE AND SOFTWARE OPTIONS
60- ******************************************************************************/
61-+#ifdef PNG_APNG_SUPPORTED
62-+PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
63-+ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
64-+
65-+PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
66-+ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
67-+
68-+PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
69-+ png_infop info_ptr));
70-+
71-+PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
72-+ png_infop info_ptr));
73-+
74-+PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
75-+ (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
76-+ png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
77-+ png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
78-+ png_byte *blend_op));
79-+
80-+PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
81-+ (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
82-+ png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
83-+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
84-+ png_byte blend_op));
85-+
86-+PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
87-+ (png_structp png_ptr, png_infop info_ptr));
88-+PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
89-+ (png_structp png_ptr, png_infop info_ptr));
90-+PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
91-+ (png_structp png_ptr, png_infop info_ptr));
92-+PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
93-+ (png_structp png_ptr, png_infop info_ptr));
94-+PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
95-+ (png_structp png_ptr, png_infop info_ptr));
96-+PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
97-+ (png_structp png_ptr, png_infop info_ptr));
98-+PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
99-+ (png_structp png_ptr, png_infop info_ptr));
100-+PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
101-+ (png_structp png_ptr, png_infop info_ptr));
102-+PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
103-+ (png_structp png_ptr, png_infop info_ptr));
104-+PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
105-+ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
106-+
107-+#ifdef PNG_READ_APNG_SUPPORTED
108-+PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
109-+ png_infop info_ptr));
110-+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
111-+PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
112-+ png_progressive_frame_ptr frame_info_fn,
113-+ png_progressive_frame_ptr frame_end_fn));
114-+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
115-+#endif /* PNG_READ_APNG_SUPPORTED */
116-+
117-+#ifdef PNG_WRITE_APNG_SUPPORTED
118-+PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
119-+ png_infop info_ptr, png_bytepp row_pointers,
120-+ png_uint_32 width, png_uint_32 height,
121-+ png_uint_32 x_offset, png_uint_32 y_offset,
122-+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
123-+ png_byte blend_op));
124-+
125-+PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
126-+ png_infop info_ptr));
127-+#endif /* PNG_WRITE_APNG_SUPPORTED */
128-+#endif /* PNG_APNG_SUPPORTED */
129-
130- /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
131- * defs, and in scripts/symbols.def.
132-@@ -3235,7 +3326,11 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
133- * one to use is one more than this.)
134- */
135- #ifdef PNG_EXPORT_LAST_ORDINAL
136-+#ifdef PNG_APNG_SUPPORTED
137-+ PNG_EXPORT_LAST_ORDINAL(269);
138-+#else
139- PNG_EXPORT_LAST_ORDINAL(249);
140-+#endif /* PNG_APNG_SUPPORTED */
141- #endif
142-
143- #ifdef __cplusplus
144-diff --git a/pngget.c b/pngget.c
145-index 1490a03..df6f8f7 100644
146---- a/pngget.c
147-+++ b/pngget.c
148-@@ -1257,4 +1257,166 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
149- # endif
150- #endif
151-
152-+#ifdef PNG_APNG_SUPPORTED
153-+png_uint_32 PNGAPI
154-+png_get_acTL(png_structp png_ptr, png_infop info_ptr,
155-+ png_uint_32 *num_frames, png_uint_32 *num_plays)
156-+{
157-+ png_debug1(1, "in %s retrieval function", "acTL");
158-+
159-+ if (png_ptr != NULL && info_ptr != NULL &&
160-+ (info_ptr->valid & PNG_INFO_acTL) &&
161-+ num_frames != NULL && num_plays != NULL)
162-+ {
163-+ *num_frames = info_ptr->num_frames;
164-+ *num_plays = info_ptr->num_plays;
165-+ return (1);
166-+ }
167-+
168-+ return (0);
169-+}
170-+
171-+png_uint_32 PNGAPI
172-+png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
173-+{
174-+ png_debug(1, "in png_get_num_frames()");
175-+
176-+ if (png_ptr != NULL && info_ptr != NULL)
177-+ return (info_ptr->num_frames);
178-+ return (0);
179-+}
180-+
181-+png_uint_32 PNGAPI
182-+png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
183-+{
184-+ png_debug(1, "in png_get_num_plays()");
185-+
186-+ if (png_ptr != NULL && info_ptr != NULL)
187-+ return (info_ptr->num_plays);
188-+ return (0);
189-+}
190-+
191-+png_uint_32 PNGAPI
192-+png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
193-+ png_uint_32 *width, png_uint_32 *height,
194-+ png_uint_32 *x_offset, png_uint_32 *y_offset,
195-+ png_uint_16 *delay_num, png_uint_16 *delay_den,
196-+ png_byte *dispose_op, png_byte *blend_op)
197-+{
198-+ png_debug1(1, "in %s retrieval function", "fcTL");
199-+
200-+ if (png_ptr != NULL && info_ptr != NULL &&
201-+ (info_ptr->valid & PNG_INFO_fcTL) &&
202-+ width != NULL && height != NULL &&
203-+ x_offset != NULL && y_offset != NULL &&
204-+ delay_num != NULL && delay_den != NULL &&
205-+ dispose_op != NULL && blend_op != NULL)
206-+ {
207-+ *width = info_ptr->next_frame_width;
208-+ *height = info_ptr->next_frame_height;
209-+ *x_offset = info_ptr->next_frame_x_offset;
210-+ *y_offset = info_ptr->next_frame_y_offset;
211-+ *delay_num = info_ptr->next_frame_delay_num;
212-+ *delay_den = info_ptr->next_frame_delay_den;
213-+ *dispose_op = info_ptr->next_frame_dispose_op;
214-+ *blend_op = info_ptr->next_frame_blend_op;
215-+ return (1);
216-+ }
217-+
218-+ return (0);
219-+}
220-+
221-+png_uint_32 PNGAPI
222-+png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
223-+{
224-+ png_debug(1, "in png_get_next_frame_width()");
225-+
226-+ if (png_ptr != NULL && info_ptr != NULL)
227-+ return (info_ptr->next_frame_width);
228-+ return (0);
229-+}
230-+
231-+png_uint_32 PNGAPI
232-+png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
233-+{
234-+ png_debug(1, "in png_get_next_frame_height()");
235-+
236-+ if (png_ptr != NULL && info_ptr != NULL)
237-+ return (info_ptr->next_frame_height);
238-+ return (0);
239-+}
240-+
241-+png_uint_32 PNGAPI
242-+png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
243-+{
244-+ png_debug(1, "in png_get_next_frame_x_offset()");
245-+
246-+ if (png_ptr != NULL && info_ptr != NULL)
247-+ return (info_ptr->next_frame_x_offset);
248-+ return (0);
249-+}
250-+
251-+png_uint_32 PNGAPI
252-+png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
253-+{
254-+ png_debug(1, "in png_get_next_frame_y_offset()");
255-+
256-+ if (png_ptr != NULL && info_ptr != NULL)
257-+ return (info_ptr->next_frame_y_offset);
258-+ return (0);
259-+}
260-+
261-+png_uint_16 PNGAPI
262-+png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
263-+{
264-+ png_debug(1, "in png_get_next_frame_delay_num()");
265-+
266-+ if (png_ptr != NULL && info_ptr != NULL)
267-+ return (info_ptr->next_frame_delay_num);
268-+ return (0);
269-+}
270-+
271-+png_uint_16 PNGAPI
272-+png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
273-+{
274-+ png_debug(1, "in png_get_next_frame_delay_den()");
275-+
276-+ if (png_ptr != NULL && info_ptr != NULL)
277-+ return (info_ptr->next_frame_delay_den);
278-+ return (0);
279-+}
280-+
281-+png_byte PNGAPI
282-+png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
283-+{
284-+ png_debug(1, "in png_get_next_frame_dispose_op()");
285-+
286-+ if (png_ptr != NULL && info_ptr != NULL)
287-+ return (info_ptr->next_frame_dispose_op);
288-+ return (0);
289-+}
290-+
291-+png_byte PNGAPI
292-+png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
293-+{
294-+ png_debug(1, "in png_get_next_frame_blend_op()");
295-+
296-+ if (png_ptr != NULL && info_ptr != NULL)
297-+ return (info_ptr->next_frame_blend_op);
298-+ return (0);
299-+}
300-+
301-+png_byte PNGAPI
302-+png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
303-+{
304-+ png_debug(1, "in png_first_frame_is_hidden()");
305-+
306-+ if (png_ptr != NULL)
307-+ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
308-+
309-+ PNG_UNUSED(info_ptr)
310-+
311-+ return 0;
312-+}
313-+#endif /* PNG_APNG_SUPPORTED */
314- #endif /* READ || WRITE */
315-diff --git a/pnginfo.h b/pnginfo.h
316-index 1f98ded..ac7b269 100644
317---- a/pnginfo.h
318-+++ b/pnginfo.h
319-@@ -263,5 +263,18 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
320- png_bytepp row_pointers; /* the image bits */
321- #endif
322-
323-+#ifdef PNG_APNG_SUPPORTED
324-+ png_uint_32 num_frames; /* including default image */
325-+ png_uint_32 num_plays;
326-+ png_uint_32 next_frame_width;
327-+ png_uint_32 next_frame_height;
328-+ png_uint_32 next_frame_x_offset;
329-+ png_uint_32 next_frame_y_offset;
330-+ png_uint_16 next_frame_delay_num;
331-+ png_uint_16 next_frame_delay_den;
332-+ png_byte next_frame_dispose_op;
333-+ png_byte next_frame_blend_op;
334-+#endif
335-+
336- };
337- #endif /* PNGINFO_H */
338-diff --git a/pngpread.c b/pngpread.c
339-index e283627..2eaeca0 100644
340---- a/pngpread.c
341-+++ b/pngpread.c
342-@@ -195,6 +195,106 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
343-
344- chunk_name = png_ptr->chunk_name;
345-
346-+#ifdef PNG_READ_APNG_SUPPORTED
347-+ if (png_ptr->num_frames_read > 0 &&
348-+ png_ptr->num_frames_read < info_ptr->num_frames)
349-+ {
350-+ if (chunk_name == png_IDAT)
351-+ {
352-+ /* Discard trailing IDATs for the first frame */
353-+ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
354-+ png_error(png_ptr, "out of place IDAT");
355-+
356-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
357-+ {
358-+ png_push_save_buffer(png_ptr);
359-+ return;
360-+ }
361-+
362-+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
363-+ return;
364-+ }
365-+ else if (chunk_name == png_fdAT)
366-+ {
367-+ if (png_ptr->buffer_size < 4)
368-+ {
369-+ png_push_save_buffer(png_ptr);
370-+ return;
371-+ }
372-+
373-+ png_ensure_sequence_number(png_ptr, 4);
374-+
375-+ if (!(png_ptr->mode & PNG_HAVE_fcTL))
376-+ {
377-+ /* Discard trailing fdATs for frames other than the first */
378-+ if (png_ptr->num_frames_read < 2)
379-+ png_error(png_ptr, "out of place fdAT");
380-+
381-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
382-+ {
383-+ png_push_save_buffer(png_ptr);
384-+ return;
385-+ }
386-+
387-+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
388-+ return;
389-+ }
390-+
391-+ else
392-+ {
393-+ /* frame data follows */
394-+ png_ptr->idat_size = png_ptr->push_length - 4;
395-+ png_ptr->mode |= PNG_HAVE_IDAT;
396-+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
397-+
398-+ return;
399-+ }
400-+ }
401-+
402-+ else if (chunk_name == png_fcTL)
403-+ {
404-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
405-+ {
406-+ png_push_save_buffer(png_ptr);
407-+ return;
408-+ }
409-+
410-+ png_read_reset(png_ptr);
411-+ png_ptr->mode &= ~PNG_HAVE_fcTL;
412-+
413-+ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
414-+
415-+ if (!(png_ptr->mode & PNG_HAVE_fcTL))
416-+ png_error(png_ptr, "missing required fcTL chunk");
417-+
418-+ png_read_reinit(png_ptr, info_ptr);
419-+ png_progressive_read_reset(png_ptr);
420-+
421-+ if (png_ptr->frame_info_fn != NULL)
422-+ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
423-+
424-+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
425-+
426-+ return;
427-+ }
428-+
429-+ else
430-+ {
431-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
432-+ {
433-+ png_push_save_buffer(png_ptr);
434-+ return;
435-+ }
436-+ png_warning(png_ptr, "Skipped (ignored) a chunk "
437-+ "between APNG chunks");
438-+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
439-+ return;
440-+ }
441-+
442-+ return;
443-+ }
444-+#endif /* PNG_READ_APNG_SUPPORTED */
445-+
446- if (chunk_name == png_IDAT)
447- {
448- if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
449-@@ -261,6 +361,9 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
450-
451- else if (chunk_name == png_IDAT)
452- {
453-+#ifdef PNG_READ_APNG_SUPPORTED
454-+ png_have_info(png_ptr, info_ptr);
455-+#endif
456- png_ptr->idat_size = png_ptr->push_length;
457- png_ptr->process_mode = PNG_READ_IDAT_MODE;
458- png_push_have_info(png_ptr, info_ptr);
459-@@ -406,6 +509,30 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
460- png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
461- }
462- #endif
463-+#ifdef PNG_READ_APNG_SUPPORTED
464-+ else if (chunk_name == png_acTL)
465-+ {
466-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
467-+ {
468-+ png_push_save_buffer(png_ptr);
469-+ return;
470-+ }
471-+
472-+ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
473-+ }
474-+
475-+ else if (chunk_name == png_fcTL)
476-+ {
477-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
478-+ {
479-+ png_push_save_buffer(png_ptr);
480-+ return;
481-+ }
482-+
483-+ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
484-+ }
485-+
486-+#endif /* PNG_READ_APNG_SUPPORTED */
487-
488- else
489- {
490-@@ -539,7 +666,11 @@ png_push_read_IDAT(png_structrp png_ptr)
491- png_byte chunk_tag[4];
492-
493- /* TODO: this code can be commoned up with the same code in push_read */
494-+#ifdef PNG_READ_APNG_SUPPORTED
495-+ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
496-+#else
497- PNG_PUSH_SAVE_BUFFER_IF_LT(8)
498-+#endif
499- png_push_fill_buffer(png_ptr, chunk_length, 4);
500- png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
501- png_reset_crc(png_ptr);
502-@@ -547,17 +678,64 @@ png_push_read_IDAT(png_structrp png_ptr)
503- png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
504- png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
505-
506-+#ifdef PNG_READ_APNG_SUPPORTED
507-+ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
508-+ {
509-+ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
510-+ {
511-+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
512-+ if (png_ptr->frame_end_fn != NULL)
513-+ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
514-+ png_ptr->num_frames_read++;
515-+ return;
516-+ }
517-+ else
518-+ {
519-+ if (png_ptr->chunk_name == png_IEND)
520-+ png_error(png_ptr, "Not enough image data");
521-+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
522-+ {
523-+ png_push_save_buffer(png_ptr);
524-+ return;
525-+ }
526-+ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
527-+ "APNG chunks");
528-+ png_crc_finish(png_ptr, png_ptr->push_length);
529-+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
530-+ return;
531-+ }
532-+ }
533-+ else
534-+#endif
535-+#ifdef PNG_READ_APNG_SUPPORTED
536-+ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
537-+#else
538- if (png_ptr->chunk_name != png_IDAT)
539-+#endif
540- {
541- png_ptr->process_mode = PNG_READ_CHUNK_MODE;
542-
543- if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
544- png_error(png_ptr, "Not enough compressed data");
545-
546-+#ifdef PNG_READ_APNG_SUPPORTED
547-+ if (png_ptr->frame_end_fn != NULL)
548-+ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
549-+ png_ptr->num_frames_read++;
550-+#endif
551-+
552- return;
553- }
554-
555- png_ptr->idat_size = png_ptr->push_length;
556-+
557-+#ifdef PNG_READ_APNG_SUPPORTED
558-+ if (png_ptr->num_frames_read > 0)
559-+ {
560-+ png_ensure_sequence_number(png_ptr, 4);
561-+ png_ptr->idat_size -= 4;
562-+ }
563-+#endif
564- }
565-
566- if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
567-@@ -631,6 +809,15 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
568- if (!(buffer_length > 0) || buffer == NULL)
569- png_error(png_ptr, "No IDAT data (internal error)");
570-
571-+#ifdef PNG_READ_APNG_SUPPORTED
572-+ /* If the app is not APNG-aware, decode only the first frame */
573-+ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
574-+ {
575-+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
576-+ return;
577-+ }
578-+#endif
579-+
580- /* This routine must process all the data it has been given
581- * before returning, calling the row callback as required to
582- * handle the uncompressed results.
583-@@ -1085,6 +1272,18 @@ png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,
584- png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
585- }
586-
587-+#ifdef PNG_READ_APNG_SUPPORTED
588-+void PNGAPI
589-+png_set_progressive_frame_fn(png_structp png_ptr,
590-+ png_progressive_frame_ptr frame_info_fn,
591-+ png_progressive_frame_ptr frame_end_fn)
592-+{
593-+ png_ptr->frame_info_fn = frame_info_fn;
594-+ png_ptr->frame_end_fn = frame_end_fn;
595-+ png_ptr->apng_flags |= PNG_APNG_APP;
596-+}
597-+#endif
598-+
599- png_voidp PNGAPI
600- png_get_progressive_ptr(png_const_structrp png_ptr)
601- {
602-diff --git a/pngpriv.h b/pngpriv.h
603-index 7c19373..0757ecc 100644
604---- a/pngpriv.h
605-+++ b/pngpriv.h
606-@@ -628,6 +628,10 @@
607- #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
608- #define PNG_WROTE_eXIf 0x4000U
609- #define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
610-+#ifdef PNG_APNG_SUPPORTED
611-+#define PNG_HAVE_acTL 0x10000U
612-+#define PNG_HAVE_fcTL 0x20000U
613-+#endif
614-
615- /* Flags for the transformations the PNG library does on the image data */
616- #define PNG_BGR 0x0001U
617-@@ -864,6 +868,16 @@
618- #define png_tRNS PNG_U32(116, 82, 78, 83)
619- #define png_zTXt PNG_U32(122, 84, 88, 116)
620-
621-+#ifdef PNG_APNG_SUPPORTED
622-+#define png_acTL PNG_U32( 97, 99, 84, 76)
623-+#define png_fcTL PNG_U32(102, 99, 84, 76)
624-+#define png_fdAT PNG_U32(102, 100, 65, 84)
625-+
626-+/* For png_struct.apng_flags: */
627-+#define PNG_FIRST_FRAME_HIDDEN 0x0001U
628-+#define PNG_APNG_APP 0x0002U
629-+#endif
630-+
631- /* The following will work on (signed char*) strings, whereas the get_uint_32
632- * macro will fail on top-bit-set values because of the sign extension.
633- */
634-@@ -1635,6 +1649,47 @@ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,
635- */
636- #endif
637-
638-+#ifdef PNG_APNG_SUPPORTED
639-+PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
640-+ png_uint_32 width, png_uint_32 height,
641-+ png_uint_32 x_offset, png_uint_32 y_offset,
642-+ png_uint_16 delay_num, png_uint_16 delay_den,
643-+ png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
644-+
645-+#ifdef PNG_READ_APNG_SUPPORTED
646-+PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
647-+ png_uint_32 length),PNG_EMPTY);
648-+PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
649-+ png_uint_32 length),PNG_EMPTY);
650-+PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
651-+ png_uint_32 length),PNG_EMPTY);
652-+PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
653-+PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
654-+ png_uint_32 length),PNG_EMPTY);
655-+PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
656-+PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
657-+ png_infop info_ptr),PNG_EMPTY);
658-+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
659-+PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
660-+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
661-+#endif /* PNG_READ_APNG_SUPPORTED */
662-+
663-+#ifdef PNG_WRITE_APNG_SUPPORTED
664-+PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
665-+ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
666-+PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
667-+ png_uint_32 width, png_uint_32 height,
668-+ png_uint_32 x_offset, png_uint_32 y_offset,
669-+ png_uint_16 delay_num, png_uint_16 delay_den,
670-+ png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
671-+PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
672-+ png_const_bytep data, png_size_t length),PNG_EMPTY);
673-+PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
674-+PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
675-+ png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
676-+#endif /* PNG_WRITE_APNG_SUPPORTED */
677-+#endif /* PNG_APNG_SUPPORTED */
678-+
679- /* Added at libpng version 1.4.0 */
680- #ifdef PNG_COLORSPACE_SUPPORTED
681- /* These internal functions are for maintaining the colorspace structure within
682-diff --git a/pngread.c b/pngread.c
683-index 96996ce..a6e35a9 100644
684---- a/pngread.c
685-+++ b/pngread.c
686-@@ -161,6 +161,9 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
687-
688- else if (chunk_name == png_IDAT)
689- {
690-+#ifdef PNG_READ_APNG_SUPPORTED
691-+ png_have_info(png_ptr, info_ptr);
692-+#endif
693- png_ptr->idat_size = length;
694- break;
695- }
696-@@ -255,6 +258,17 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
697- png_handle_iTXt(png_ptr, info_ptr, length);
698- #endif
699-
700-+#ifdef PNG_READ_APNG_SUPPORTED
701-+ else if (chunk_name == png_acTL)
702-+ png_handle_acTL(png_ptr, info_ptr, length);
703-+
704-+ else if (chunk_name == png_fcTL)
705-+ png_handle_fcTL(png_ptr, info_ptr, length);
706-+
707-+ else if (chunk_name == png_fdAT)
708-+ png_handle_fdAT(png_ptr, info_ptr, length);
709-+#endif
710-+
711- else
712- png_handle_unknown(png_ptr, info_ptr, length,
713- PNG_HANDLE_CHUNK_AS_DEFAULT);
714-@@ -262,6 +276,72 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
715- }
716- #endif /* SEQUENTIAL_READ */
717-
718-+#ifdef PNG_READ_APNG_SUPPORTED
719-+void PNGAPI
720-+png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
721-+{
722-+ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
723-+
724-+ png_debug(0, "Reading frame head");
725-+
726-+ if (!(png_ptr->mode & PNG_HAVE_acTL))
727-+ png_error(png_ptr, "attempt to png_read_frame_head() but "
728-+ "no acTL present");
729-+
730-+ /* do nothing for the main IDAT */
731-+ if (png_ptr->num_frames_read == 0)
732-+ return;
733-+
734-+ png_read_reset(png_ptr);
735-+ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
736-+ png_ptr->mode &= ~PNG_HAVE_fcTL;
737-+
738-+ have_chunk_after_DAT = 0;
739-+ for (;;)
740-+ {
741-+ png_uint_32 length = png_read_chunk_header(png_ptr);
742-+
743-+ if (png_ptr->chunk_name == png_IDAT)
744-+ {
745-+ /* discard trailing IDATs for the first frame */
746-+ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
747-+ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
748-+ png_crc_finish(png_ptr, length);
749-+ }
750-+
751-+ else if (png_ptr->chunk_name == png_fcTL)
752-+ {
753-+ png_handle_fcTL(png_ptr, info_ptr, length);
754-+ have_chunk_after_DAT = 1;
755-+ }
756-+
757-+ else if (png_ptr->chunk_name == png_fdAT)
758-+ {
759-+ png_ensure_sequence_number(png_ptr, length);
760-+
761-+ /* discard trailing fdATs for frames other than the first */
762-+ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
763-+ png_crc_finish(png_ptr, length - 4);
764-+ else if(png_ptr->mode & PNG_HAVE_fcTL)
765-+ {
766-+ png_ptr->idat_size = length - 4;
767-+ png_ptr->mode |= PNG_HAVE_IDAT;
768-+
769-+ break;
770-+ }
771-+ else
772-+ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
773-+ }
774-+ else
775-+ {
776-+ png_warning(png_ptr, "Skipped (ignored) a chunk "
777-+ "between APNG chunks");
778-+ png_crc_finish(png_ptr, length);
779-+ }
780-+ }
781-+}
782-+#endif /* PNG_READ_APNG_SUPPORTED */
783-+
784- /* Optional call to update the users info_ptr structure */
785- void PNGAPI
786- png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
787-diff --git a/pngrutil.c b/pngrutil.c
788-index 068ab19..d0748ff 100644
789---- a/pngrutil.c
790-+++ b/pngrutil.c
791-@@ -864,6 +864,11 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
792- filter_type = buf[11];
793- interlace_type = buf[12];
794-
795-+#ifdef PNG_READ_APNG_SUPPORTED
796-+ png_ptr->first_frame_width = width;
797-+ png_ptr->first_frame_height = height;
798-+#endif
799-+
800- /* Set internal variables */
801- png_ptr->width = width;
802- png_ptr->height = height;
803-@@ -2858,6 +2863,179 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
804- }
805- #endif
806-
807-+#ifdef PNG_READ_APNG_SUPPORTED
808-+void /* PRIVATE */
809-+png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
810-+{
811-+ png_byte data[8];
812-+ png_uint_32 num_frames;
813-+ png_uint_32 num_plays;
814-+ png_uint_32 didSet;
815-+
816-+ png_debug(1, "in png_handle_acTL");
817-+
818-+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
819-+ {
820-+ png_error(png_ptr, "Missing IHDR before acTL");
821-+ }
822-+ else if (png_ptr->mode & PNG_HAVE_IDAT)
823-+ {
824-+ png_warning(png_ptr, "Invalid acTL after IDAT skipped");
825-+ png_crc_finish(png_ptr, length);
826-+ return;
827-+ }
828-+ else if (png_ptr->mode & PNG_HAVE_acTL)
829-+ {
830-+ png_warning(png_ptr, "Duplicate acTL skipped");
831-+ png_crc_finish(png_ptr, length);
832-+ return;
833-+ }
834-+ else if (length != 8)
835-+ {
836-+ png_warning(png_ptr, "acTL with invalid length skipped");
837-+ png_crc_finish(png_ptr, length);
838-+ return;
839-+ }
840-+
841-+ png_crc_read(png_ptr, data, 8);
842-+ png_crc_finish(png_ptr, 0);
843-+
844-+ num_frames = png_get_uint_31(png_ptr, data);
845-+ num_plays = png_get_uint_31(png_ptr, data + 4);
846-+
847-+ /* the set function will do error checking on num_frames */
848-+ didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
849-+ if(didSet)
850-+ png_ptr->mode |= PNG_HAVE_acTL;
851-+}
852-+
853-+void /* PRIVATE */
854-+png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
855-+{
856-+ png_byte data[22];
857-+ png_uint_32 width;
858-+ png_uint_32 height;
859-+ png_uint_32 x_offset;
860-+ png_uint_32 y_offset;
861-+ png_uint_16 delay_num;
862-+ png_uint_16 delay_den;
863-+ png_byte dispose_op;
864-+ png_byte blend_op;
865-+
866-+ png_debug(1, "in png_handle_fcTL");
867-+
868-+ png_ensure_sequence_number(png_ptr, length);
869-+
870-+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
871-+ {
872-+ png_error(png_ptr, "Missing IHDR before fcTL");
873-+ }
874-+ else if (png_ptr->mode & PNG_HAVE_IDAT)
875-+ {
876-+ /* for any frames other then the first this message may be misleading,
877-+ * but correct. PNG_HAVE_IDAT is unset before the frame head is read
878-+ * i can't think of a better message */
879-+ png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
880-+ png_crc_finish(png_ptr, length-4);
881-+ return;
882-+ }
883-+ else if (png_ptr->mode & PNG_HAVE_fcTL)
884-+ {
885-+ png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
886-+ png_crc_finish(png_ptr, length-4);
887-+ return;
888-+ }
889-+ else if (length != 26)
890-+ {
891-+ png_warning(png_ptr, "fcTL with invalid length skipped");
892-+ png_crc_finish(png_ptr, length-4);
893-+ return;
894-+ }
895-+
896-+ png_crc_read(png_ptr, data, 22);
897-+ png_crc_finish(png_ptr, 0);
898-+
899-+ width = png_get_uint_31(png_ptr, data);
900-+ height = png_get_uint_31(png_ptr, data + 4);
901-+ x_offset = png_get_uint_31(png_ptr, data + 8);
902-+ y_offset = png_get_uint_31(png_ptr, data + 12);
903-+ delay_num = png_get_uint_16(data + 16);
904-+ delay_den = png_get_uint_16(data + 18);
905-+ dispose_op = data[20];
906-+ blend_op = data[21];
907-+
908-+ if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
909-+ {
910-+ png_warning(png_ptr, "fcTL for the first frame must have zero offset");
911-+ return;
912-+ }
913-+
914-+ if (info_ptr != NULL)
915-+ {
916-+ if (png_ptr->num_frames_read == 0 &&
917-+ (width != info_ptr->width || height != info_ptr->height))
918-+ {
919-+ png_warning(png_ptr, "size in first frame's fcTL must match "
920-+ "the size in IHDR");
921-+ return;
922-+ }
923-+
924-+ /* The set function will do more error checking */
925-+ png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
926-+ x_offset, y_offset, delay_num, delay_den,
927-+ dispose_op, blend_op);
928-+
929-+ png_read_reinit(png_ptr, info_ptr);
930-+
931-+ png_ptr->mode |= PNG_HAVE_fcTL;
932-+ }
933-+}
934-+
935-+void /* PRIVATE */
936-+png_have_info(png_structp png_ptr, png_infop info_ptr)
937-+{
938-+ if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
939-+ {
940-+ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
941-+ info_ptr->num_frames++;
942-+ }
943-+}
944-+
945-+void /* PRIVATE */
946-+png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
947-+{
948-+ png_ensure_sequence_number(png_ptr, length);
949-+
950-+ /* This function is only called from png_read_end(), png_read_info(),
951-+ * and png_push_read_chunk() which means that:
952-+ * - the user doesn't want to read this frame
953-+ * - or this is an out-of-place fdAT
954-+ * in either case it is safe to ignore the chunk with a warning */
955-+ png_warning(png_ptr, "ignoring fdAT chunk");
956-+ png_crc_finish(png_ptr, length - 4);
957-+ PNG_UNUSED(info_ptr)
958-+}
959-+
960-+void /* PRIVATE */
961-+png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
962-+{
963-+ png_byte data[4];
964-+ png_uint_32 sequence_number;
965-+
966-+ if (length < 4)
967-+ png_error(png_ptr, "invalid fcTL or fdAT chunk found");
968-+
969-+ png_crc_read(png_ptr, data, 4);
970-+ sequence_number = png_get_uint_31(png_ptr, data);
971-+
972-+ if (sequence_number != png_ptr->next_seq_num)
973-+ png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
974-+ "number found");
975-+
976-+ png_ptr->next_seq_num++;
977-+}
978-+#endif /* PNG_READ_APNG_SUPPORTED */
979-+
980- #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
981- /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
982- static int
983-@@ -4166,7 +4344,38 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
984- {
985- uInt avail_in;
986- png_bytep buffer;
987-+#ifdef PNG_READ_APNG_SUPPORTED
988-+ png_uint_32 bytes_to_skip = 0;
989-+
990-+ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
991-+ {
992-+ png_crc_finish(png_ptr, bytes_to_skip);
993-+ bytes_to_skip = 0;
994-+
995-+ png_ptr->idat_size = png_read_chunk_header(png_ptr);
996-+ if (png_ptr->num_frames_read == 0)
997-+ {
998-+ if (png_ptr->chunk_name != png_IDAT)
999-+ png_error(png_ptr, "Not enough image data");
1000-+ }
1001-+ else
1002-+ {
1003-+ if (png_ptr->chunk_name == png_IEND)
1004-+ png_error(png_ptr, "Not enough image data");
1005-+ if (png_ptr->chunk_name != png_fdAT)
1006-+ {
1007-+ png_warning(png_ptr, "Skipped (ignored) a chunk "
1008-+ "between APNG chunks");
1009-+ bytes_to_skip = png_ptr->idat_size;
1010-+ continue;
1011-+ }
1012-+
1013-+ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
1014-
1015-+ png_ptr->idat_size -= 4;
1016-+ }
1017-+ }
1018-+#else
1019- while (png_ptr->idat_size == 0)
1020- {
1021- png_crc_finish(png_ptr, 0);
1022-@@ -4178,7 +4387,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
1023- if (png_ptr->chunk_name != png_IDAT)
1024- png_error(png_ptr, "Not enough image data");
1025- }
1026--
1027-+#endif /* PNG_READ_APNG_SUPPORTED */
1028- avail_in = png_ptr->IDAT_read_size;
1029-
1030- if (avail_in > png_ptr->idat_size)
1031-@@ -4241,6 +4450,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
1032-
1033- png_ptr->mode |= PNG_AFTER_IDAT;
1034- png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
1035-+#ifdef PNG_READ_APNG_SUPPORTED
1036-+ png_ptr->num_frames_read++;
1037-+#endif
1038-
1039- if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
1040- png_chunk_benign_error(png_ptr, "Extra compressed data");
1041-@@ -4678,4 +4890,80 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
1042-
1043- png_ptr->flags |= PNG_FLAG_ROW_INIT;
1044- }
1045-+
1046-+#ifdef PNG_READ_APNG_SUPPORTED
1047-+/* This function is to be called after the main IDAT set has been read and
1048-+ * before a new IDAT is read. It resets some parts of png_ptr
1049-+ * to make them usable by the read functions again */
1050-+void /* PRIVATE */
1051-+png_read_reset(png_structp png_ptr)
1052-+{
1053-+ png_ptr->mode &= ~PNG_HAVE_IDAT;
1054-+ png_ptr->mode &= ~PNG_AFTER_IDAT;
1055-+ png_ptr->row_number = 0;
1056-+ png_ptr->pass = 0;
1057-+}
1058-+
1059-+void /* PRIVATE */
1060-+png_read_reinit(png_structp png_ptr, png_infop info_ptr)
1061-+{
1062-+ png_ptr->width = info_ptr->next_frame_width;
1063-+ png_ptr->height = info_ptr->next_frame_height;
1064-+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
1065-+ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
1066-+ png_ptr->width);
1067-+ if (png_ptr->prev_row)
1068-+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
1069-+}
1070-+
1071-+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
1072-+/* same as png_read_reset() but for the progressive reader */
1073-+void /* PRIVATE */
1074-+png_progressive_read_reset(png_structp png_ptr)
1075-+{
1076-+#ifdef PNG_READ_INTERLACING_SUPPORTED
1077-+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1078-+
1079-+ /* Start of interlace block */
1080-+ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
1081-+
1082-+ /* Offset to next interlace block */
1083-+ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
1084-+
1085-+ /* Start of interlace block in the y direction */
1086-+ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
1087-+
1088-+ /* Offset to next interlace block in the y direction */
1089-+ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
1090-+
1091-+ if (png_ptr->interlaced)
1092-+ {
1093-+ if (!(png_ptr->transformations & PNG_INTERLACE))
1094-+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1095-+ png_pass_ystart[0]) / png_pass_yinc[0];
1096-+ else
1097-+ png_ptr->num_rows = png_ptr->height;
1098-+
1099-+ png_ptr->iwidth = (png_ptr->width +
1100-+ png_pass_inc[png_ptr->pass] - 1 -
1101-+ png_pass_start[png_ptr->pass]) /
1102-+ png_pass_inc[png_ptr->pass];
1103-+ }
1104-+ else
1105-+#endif /* PNG_READ_INTERLACING_SUPPORTED */
1106-+ {
1107-+ png_ptr->num_rows = png_ptr->height;
1108-+ png_ptr->iwidth = png_ptr->width;
1109-+ }
1110-+ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
1111-+ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
1112-+ png_error(png_ptr, "inflateReset failed");
1113-+ png_ptr->zstream.avail_in = 0;
1114-+ png_ptr->zstream.next_in = 0;
1115-+ png_ptr->zstream.next_out = png_ptr->row_buf;
1116-+ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
1117-+ png_ptr->iwidth) + 1;
1118-+}
1119-+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
1120-+#endif /* PNG_READ_APNG_SUPPORTED */
1121- #endif /* READ */
1122-diff --git a/pngset.c b/pngset.c
1123-index 3fc31fe..0bea6bc 100644
1124---- a/pngset.c
1125-+++ b/pngset.c
1126-@@ -280,6 +280,11 @@ png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
1127- info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
1128-
1129- info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
1130-+
1131-+#ifdef PNG_APNG_SUPPORTED
1132-+ /* for non-animated png. this may be overwritten from an acTL chunk later */
1133-+ info_ptr->num_frames = 1;
1134-+#endif
1135- }
1136-
1137- #ifdef PNG_oFFs_SUPPORTED
1138-@@ -1149,6 +1154,147 @@ png_set_sPLT(png_const_structrp png_ptr,
1139- }
1140- #endif /* sPLT */
1141-
1142-+#ifdef PNG_APNG_SUPPORTED
1143-+png_uint_32 PNGAPI
1144-+png_set_acTL(png_structp png_ptr, png_infop info_ptr,
1145-+ png_uint_32 num_frames, png_uint_32 num_plays)
1146-+{
1147-+ png_debug1(1, "in %s storage function", "acTL");
1148-+
1149-+ if (png_ptr == NULL || info_ptr == NULL)
1150-+ {
1151-+ png_warning(png_ptr,
1152-+ "Call to png_set_acTL() with NULL png_ptr "
1153-+ "or info_ptr ignored");
1154-+ return (0);
1155-+ }
1156-+ if (num_frames == 0)
1157-+ {
1158-+ png_warning(png_ptr,
1159-+ "Ignoring attempt to set acTL with num_frames zero");
1160-+ return (0);
1161-+ }
1162-+ if (num_frames > PNG_UINT_31_MAX)
1163-+ {
1164-+ png_warning(png_ptr,
1165-+ "Ignoring attempt to set acTL with num_frames > 2^31-1");
1166-+ return (0);
1167-+ }
1168-+ if (num_plays > PNG_UINT_31_MAX)
1169-+ {
1170-+ png_warning(png_ptr,
1171-+ "Ignoring attempt to set acTL with num_plays "
1172-+ "> 2^31-1");
1173-+ return (0);
1174-+ }
1175-+
1176-+ info_ptr->num_frames = num_frames;
1177-+ info_ptr->num_plays = num_plays;
1178-+
1179-+ info_ptr->valid |= PNG_INFO_acTL;
1180-+
1181-+ return (1);
1182-+}
1183-+
1184-+/* delay_num and delay_den can hold any 16-bit values including zero */
1185-+png_uint_32 PNGAPI
1186-+png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
1187-+ png_uint_32 width, png_uint_32 height,
1188-+ png_uint_32 x_offset, png_uint_32 y_offset,
1189-+ png_uint_16 delay_num, png_uint_16 delay_den,
1190-+ png_byte dispose_op, png_byte blend_op)
1191-+{
1192-+ png_debug1(1, "in %s storage function", "fcTL");
1193-+
1194-+ if (png_ptr == NULL || info_ptr == NULL)
1195-+ {
1196-+ png_warning(png_ptr,
1197-+ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
1198-+ "ignored");
1199-+ return (0);
1200-+ }
1201-+
1202-+ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1203-+ delay_num, delay_den, dispose_op, blend_op);
1204-+
1205-+ if (blend_op == PNG_BLEND_OP_OVER)
1206-+ {
1207-+ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
1208-+ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
1209-+ {
1210-+ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
1211-+ "and wasteful for opaque images, ignored");
1212-+ blend_op = PNG_BLEND_OP_SOURCE;
1213-+ }
1214-+ }
1215-+
1216-+ info_ptr->next_frame_width = width;
1217-+ info_ptr->next_frame_height = height;
1218-+ info_ptr->next_frame_x_offset = x_offset;
1219-+ info_ptr->next_frame_y_offset = y_offset;
1220-+ info_ptr->next_frame_delay_num = delay_num;
1221-+ info_ptr->next_frame_delay_den = delay_den;
1222-+ info_ptr->next_frame_dispose_op = dispose_op;
1223-+ info_ptr->next_frame_blend_op = blend_op;
1224-+
1225-+ info_ptr->valid |= PNG_INFO_fcTL;
1226-+
1227-+ return (1);
1228-+}
1229-+
1230-+void /* PRIVATE */
1231-+png_ensure_fcTL_is_valid(png_structp png_ptr,
1232-+ png_uint_32 width, png_uint_32 height,
1233-+ png_uint_32 x_offset, png_uint_32 y_offset,
1234-+ png_uint_16 delay_num, png_uint_16 delay_den,
1235-+ png_byte dispose_op, png_byte blend_op)
1236-+{
1237-+ if (width == 0 || width > PNG_UINT_31_MAX)
1238-+ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
1239-+ if (height == 0 || height > PNG_UINT_31_MAX)
1240-+ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
1241-+ if (x_offset > PNG_UINT_31_MAX)
1242-+ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
1243-+ if (y_offset > PNG_UINT_31_MAX)
1244-+ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
1245-+ if (width + x_offset > png_ptr->first_frame_width ||
1246-+ height + y_offset > png_ptr->first_frame_height)
1247-+ png_error(png_ptr, "dimensions of a frame are greater than"
1248-+ "the ones in IHDR");
1249-+
1250-+ if (dispose_op != PNG_DISPOSE_OP_NONE &&
1251-+ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
1252-+ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
1253-+ png_error(png_ptr, "invalid dispose_op in fcTL");
1254-+
1255-+ if (blend_op != PNG_BLEND_OP_SOURCE &&
1256-+ blend_op != PNG_BLEND_OP_OVER)
1257-+ png_error(png_ptr, "invalid blend_op in fcTL");
1258-+
1259-+ PNG_UNUSED(delay_num)
1260-+ PNG_UNUSED(delay_den)
1261-+}
1262-+
1263-+png_uint_32 PNGAPI
1264-+png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
1265-+ png_byte is_hidden)
1266-+{
1267-+ png_debug(1, "in png_first_frame_is_hidden()");
1268-+
1269-+ if (png_ptr == NULL)
1270-+ return 0;
1271-+
1272-+ if (is_hidden)
1273-+ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
1274-+ else
1275-+ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
1276-+
1277-+ PNG_UNUSED(info_ptr)
1278-+
1279-+ return 1;
1280-+}
1281-+#endif /* PNG_APNG_SUPPORTED */
1282-+
1283- #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1284- static png_byte
1285- check_location(png_const_structrp png_ptr, int location)
1286-diff --git a/pngstruct.h b/pngstruct.h
1287-index e591d94..1583dfc 100644
1288---- a/pngstruct.h
1289-+++ b/pngstruct.h
1290-@@ -399,6 +399,27 @@ struct png_struct_def
1291- png_byte filter_type;
1292- #endif
1293-
1294-+#ifdef PNG_APNG_SUPPORTED
1295-+ png_uint_32 apng_flags;
1296-+ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
1297-+ png_uint_32 first_frame_width;
1298-+ png_uint_32 first_frame_height;
1299-+
1300-+#ifdef PNG_READ_APNG_SUPPORTED
1301-+ png_uint_32 num_frames_read; /* incremented after all image data of */
1302-+ /* a frame is read */
1303-+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
1304-+ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
1305-+ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
1306-+#endif
1307-+#endif
1308-+
1309-+#ifdef PNG_WRITE_APNG_SUPPORTED
1310-+ png_uint_32 num_frames_to_write;
1311-+ png_uint_32 num_frames_written;
1312-+#endif
1313-+#endif /* PNG_APNG_SUPPORTED */
1314-+
1315- /* New members added in libpng-1.2.0 */
1316-
1317- /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
1318-diff --git a/pngtest.c b/pngtest.c
1319-index 37b42bb..6b0e676 100644
1320---- a/pngtest.c
1321-+++ b/pngtest.c
1322-@@ -875,6 +875,10 @@ test_one_file(const char *inname, const char *outname)
1323- volatile int num_passes;
1324- int pass;
1325- int bit_depth, color_type;
1326-+#ifdef PNG_APNG_SUPPORTED
1327-+ png_uint_32 num_frames;
1328-+ png_uint_32 num_plays;
1329-+#endif
1330-
1331- row_buf = NULL;
1332- error_parameters.file_name = inname;
1333-@@ -1383,6 +1387,22 @@ test_one_file(const char *inname, const char *outname)
1334- }
1335- }
1336- #endif
1337-+
1338-+#ifdef PNG_APNG_SUPPORTED
1339-+ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
1340-+ {
1341-+ if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
1342-+ {
1343-+ png_byte is_hidden;
1344-+ pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
1345-+ num_frames, num_plays);
1346-+ png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
1347-+ is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
1348-+ png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
1349-+ }
1350-+ }
1351-+#endif
1352-+
1353- #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1354- {
1355- png_unknown_chunkp unknowns;
1356-@@ -1462,6 +1482,110 @@ test_one_file(const char *inname, const char *outname)
1357- t_stop = (float)clock();
1358- t_misc += (t_stop - t_start);
1359- t_start = t_stop;
1360-+#endif
1361-+#ifdef PNG_APNG_SUPPORTED
1362-+ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
1363-+ {
1364-+ png_uint_32 frame;
1365-+ for (frame = 0; frame < num_frames; frame++)
1366-+ {
1367-+ png_uint_32 frame_width;
1368-+ png_uint_32 frame_height;
1369-+ png_uint_32 x_offset;
1370-+ png_uint_32 y_offset;
1371-+ png_uint_16 delay_num;
1372-+ png_uint_16 delay_den;
1373-+ png_byte dispose_op;
1374-+ png_byte blend_op;
1375-+ png_read_frame_head(read_ptr, read_info_ptr);
1376-+ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
1377-+ {
1378-+ png_get_next_frame_fcTL(read_ptr, read_info_ptr,
1379-+ &frame_width, &frame_height,
1380-+ &x_offset, &y_offset,
1381-+ &delay_num, &delay_den,
1382-+ &dispose_op, &blend_op);
1383-+ }
1384-+ else
1385-+ {
1386-+ frame_width = width;
1387-+ frame_height = height;
1388-+ x_offset = 0;
1389-+ y_offset = 0;
1390-+ delay_num = 1;
1391-+ delay_den = 1;
1392-+ dispose_op = PNG_DISPOSE_OP_NONE;
1393-+ blend_op = PNG_BLEND_OP_SOURCE;
1394-+ }
1395-+#ifdef PNG_WRITE_APNG_SUPPORTED
1396-+ png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
1397-+ frame_width, frame_height,
1398-+ x_offset, y_offset,
1399-+ delay_num, delay_den,
1400-+ dispose_op, blend_op);
1401-+#endif
1402-+ for (pass = 0; pass < num_passes; pass++)
1403-+ {
1404-+# ifdef calc_pass_height
1405-+ png_uint_32 pass_height;
1406-+
1407-+ if (num_passes == 7) /* interlaced */
1408-+ {
1409-+ if (PNG_PASS_COLS(frame_width, pass) > 0)
1410-+ pass_height = PNG_PASS_ROWS(frame_height, pass);
1411-+
1412-+ else
1413-+ pass_height = 0;
1414-+ }
1415-+
1416-+ else /* not interlaced */
1417-+ pass_height = frame_height;
1418-+# else
1419-+# define pass_height frame_height
1420-+# endif
1421-+
1422-+ pngtest_debug1("Writing row data for pass %d", pass);
1423-+ for (y = 0; y < pass_height; y++)
1424-+ {
1425-+#ifndef SINGLE_ROWBUF_ALLOC
1426-+ pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1427-+
1428-+ row_buf = (png_bytep)png_malloc(read_ptr,
1429-+ png_get_rowbytes(read_ptr, read_info_ptr));
1430-+
1431-+ pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
1432-+ (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1433-+
1434-+#endif /* !SINGLE_ROWBUF_ALLOC */
1435-+ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1436-+
1437-+#ifdef PNG_WRITE_SUPPORTED
1438-+#ifdef PNGTEST_TIMING
1439-+ t_stop = (float)clock();
1440-+ t_decode += (t_stop - t_start);
1441-+ t_start = t_stop;
1442-+#endif
1443-+ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1444-+#ifdef PNGTEST_TIMING
1445-+ t_stop = (float)clock();
1446-+ t_encode += (t_stop - t_start);
1447-+ t_start = t_stop;
1448-+#endif
1449-+#endif /* PNG_WRITE_SUPPORTED */
1450-+
1451-+#ifndef SINGLE_ROWBUF_ALLOC
1452-+ pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1453-+ png_free(read_ptr, row_buf);
1454-+ row_buf = NULL;
1455-+#endif /* !SINGLE_ROWBUF_ALLOC */
1456-+ }
1457-+ }
1458-+#ifdef PNG_WRITE_APNG_SUPPORTED
1459-+ png_write_frame_tail(write_ptr, write_info_ptr);
1460-+#endif
1461-+ }
1462-+ }
1463-+ else
1464- #endif
1465- for (pass = 0; pass < num_passes; pass++)
1466- {
1467-diff --git a/pngwrite.c b/pngwrite.c
1468-index 32f4bfb..6d2e021 100644
1469---- a/pngwrite.c
1470-+++ b/pngwrite.c
1471-@@ -128,6 +128,10 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
1472- * the application continues writing the PNG. So check the 'invalid'
1473- * flag here too.
1474- */
1475-+#ifdef PNG_WRITE_APNG_SUPPORTED
1476-+ if (info_ptr->valid & PNG_INFO_acTL)
1477-+ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
1478-+#endif
1479- #ifdef PNG_GAMMA_SUPPORTED
1480- # ifdef PNG_WRITE_gAMA_SUPPORTED
1481- if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
1482-@@ -373,6 +377,11 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
1483- png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
1484- #endif
1485-
1486-+#ifdef PNG_WRITE_APNG_SUPPORTED
1487-+ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
1488-+ png_error(png_ptr, "Not enough frames written");
1489-+#endif
1490-+
1491- /* See if user wants us to write information chunks */
1492- if (info_ptr != NULL)
1493- {
1494-@@ -1475,6 +1484,43 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
1495- }
1496- #endif
1497-
1498-+#ifdef PNG_WRITE_APNG_SUPPORTED
1499-+void PNGAPI
1500-+png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
1501-+ png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
1502-+ png_uint_32 x_offset, png_uint_32 y_offset,
1503-+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
1504-+ png_byte blend_op)
1505-+{
1506-+ png_debug(1, "in png_write_frame_head");
1507-+
1508-+ /* there is a chance this has been set after png_write_info was called,
1509-+ * so it would be set but not written. is there a way to be sure? */
1510-+ if (!(info_ptr->valid & PNG_INFO_acTL))
1511-+ png_error(png_ptr, "png_write_frame_head(): acTL not set");
1512-+
1513-+ png_write_reset(png_ptr);
1514-+
1515-+ png_write_reinit(png_ptr, info_ptr, width, height);
1516-+
1517-+ if ( !(png_ptr->num_frames_written == 0 &&
1518-+ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
1519-+ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
1520-+ delay_num, delay_den, dispose_op, blend_op);
1521-+
1522-+ PNG_UNUSED(row_pointers)
1523-+}
1524-+
1525-+void PNGAPI
1526-+png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
1527-+{
1528-+ png_debug(1, "in png_write_frame_tail");
1529-+
1530-+ png_ptr->num_frames_written++;
1531-+
1532-+ PNG_UNUSED(info_ptr)
1533-+}
1534-+#endif /* PNG_WRITE_APNG_SUPPORTED */
1535-
1536- #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
1537- /* Initialize the write structure - general purpose utility. */
1538-diff --git a/pngwutil.c b/pngwutil.c
1539-index 01f0607..8b374e2 100644
1540---- a/pngwutil.c
1541-+++ b/pngwutil.c
1542-@@ -821,6 +821,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
1543- /* Write the chunk */
1544- png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
1545-
1546-+#ifdef PNG_WRITE_APNG_SUPPORTED
1547-+ png_ptr->first_frame_width = width;
1548-+ png_ptr->first_frame_height = height;
1549-+#endif
1550-+
1551- if ((png_ptr->do_filter) == PNG_NO_FILTERS)
1552- {
1553- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1554-@@ -1002,8 +1007,17 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
1555- optimize_cmf(data, png_image_size(png_ptr));
1556- #endif
1557-
1558-- if (size > 0)
1559-- png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1560-+ if (size > 0)
1561-+#ifdef PNG_WRITE_APNG_SUPPORTED
1562-+ {
1563-+ if (png_ptr->num_frames_written == 0)
1564-+#endif
1565-+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1566-+#ifdef PNG_WRITE_APNG_SUPPORTED
1567-+ else
1568-+ png_write_fdAT(png_ptr, data, size);
1569-+ }
1570-+#endif /* PNG_WRITE_APNG_SUPPORTED */
1571- png_ptr->mode |= PNG_HAVE_IDAT;
1572-
1573- png_ptr->zstream.next_out = data;
1574-@@ -1050,7 +1064,17 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
1575- #endif
1576-
1577- if (size > 0)
1578-+#ifdef PNG_WRITE_APNG_SUPPORTED
1579-+ {
1580-+ if (png_ptr->num_frames_written == 0)
1581-+#endif
1582- png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1583-+#ifdef PNG_WRITE_APNG_SUPPORTED
1584-+ else
1585-+ png_write_fdAT(png_ptr, data, size);
1586-+ }
1587-+#endif /* PNG_WRITE_APNG_SUPPORTED */
1588-+
1589- png_ptr->zstream.avail_out = 0;
1590- png_ptr->zstream.next_out = NULL;
1591- png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
1592-@@ -1885,6 +1909,82 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
1593- }
1594- #endif
1595-
1596-+#ifdef PNG_WRITE_APNG_SUPPORTED
1597-+void /* PRIVATE */
1598-+png_write_acTL(png_structp png_ptr,
1599-+ png_uint_32 num_frames, png_uint_32 num_plays)
1600-+{
1601-+ png_byte buf[8];
1602-+
1603-+ png_debug(1, "in png_write_acTL");
1604-+
1605-+ png_ptr->num_frames_to_write = num_frames;
1606-+
1607-+ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
1608-+ num_frames--;
1609-+
1610-+ png_save_uint_32(buf, num_frames);
1611-+ png_save_uint_32(buf + 4, num_plays);
1612-+
1613-+ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
1614-+}
1615-+
1616-+void /* PRIVATE */
1617-+png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
1618-+ png_uint_32 x_offset, png_uint_32 y_offset,
1619-+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
1620-+ png_byte blend_op)
1621-+{
1622-+ png_byte buf[26];
1623-+
1624-+ png_debug(1, "in png_write_fcTL");
1625-+
1626-+ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
1627-+ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
1628-+ if (png_ptr->num_frames_written == 0 &&
1629-+ (width != png_ptr->first_frame_width ||
1630-+ height != png_ptr->first_frame_height))
1631-+ png_error(png_ptr, "width and/or height in the first frame's fcTL "
1632-+ "don't match the ones in IHDR");
1633-+
1634-+ /* more error checking */
1635-+ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1636-+ delay_num, delay_den, dispose_op, blend_op);
1637-+
1638-+ png_save_uint_32(buf, png_ptr->next_seq_num);
1639-+ png_save_uint_32(buf + 4, width);
1640-+ png_save_uint_32(buf + 8, height);
1641-+ png_save_uint_32(buf + 12, x_offset);
1642-+ png_save_uint_32(buf + 16, y_offset);
1643-+ png_save_uint_16(buf + 20, delay_num);
1644-+ png_save_uint_16(buf + 22, delay_den);
1645-+ buf[24] = dispose_op;
1646-+ buf[25] = blend_op;
1647-+
1648-+ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
1649-+
1650-+ png_ptr->next_seq_num++;
1651-+}
1652-+
1653-+void /* PRIVATE */
1654-+png_write_fdAT(png_structp png_ptr,
1655-+ png_const_bytep data, png_size_t length)
1656-+{
1657-+ png_byte buf[4];
1658-+
1659-+ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
1660-+
1661-+ png_save_uint_32(buf, png_ptr->next_seq_num);
1662-+ png_write_chunk_data(png_ptr, buf, 4);
1663-+
1664-+ png_write_chunk_data(png_ptr, data, length);
1665-+
1666-+ png_write_chunk_end(png_ptr);
1667-+
1668-+ png_ptr->next_seq_num++;
1669-+}
1670-+#endif /* PNG_WRITE_APNG_SUPPORTED */
1671-+
1672- /* Initializes the row writing capability of libpng */
1673- void /* PRIVATE */
1674- png_write_start_row(png_structrp png_ptr)
1675-@@ -2778,4 +2878,39 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
1676- }
1677- #endif /* WRITE_FLUSH */
1678- }
1679-+
1680-+#ifdef PNG_WRITE_APNG_SUPPORTED
1681-+void /* PRIVATE */
1682-+png_write_reset(png_structp png_ptr)
1683-+{
1684-+ png_ptr->row_number = 0;
1685-+ png_ptr->pass = 0;
1686-+ png_ptr->mode &= ~PNG_HAVE_IDAT;
1687-+}
1688-+
1689-+void /* PRIVATE */
1690-+png_write_reinit(png_structp png_ptr, png_infop info_ptr,
1691-+ png_uint_32 width, png_uint_32 height)
1692-+{
1693-+ if (png_ptr->num_frames_written == 0 &&
1694-+ (width != png_ptr->first_frame_width ||
1695-+ height != png_ptr->first_frame_height))
1696-+ png_error(png_ptr, "width and/or height in the first frame's fcTL "
1697-+ "don't match the ones in IHDR");
1698-+ if (width > png_ptr->first_frame_width ||
1699-+ height > png_ptr->first_frame_height)
1700-+ png_error(png_ptr, "width and/or height for a frame greater than"
1701-+ "the ones in IHDR");
1702-+
1703-+ png_set_IHDR(png_ptr, info_ptr, width, height,
1704-+ info_ptr->bit_depth, info_ptr->color_type,
1705-+ info_ptr->interlace_type, info_ptr->compression_type,
1706-+ info_ptr->filter_type);
1707-+
1708-+ png_ptr->width = width;
1709-+ png_ptr->height = height;
1710-+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
1711-+ png_ptr->usr_width = png_ptr->width;
1712-+}
1713-+#endif /* PNG_WRITE_APNG_SUPPORTED */
1714- #endif /* WRITE */
1715-diff --git a/scripts/symbols.def b/scripts/symbols.def
1716-index 82494bb..2d08674 100644
1717---- a/scripts/symbols.def
1718-+++ b/scripts/symbols.def
1719-@@ -253,3 +253,23 @@ EXPORTS
1720- png_set_eXIf @247
1721- png_get_eXIf_1 @248
1722- png_set_eXIf_1 @249
1723-+ png_get_acTL @250
1724-+ png_set_acTL @251
1725-+ png_get_num_frames @252
1726-+ png_get_num_plays @253
1727-+ png_get_next_frame_fcTL @254
1728-+ png_set_next_frame_fcTL @255
1729-+ png_get_next_frame_width @256
1730-+ png_get_next_frame_height @257
1731-+ png_get_next_frame_x_offset @258
1732-+ png_get_next_frame_y_offset @259
1733-+ png_get_next_frame_delay_num @260
1734-+ png_get_next_frame_delay_den @261
1735-+ png_get_next_frame_dispose_op @262
1736-+ png_get_next_frame_blend_op @263
1737-+ png_get_first_frame_is_hidden @264
1738-+ png_set_first_frame_is_hidden @265
1739-+ png_read_frame_head @266
1740-+ png_set_progressive_frame_fn @267
1741-+ png_write_frame_head @268
1742-+ png_write_frame_tail @269
+0,
-1
1@@ -1,2 +1 @@
2 https://github.com/glennrp/libpng/archive/v1.6.43.tar.gz
3-patches/apng.patch