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