wok-next diff libpng16/stuff/patches/libpng-1.6.28-apng.patch @ rev 20050

Up scite (4.0.1)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Mon Oct 23 13:19:31 2017 +0200 (2017-10-23)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libpng16/stuff/patches/libpng-1.6.28-apng.patch	Mon Oct 23 13:19:31 2017 +0200
     1.3 @@ -0,0 +1,1629 @@
     1.4 +Index: LICENSE
     1.5 +===================================================================
     1.6 +--- a/LICENSE
     1.7 ++++ b/LICENSE
     1.8 +@@ -8,6 +8,12 @@
     1.9 + If you modify libpng you may insert additional notices immediately following
    1.10 + this sentence.
    1.11 + 
    1.12 ++This modified version of libpng code adds animated PNG support and is
    1.13 ++released under the libpng license described below. The modifications are
    1.14 ++Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
    1.15 ++and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
    1.16 ++surrounding them in the modified libpng source files.
    1.17 ++
    1.18 + This code is released under the libpng license.
    1.19 + 
    1.20 + libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
    1.21 +Index: pngread.c
    1.22 +===================================================================
    1.23 +--- a/pngread.c
    1.24 ++++ b/pngread.c
    1.25 +@@ -161,6 +161,9 @@
    1.26 + 
    1.27 +       else if (chunk_name == png_IDAT)
    1.28 +       {
    1.29 ++#ifdef PNG_READ_APNG_SUPPORTED
    1.30 ++         png_have_info(png_ptr, info_ptr);
    1.31 ++#endif
    1.32 +          png_ptr->idat_size = length;
    1.33 +          break;
    1.34 +       }
    1.35 +@@ -250,6 +253,17 @@
    1.36 +          png_handle_iTXt(png_ptr, info_ptr, length);
    1.37 + #endif
    1.38 + 
    1.39 ++#ifdef PNG_READ_APNG_SUPPORTED
    1.40 ++      else if (chunk_name == png_acTL)
    1.41 ++         png_handle_acTL(png_ptr, info_ptr, length);
    1.42 ++
    1.43 ++      else if (chunk_name == png_fcTL)
    1.44 ++         png_handle_fcTL(png_ptr, info_ptr, length);
    1.45 ++
    1.46 ++      else if (chunk_name == png_fdAT)
    1.47 ++         png_handle_fdAT(png_ptr, info_ptr, length);
    1.48 ++#endif
    1.49 ++
    1.50 +       else
    1.51 +          png_handle_unknown(png_ptr, info_ptr, length,
    1.52 +              PNG_HANDLE_CHUNK_AS_DEFAULT);
    1.53 +@@ -257,6 +271,72 @@
    1.54 + }
    1.55 + #endif /* SEQUENTIAL_READ */
    1.56 + 
    1.57 ++#ifdef PNG_READ_APNG_SUPPORTED
    1.58 ++void PNGAPI
    1.59 ++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
    1.60 ++{
    1.61 ++    png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
    1.62 ++
    1.63 ++    png_debug(0, "Reading frame head");
    1.64 ++
    1.65 ++    if ((png_ptr->mode & PNG_HAVE_acTL) == 0)
    1.66 ++        png_error(png_ptr, "attempt to png_read_frame_head() but "
    1.67 ++                           "no acTL present");
    1.68 ++
    1.69 ++    /* do nothing for the main IDAT */
    1.70 ++    if (png_ptr->num_frames_read == 0)
    1.71 ++        return;
    1.72 ++
    1.73 ++    png_read_reset(png_ptr);
    1.74 ++    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
    1.75 ++    png_ptr->mode &= ~PNG_HAVE_fcTL;
    1.76 ++
    1.77 ++    have_chunk_after_DAT = 0;
    1.78 ++    for (;;)
    1.79 ++    {
    1.80 ++        png_uint_32 length = png_read_chunk_header(png_ptr);
    1.81 ++
    1.82 ++        if (png_ptr->chunk_name == png_IDAT)
    1.83 ++        {
    1.84 ++            /* discard trailing IDATs for the first frame */
    1.85 ++            if (have_chunk_after_DAT != 0 || png_ptr->num_frames_read > 1)
    1.86 ++                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
    1.87 ++            png_crc_finish(png_ptr, length);
    1.88 ++        }
    1.89 ++
    1.90 ++        else if (png_ptr->chunk_name == png_fcTL)
    1.91 ++        {
    1.92 ++            png_handle_fcTL(png_ptr, info_ptr, length);
    1.93 ++            have_chunk_after_DAT = 1;
    1.94 ++        }
    1.95 ++
    1.96 ++        else if (png_ptr->chunk_name == png_fdAT)
    1.97 ++        {
    1.98 ++            png_ensure_sequence_number(png_ptr, length);
    1.99 ++
   1.100 ++            /* discard trailing fdATs for frames other than the first */
   1.101 ++            if (have_chunk_after_DAT == 0 && png_ptr->num_frames_read > 1)
   1.102 ++                png_crc_finish(png_ptr, length - 4);
   1.103 ++            else if (png_ptr->mode & PNG_HAVE_fcTL)
   1.104 ++            {
   1.105 ++                png_ptr->idat_size = length - 4;
   1.106 ++                png_ptr->mode |= PNG_HAVE_IDAT;
   1.107 ++
   1.108 ++                break;
   1.109 ++            }
   1.110 ++            else
   1.111 ++                png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
   1.112 ++        }
   1.113 ++        else
   1.114 ++        {
   1.115 ++            png_warning(png_ptr, "Skipped (ignored) a chunk "
   1.116 ++                                 "between APNG chunks");
   1.117 ++            png_crc_finish(png_ptr, length);
   1.118 ++        }
   1.119 ++    }
   1.120 ++}
   1.121 ++#endif /* READ_APNG */
   1.122 ++
   1.123 + /* Optional call to update the users info_ptr structure */
   1.124 + void PNGAPI
   1.125 + png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
   1.126 +Index: pngget.c
   1.127 +===================================================================
   1.128 +--- a/pngget.c
   1.129 ++++ b/pngget.c
   1.130 +@@ -1216,4 +1216,166 @@
   1.131 + #  endif
   1.132 + #endif
   1.133 + 
   1.134 ++#ifdef PNG_APNG_SUPPORTED
   1.135 ++png_uint_32 PNGAPI
   1.136 ++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
   1.137 ++             png_uint_32 *num_frames, png_uint_32 *num_plays)
   1.138 ++{
   1.139 ++    png_debug1(1, "in %s retrieval function", "acTL");
   1.140 ++
   1.141 ++    if (png_ptr != NULL && info_ptr != NULL &&
   1.142 ++        (info_ptr->valid & PNG_INFO_acTL) != 0 &&
   1.143 ++        num_frames != NULL && num_plays != NULL)
   1.144 ++    {
   1.145 ++        *num_frames = info_ptr->num_frames;
   1.146 ++        *num_plays = info_ptr->num_plays;
   1.147 ++        return (1);
   1.148 ++    }
   1.149 ++
   1.150 ++    return (0);
   1.151 ++}
   1.152 ++
   1.153 ++png_uint_32 PNGAPI
   1.154 ++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
   1.155 ++{
   1.156 ++    png_debug(1, "in png_get_num_frames()");
   1.157 ++
   1.158 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.159 ++        return (info_ptr->num_frames);
   1.160 ++    return (0);
   1.161 ++}
   1.162 ++
   1.163 ++png_uint_32 PNGAPI
   1.164 ++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
   1.165 ++{
   1.166 ++    png_debug(1, "in png_get_num_plays()");
   1.167 ++
   1.168 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.169 ++        return (info_ptr->num_plays);
   1.170 ++    return (0);
   1.171 ++}
   1.172 ++
   1.173 ++png_uint_32 PNGAPI
   1.174 ++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
   1.175 ++             png_uint_32 *width, png_uint_32 *height,
   1.176 ++             png_uint_32 *x_offset, png_uint_32 *y_offset,
   1.177 ++             png_uint_16 *delay_num, png_uint_16 *delay_den,
   1.178 ++             png_byte *dispose_op, png_byte *blend_op)
   1.179 ++{
   1.180 ++    png_debug1(1, "in %s retrieval function", "fcTL");
   1.181 ++
   1.182 ++    if (png_ptr != NULL && info_ptr != NULL &&
   1.183 ++        (info_ptr->valid & PNG_INFO_fcTL) != 0 &&
   1.184 ++        width != NULL && height != NULL &&
   1.185 ++        x_offset != NULL && y_offset != NULL &&
   1.186 ++        delay_num != NULL && delay_den != NULL &&
   1.187 ++        dispose_op != NULL && blend_op != NULL)
   1.188 ++    {
   1.189 ++        *width = info_ptr->next_frame_width;
   1.190 ++        *height = info_ptr->next_frame_height;
   1.191 ++        *x_offset = info_ptr->next_frame_x_offset;
   1.192 ++        *y_offset = info_ptr->next_frame_y_offset;
   1.193 ++        *delay_num = info_ptr->next_frame_delay_num;
   1.194 ++        *delay_den = info_ptr->next_frame_delay_den;
   1.195 ++        *dispose_op = info_ptr->next_frame_dispose_op;
   1.196 ++        *blend_op = info_ptr->next_frame_blend_op;
   1.197 ++        return (1);
   1.198 ++    }
   1.199 ++
   1.200 ++    return (0);
   1.201 ++}
   1.202 ++
   1.203 ++png_uint_32 PNGAPI
   1.204 ++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
   1.205 ++{
   1.206 ++    png_debug(1, "in png_get_next_frame_width()");
   1.207 ++
   1.208 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.209 ++        return (info_ptr->next_frame_width);
   1.210 ++    return (0);
   1.211 ++}
   1.212 ++
   1.213 ++png_uint_32 PNGAPI
   1.214 ++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
   1.215 ++{
   1.216 ++    png_debug(1, "in png_get_next_frame_height()");
   1.217 ++
   1.218 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.219 ++        return (info_ptr->next_frame_height);
   1.220 ++    return (0);
   1.221 ++}
   1.222 ++
   1.223 ++png_uint_32 PNGAPI
   1.224 ++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
   1.225 ++{
   1.226 ++    png_debug(1, "in png_get_next_frame_x_offset()");
   1.227 ++
   1.228 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.229 ++        return (info_ptr->next_frame_x_offset);
   1.230 ++    return (0);
   1.231 ++}
   1.232 ++
   1.233 ++png_uint_32 PNGAPI
   1.234 ++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
   1.235 ++{
   1.236 ++    png_debug(1, "in png_get_next_frame_y_offset()");
   1.237 ++
   1.238 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.239 ++        return (info_ptr->next_frame_y_offset);
   1.240 ++    return (0);
   1.241 ++}
   1.242 ++
   1.243 ++png_uint_16 PNGAPI
   1.244 ++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
   1.245 ++{
   1.246 ++    png_debug(1, "in png_get_next_frame_delay_num()");
   1.247 ++
   1.248 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.249 ++        return (info_ptr->next_frame_delay_num);
   1.250 ++    return (0);
   1.251 ++}
   1.252 ++
   1.253 ++png_uint_16 PNGAPI
   1.254 ++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
   1.255 ++{
   1.256 ++    png_debug(1, "in png_get_next_frame_delay_den()");
   1.257 ++
   1.258 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.259 ++        return (info_ptr->next_frame_delay_den);
   1.260 ++    return (0);
   1.261 ++}
   1.262 ++
   1.263 ++png_byte PNGAPI
   1.264 ++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
   1.265 ++{
   1.266 ++    png_debug(1, "in png_get_next_frame_dispose_op()");
   1.267 ++
   1.268 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.269 ++        return (info_ptr->next_frame_dispose_op);
   1.270 ++    return (0);
   1.271 ++}
   1.272 ++
   1.273 ++png_byte PNGAPI
   1.274 ++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
   1.275 ++{
   1.276 ++    png_debug(1, "in png_get_next_frame_blend_op()");
   1.277 ++
   1.278 ++    if (png_ptr != NULL && info_ptr != NULL)
   1.279 ++        return (info_ptr->next_frame_blend_op);
   1.280 ++    return (0);
   1.281 ++}
   1.282 ++
   1.283 ++png_byte PNGAPI
   1.284 ++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
   1.285 ++{
   1.286 ++    png_debug(1, "in png_first_frame_is_hidden()");
   1.287 ++
   1.288 ++    if (png_ptr != NULL)
   1.289 ++       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
   1.290 ++
   1.291 ++    PNG_UNUSED(info_ptr)
   1.292 ++
   1.293 ++    return 0;
   1.294 ++}
   1.295 ++#endif /* APNG */
   1.296 + #endif /* READ || WRITE */
   1.297 +Index: png.c
   1.298 +===================================================================
   1.299 +--- a/png.c
   1.300 ++++ b/png.c
   1.301 +@@ -776,17 +776,21 @@
   1.302 + #else
   1.303 + #  ifdef __STDC__
   1.304 +    return PNG_STRING_NEWLINE \
   1.305 +-      "libpng version 1.6.28 - January 5, 2017" PNG_STRING_NEWLINE \
   1.306 ++      "libpng version 1.6.28+apng - January 5, 2017" PNG_STRING_NEWLINE \
   1.307 +       "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
   1.308 +       PNG_STRING_NEWLINE \
   1.309 +       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
   1.310 +       "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
   1.311 +-      PNG_STRING_NEWLINE;
   1.312 ++      PNG_STRING_NEWLINE \
   1.313 ++      "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
   1.314 ++      "Portions Copyright (c) 2008-2017 Max Stepin" PNG_STRING_NEWLINE ;
   1.315 + #  else
   1.316 +-   return "libpng version 1.6.28 - January 5, 2017\
   1.317 ++   return "libpng version 1.6.28+apng - January 5, 2017\
   1.318 +       Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
   1.319 +       Copyright (c) 1996-1997 Andreas Dilger\
   1.320 +-      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
   1.321 ++      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
   1.322 ++      Portions Copyright (c) 2006-2007 Andrew Smith\
   1.323 ++      Portions Copyright (c) 2008-2017 Max Stepin";
   1.324 + #  endif
   1.325 + #endif
   1.326 + }
   1.327 +Index: png.h
   1.328 +===================================================================
   1.329 +--- a/png.h
   1.330 ++++ b/png.h
   1.331 +@@ -23,6 +23,12 @@
   1.332 +  * If you modify libpng you may insert additional notices immediately following
   1.333 +  * this sentence.
   1.334 +  *
   1.335 ++ * This modified version of libpng code adds animated PNG support and is
   1.336 ++ * released under the libpng license described below. The modifications are
   1.337 ++ * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
   1.338 ++ * and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
   1.339 ++ * surrounding them in the modified libpng source files.
   1.340 ++ *
   1.341 +  * This code is released under the libpng license.
   1.342 +  *
   1.343 +  * libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
   1.344 +@@ -307,8 +313,9 @@
   1.345 +  */
   1.346 + 
   1.347 + /* Version information for png.h - this should match the version in png.c */
   1.348 +-#define PNG_LIBPNG_VER_STRING "1.6.28"
   1.349 +-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.28 - January 5, 2017\n"
   1.350 ++#define PNG_LIBPNG_VER_STRING "1.6.28+apng"
   1.351 ++#define PNG_HEADER_VERSION_STRING \
   1.352 ++     " libpng version 1.6.28+apng - January 5, 2017\n"
   1.353 + 
   1.354 + #define PNG_LIBPNG_VER_SONUM   16
   1.355 + #define PNG_LIBPNG_VER_DLLNUM  16
   1.356 +@@ -359,6 +366,10 @@
   1.357 + #   include "pnglibconf.h"
   1.358 + #endif
   1.359 + 
   1.360 ++#define PNG_APNG_SUPPORTED
   1.361 ++#define PNG_READ_APNG_SUPPORTED
   1.362 ++#define PNG_WRITE_APNG_SUPPORTED
   1.363 ++
   1.364 + #ifndef PNG_VERSION_INFO_ONLY
   1.365 + /* Machine specific configuration. */
   1.366 + #  include "pngconf.h"
   1.367 +@@ -454,6 +465,17 @@
   1.368 +  * See pngconf.h for base types that vary by machine/system
   1.369 +  */
   1.370 + 
   1.371 ++#ifdef PNG_APNG_SUPPORTED
   1.372 ++/* dispose_op flags from inside fcTL */
   1.373 ++#define PNG_DISPOSE_OP_NONE        0x00
   1.374 ++#define PNG_DISPOSE_OP_BACKGROUND  0x01
   1.375 ++#define PNG_DISPOSE_OP_PREVIOUS    0x02
   1.376 ++
   1.377 ++/* blend_op flags from inside fcTL */
   1.378 ++#define PNG_BLEND_OP_SOURCE        0x00
   1.379 ++#define PNG_BLEND_OP_OVER          0x01
   1.380 ++#endif /* APNG */
   1.381 ++
   1.382 + /* This triggers a compiler error in png.c, if png.c and png.h
   1.383 +  * do not agree upon the version number.
   1.384 +  */
   1.385 +@@ -774,6 +796,10 @@
   1.386 + #define PNG_INFO_sPLT 0x2000U  /* ESR, 1.0.6 */
   1.387 + #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
   1.388 + #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
   1.389 ++#ifdef PNG_APNG_SUPPORTED
   1.390 ++#define PNG_INFO_acTL 0x10000U
   1.391 ++#define PNG_INFO_fcTL 0x20000U
   1.392 ++#endif
   1.393 + 
   1.394 + /* This is used for the transformation routines, as some of them
   1.395 +  * change these values for the row.  It also should enable using
   1.396 +@@ -811,6 +837,10 @@
   1.397 + #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   1.398 + typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
   1.399 + typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
   1.400 ++#ifdef PNG_APNG_SUPPORTED
   1.401 ++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
   1.402 ++    png_uint_32));
   1.403 ++#endif
   1.404 + 
   1.405 + /* The following callback receives png_uint_32 row_number, int pass for the
   1.406 +  * png_bytep data of the row.  When transforming an interlaced image the
   1.407 +@@ -3240,6 +3270,75 @@
   1.408 +  *  END OF HARDWARE AND SOFTWARE OPTIONS
   1.409 +  ******************************************************************************/
   1.410 + 
   1.411 ++#ifdef PNG_APNG_SUPPORTED
   1.412 ++PNG_EXPORT(246, png_uint_32, png_get_acTL, (png_structp png_ptr,
   1.413 ++   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
   1.414 ++
   1.415 ++PNG_EXPORT(247, png_uint_32, png_set_acTL, (png_structp png_ptr,
   1.416 ++   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
   1.417 ++
   1.418 ++PNG_EXPORT(248, png_uint_32, png_get_num_frames, (png_structp png_ptr,
   1.419 ++   png_infop info_ptr));
   1.420 ++
   1.421 ++PNG_EXPORT(249, png_uint_32, png_get_num_plays, (png_structp png_ptr,
   1.422 ++   png_infop info_ptr));
   1.423 ++
   1.424 ++PNG_EXPORT(250, png_uint_32, png_get_next_frame_fcTL,
   1.425 ++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
   1.426 ++   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
   1.427 ++   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
   1.428 ++   png_byte *blend_op));
   1.429 ++
   1.430 ++PNG_EXPORT(251, png_uint_32, png_set_next_frame_fcTL,
   1.431 ++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
   1.432 ++   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
   1.433 ++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
   1.434 ++   png_byte blend_op));
   1.435 ++
   1.436 ++PNG_EXPORT(252, png_uint_32, png_get_next_frame_width,
   1.437 ++   (png_structp png_ptr, png_infop info_ptr));
   1.438 ++PNG_EXPORT(253, png_uint_32, png_get_next_frame_height,
   1.439 ++   (png_structp png_ptr, png_infop info_ptr));
   1.440 ++PNG_EXPORT(254, png_uint_32, png_get_next_frame_x_offset,
   1.441 ++   (png_structp png_ptr, png_infop info_ptr));
   1.442 ++PNG_EXPORT(255, png_uint_32, png_get_next_frame_y_offset,
   1.443 ++   (png_structp png_ptr, png_infop info_ptr));
   1.444 ++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_num,
   1.445 ++   (png_structp png_ptr, png_infop info_ptr));
   1.446 ++PNG_EXPORT(257, png_uint_16, png_get_next_frame_delay_den,
   1.447 ++   (png_structp png_ptr, png_infop info_ptr));
   1.448 ++PNG_EXPORT(258, png_byte, png_get_next_frame_dispose_op,
   1.449 ++   (png_structp png_ptr, png_infop info_ptr));
   1.450 ++PNG_EXPORT(259, png_byte, png_get_next_frame_blend_op,
   1.451 ++   (png_structp png_ptr, png_infop info_ptr));
   1.452 ++PNG_EXPORT(260, png_byte, png_get_first_frame_is_hidden,
   1.453 ++   (png_structp png_ptr, png_infop info_ptr));
   1.454 ++PNG_EXPORT(261, png_uint_32, png_set_first_frame_is_hidden,
   1.455 ++   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
   1.456 ++
   1.457 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.458 ++PNG_EXPORT(262, void, png_read_frame_head, (png_structp png_ptr,
   1.459 ++   png_infop info_ptr));
   1.460 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   1.461 ++PNG_EXPORT(263, void, png_set_progressive_frame_fn, (png_structp png_ptr,
   1.462 ++   png_progressive_frame_ptr frame_info_fn,
   1.463 ++   png_progressive_frame_ptr frame_end_fn));
   1.464 ++#endif /* PROGRESSIVE_READ */
   1.465 ++#endif /* READ_APNG */
   1.466 ++
   1.467 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.468 ++PNG_EXPORT(264, void, png_write_frame_head, (png_structp png_ptr,
   1.469 ++   png_infop info_ptr, png_bytepp row_pointers,
   1.470 ++   png_uint_32 width, png_uint_32 height,
   1.471 ++   png_uint_32 x_offset, png_uint_32 y_offset,
   1.472 ++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
   1.473 ++   png_byte blend_op));
   1.474 ++
   1.475 ++PNG_EXPORT(265, void, png_write_frame_tail, (png_structp png_ptr,
   1.476 ++   png_infop info_ptr));
   1.477 ++#endif /* WRITE_APNG */
   1.478 ++#endif /* APNG */
   1.479 ++
   1.480 + /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
   1.481 +  * defs, and in scripts/symbols.def.
   1.482 +  */
   1.483 +@@ -3248,7 +3347,11 @@
   1.484 +  * one to use is one more than this.)
   1.485 +  */
   1.486 + #ifdef PNG_EXPORT_LAST_ORDINAL
   1.487 ++#ifdef PNG_APNG_SUPPORTED
   1.488 ++  PNG_EXPORT_LAST_ORDINAL(265);
   1.489 ++#else
   1.490 +   PNG_EXPORT_LAST_ORDINAL(245);
   1.491 ++#endif /* APNG */
   1.492 + #endif
   1.493 + 
   1.494 + #ifdef __cplusplus
   1.495 +Index: pngpriv.h
   1.496 +===================================================================
   1.497 +--- a/pngpriv.h
   1.498 ++++ b/pngpriv.h
   1.499 +@@ -567,6 +567,10 @@
   1.500 + #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
   1.501 +                    /*             0x4000U (unused) */
   1.502 + #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
   1.503 ++#ifdef PNG_APNG_SUPPORTED
   1.504 ++#define PNG_HAVE_acTL            0x10000U
   1.505 ++#define PNG_HAVE_fcTL            0x20000U
   1.506 ++#endif
   1.507 + 
   1.508 + /* Flags for the transformations the PNG library does on the image data */
   1.509 + #define PNG_BGR                 0x0001U
   1.510 +@@ -802,6 +806,16 @@
   1.511 + #define png_tRNS PNG_U32(116,  82,  78,  83)
   1.512 + #define png_zTXt PNG_U32(122,  84,  88, 116)
   1.513 + 
   1.514 ++#ifdef PNG_APNG_SUPPORTED
   1.515 ++#define png_acTL PNG_U32( 97,  99,  84,  76)
   1.516 ++#define png_fcTL PNG_U32(102,  99,  84,  76)
   1.517 ++#define png_fdAT PNG_U32(102, 100,  65,  84)
   1.518 ++
   1.519 ++/* For png_struct.apng_flags: */
   1.520 ++#define PNG_FIRST_FRAME_HIDDEN       0x0001U
   1.521 ++#define PNG_APNG_APP                 0x0002U
   1.522 ++#endif
   1.523 ++
   1.524 + /* The following will work on (signed char*) strings, whereas the get_uint_32
   1.525 +  * macro will fail on top-bit-set values because of the sign extension.
   1.526 +  */
   1.527 +@@ -1508,6 +1522,49 @@
   1.528 + 
   1.529 + #endif /* PROGRESSIVE_READ */
   1.530 + 
   1.531 ++#ifdef PNG_APNG_SUPPORTED
   1.532 ++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
   1.533 ++   png_uint_32 width, png_uint_32 height,
   1.534 ++   png_uint_32 x_offset, png_uint_32 y_offset,
   1.535 ++   png_uint_16 delay_num, png_uint_16 delay_den,
   1.536 ++   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
   1.537 ++
   1.538 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.539 ++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr,
   1.540 ++   png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
   1.541 ++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr,
   1.542 ++   png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
   1.543 ++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr,
   1.544 ++   png_infop info_ptr, png_uint_32 length),PNG_EMPTY);
   1.545 ++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr,
   1.546 ++   png_infop info_ptr),PNG_EMPTY);
   1.547 ++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
   1.548 ++   png_uint_32 length),PNG_EMPTY);
   1.549 ++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
   1.550 ++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
   1.551 ++   png_infop info_ptr),PNG_EMPTY);
   1.552 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   1.553 ++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),
   1.554 ++   PNG_EMPTY);
   1.555 ++#endif /* PROGRESSIVE_READ */
   1.556 ++#endif /* READ_APNG */
   1.557 ++
   1.558 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.559 ++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
   1.560 ++   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
   1.561 ++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
   1.562 ++   png_uint_32 width, png_uint_32 height,
   1.563 ++   png_uint_32 x_offset, png_uint_32 y_offset,
   1.564 ++   png_uint_16 delay_num, png_uint_16 delay_den,
   1.565 ++   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
   1.566 ++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
   1.567 ++   png_const_bytep data, png_size_t length),PNG_EMPTY);
   1.568 ++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
   1.569 ++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
   1.570 ++   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
   1.571 ++#endif /* WRITE_APNG */
   1.572 ++#endif /* APNG */
   1.573 ++
   1.574 + /* Added at libpng version 1.6.0 */
   1.575 + #ifdef PNG_GAMMA_SUPPORTED
   1.576 + PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,
   1.577 +Index: pnginfo.h
   1.578 +===================================================================
   1.579 +--- a/pnginfo.h
   1.580 ++++ b/pnginfo.h
   1.581 +@@ -255,5 +255,18 @@
   1.582 +    png_bytepp row_pointers;        /* the image bits */
   1.583 + #endif
   1.584 + 
   1.585 ++#ifdef PNG_APNG_SUPPORTED
   1.586 ++   png_uint_32 num_frames; /* including default image */
   1.587 ++   png_uint_32 num_plays;
   1.588 ++   png_uint_32 next_frame_width;
   1.589 ++   png_uint_32 next_frame_height;
   1.590 ++   png_uint_32 next_frame_x_offset;
   1.591 ++   png_uint_32 next_frame_y_offset;
   1.592 ++   png_uint_16 next_frame_delay_num;
   1.593 ++   png_uint_16 next_frame_delay_den;
   1.594 ++   png_byte next_frame_dispose_op;
   1.595 ++   png_byte next_frame_blend_op;
   1.596 ++#endif
   1.597 ++
   1.598 + };
   1.599 + #endif /* PNGINFO_H */
   1.600 +Index: pngstruct.h
   1.601 +===================================================================
   1.602 +--- a/pngstruct.h
   1.603 ++++ b/pngstruct.h
   1.604 +@@ -403,6 +403,27 @@
   1.605 +    png_byte filter_type;
   1.606 + #endif
   1.607 + 
   1.608 ++#ifdef PNG_APNG_SUPPORTED
   1.609 ++   png_uint_32 apng_flags;
   1.610 ++   png_uint_32 next_seq_num;         /* next fcTL/fdAT chunk sequence number */
   1.611 ++   png_uint_32 first_frame_width;
   1.612 ++   png_uint_32 first_frame_height;
   1.613 ++
   1.614 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.615 ++   png_uint_32 num_frames_read;      /* incremented after all image data of */
   1.616 ++                                     /* a frame is read */
   1.617 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   1.618 ++   png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
   1.619 ++   png_progressive_frame_ptr frame_end_fn;  /* frame data read callback */
   1.620 ++#endif
   1.621 ++#endif
   1.622 ++
   1.623 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.624 ++   png_uint_32 num_frames_to_write;
   1.625 ++   png_uint_32 num_frames_written;
   1.626 ++#endif
   1.627 ++#endif /* APNG */
   1.628 ++
   1.629 + /* New members added in libpng-1.2.0 */
   1.630 + 
   1.631 + /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
   1.632 +Index: pngwrite.c
   1.633 +===================================================================
   1.634 +--- a/pngwrite.c
   1.635 ++++ b/pngwrite.c
   1.636 +@@ -128,6 +128,10 @@
   1.637 +        * the application continues writing the PNG.  So check the 'invalid'
   1.638 +        * flag here too.
   1.639 +        */
   1.640 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.641 ++   if ((info_ptr->valid & PNG_INFO_acTL) != 0)
   1.642 ++      png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
   1.643 ++#endif
   1.644 + #ifdef PNG_GAMMA_SUPPORTED
   1.645 + #  ifdef PNG_WRITE_gAMA_SUPPORTED
   1.646 +       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
   1.647 +@@ -360,6 +364,11 @@
   1.648 +    if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
   1.649 +       png_error(png_ptr, "No IDATs written into file");
   1.650 + 
   1.651 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.652 ++   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
   1.653 ++      png_error(png_ptr, "Not enough frames written");
   1.654 ++#endif
   1.655 ++
   1.656 + #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
   1.657 +    if (png_ptr->num_palette_max > png_ptr->num_palette)
   1.658 +       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
   1.659 +@@ -2382,4 +2391,42 @@
   1.660 + }
   1.661 + #endif /* SIMPLIFIED_WRITE_STDIO */
   1.662 + #endif /* SIMPLIFIED_WRITE */
   1.663 ++
   1.664 ++#ifdef PNG_WRITE_APNG_SUPPORTED
   1.665 ++void PNGAPI
   1.666 ++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
   1.667 ++    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
   1.668 ++    png_uint_32 x_offset, png_uint_32 y_offset,
   1.669 ++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
   1.670 ++    png_byte blend_op)
   1.671 ++{
   1.672 ++    png_debug(1, "in png_write_frame_head");
   1.673 ++
   1.674 ++    /* there is a chance this has been set after png_write_info was called,
   1.675 ++    * so it would be set but not written. is there a way to be sure? */
   1.676 ++    if ((info_ptr->valid & PNG_INFO_acTL) == 0)
   1.677 ++        png_error(png_ptr, "png_write_frame_head(): acTL not set");
   1.678 ++
   1.679 ++    png_write_reset(png_ptr);
   1.680 ++
   1.681 ++    png_write_reinit(png_ptr, info_ptr, width, height);
   1.682 ++
   1.683 ++    if ((png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) == 0 ||
   1.684 ++        png_ptr->num_frames_written != 0)
   1.685 ++        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
   1.686 ++                       delay_num, delay_den, dispose_op, blend_op);
   1.687 ++
   1.688 ++    PNG_UNUSED(row_pointers)
   1.689 ++}
   1.690 ++
   1.691 ++void PNGAPI
   1.692 ++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
   1.693 ++{
   1.694 ++    png_debug(1, "in png_write_frame_tail");
   1.695 ++
   1.696 ++    png_ptr->num_frames_written++;
   1.697 ++
   1.698 ++    PNG_UNUSED(info_ptr)
   1.699 ++}
   1.700 ++#endif /* WRITE_APNG */
   1.701 + #endif /* WRITE */
   1.702 +Index: pngpread.c
   1.703 +===================================================================
   1.704 +--- a/pngpread.c
   1.705 ++++ b/pngpread.c
   1.706 +@@ -194,6 +194,89 @@
   1.707 + 
   1.708 +    chunk_name = png_ptr->chunk_name;
   1.709 + 
   1.710 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.711 ++   if (png_ptr->num_frames_read > 0 &&
   1.712 ++       png_ptr->num_frames_read < info_ptr->num_frames)
   1.713 ++   {
   1.714 ++      if (chunk_name == png_IDAT)
   1.715 ++      {
   1.716 ++         /* Discard trailing IDATs for the first frame */
   1.717 ++         if ((png_ptr->mode & PNG_HAVE_fcTL) != 0 ||
   1.718 ++             png_ptr->num_frames_read > 1)
   1.719 ++            png_error(png_ptr, "out of place IDAT");
   1.720 ++
   1.721 ++         PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.722 ++         png_crc_finish(png_ptr, png_ptr->push_length);
   1.723 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
   1.724 ++      }
   1.725 ++
   1.726 ++      else if (chunk_name == png_fdAT)
   1.727 ++      {
   1.728 ++         PNG_PUSH_SAVE_BUFFER_IF_LT(4)
   1.729 ++         png_ensure_sequence_number(png_ptr, 4);
   1.730 ++
   1.731 ++         if ((png_ptr->mode & PNG_HAVE_fcTL) == 0)
   1.732 ++         {
   1.733 ++            /* Discard trailing fdATs for frames other than the first */
   1.734 ++            if (png_ptr->num_frames_read < 2)
   1.735 ++               png_error(png_ptr, "out of place fdAT");
   1.736 ++
   1.737 ++            PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.738 ++            png_crc_finish(png_ptr, png_ptr->push_length);
   1.739 ++            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
   1.740 ++         }
   1.741 ++
   1.742 ++         else
   1.743 ++         {
   1.744 ++            /* frame data follows */
   1.745 ++            png_ptr->idat_size = png_ptr->push_length - 4;
   1.746 ++            png_ptr->mode |= PNG_HAVE_IDAT;
   1.747 ++            png_ptr->process_mode = PNG_READ_IDAT_MODE;
   1.748 ++         }
   1.749 ++      }
   1.750 ++
   1.751 ++      else if (chunk_name == png_fcTL)
   1.752 ++      {
   1.753 ++         PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.754 ++         png_read_reset(png_ptr);
   1.755 ++         png_ptr->mode &= ~PNG_HAVE_fcTL;
   1.756 ++
   1.757 ++         png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
   1.758 ++
   1.759 ++         if ((png_ptr->mode & PNG_HAVE_fcTL) == 0)
   1.760 ++            png_error(png_ptr, "missing required fcTL chunk");
   1.761 ++
   1.762 ++         png_read_reinit(png_ptr, info_ptr);
   1.763 ++         png_progressive_read_reset(png_ptr);
   1.764 ++
   1.765 ++         if (png_ptr->frame_info_fn != NULL)
   1.766 ++            (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
   1.767 ++
   1.768 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
   1.769 ++      }
   1.770 ++
   1.771 ++      else if (chunk_name == png_IEND)
   1.772 ++      {
   1.773 ++         PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.774 ++         png_warning(png_ptr, "Number of actual frames fewer than expected");
   1.775 ++         png_crc_finish(png_ptr, png_ptr->push_length);
   1.776 ++         png_ptr->process_mode = PNG_READ_DONE_MODE;
   1.777 ++         png_push_have_end(png_ptr, info_ptr);
   1.778 ++      }
   1.779 ++
   1.780 ++      else
   1.781 ++      {
   1.782 ++         PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.783 ++         png_warning(png_ptr, "Skipped (ignored) a chunk "
   1.784 ++                              "between APNG chunks");
   1.785 ++         png_crc_finish(png_ptr, png_ptr->push_length);
   1.786 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
   1.787 ++      }
   1.788 ++
   1.789 ++      return;
   1.790 ++   }
   1.791 ++#endif /* READ_APNG */
   1.792 ++
   1.793 +    if (chunk_name == png_IDAT)
   1.794 +    {
   1.795 +       if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
   1.796 +@@ -260,6 +343,9 @@
   1.797 + 
   1.798 +    else if (chunk_name == png_IDAT)
   1.799 +    {
   1.800 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.801 ++      png_have_info(png_ptr, info_ptr);
   1.802 ++#endif
   1.803 +       png_ptr->idat_size = png_ptr->push_length;
   1.804 +       png_ptr->process_mode = PNG_READ_IDAT_MODE;
   1.805 +       png_push_have_info(png_ptr, info_ptr);
   1.806 +@@ -406,6 +492,20 @@
   1.807 +    }
   1.808 + #endif
   1.809 + 
   1.810 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.811 ++   else if (chunk_name == png_acTL)
   1.812 ++   {
   1.813 ++      PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.814 ++      png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
   1.815 ++   }
   1.816 ++
   1.817 ++   else if (chunk_name == png_fcTL)
   1.818 ++   {
   1.819 ++      PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.820 ++      png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
   1.821 ++   }
   1.822 ++
   1.823 ++#endif /* READ_APNG */
   1.824 +    else
   1.825 +    {
   1.826 +       PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.827 +@@ -538,7 +638,11 @@
   1.828 +       png_byte chunk_tag[4];
   1.829 + 
   1.830 +       /* TODO: this code can be commoned up with the same code in push_read */
   1.831 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.832 ++      PNG_PUSH_SAVE_BUFFER_IF_LT(12)
   1.833 ++#else
   1.834 +       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
   1.835 ++#endif
   1.836 +       png_push_fill_buffer(png_ptr, chunk_length, 4);
   1.837 +       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
   1.838 +       png_reset_crc(png_ptr);
   1.839 +@@ -546,17 +650,60 @@
   1.840 +       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
   1.841 +       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
   1.842 + 
   1.843 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.844 ++      if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
   1.845 ++      {
   1.846 ++          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) != 0)
   1.847 ++          {
   1.848 ++              png_ptr->process_mode = PNG_READ_CHUNK_MODE;
   1.849 ++              if (png_ptr->frame_end_fn != NULL)
   1.850 ++                 (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
   1.851 ++              png_ptr->num_frames_read++;
   1.852 ++              return;
   1.853 ++          }
   1.854 ++          else
   1.855 ++          {
   1.856 ++              if (png_ptr->chunk_name == png_IEND)
   1.857 ++                  png_error(png_ptr, "Not enough image data");
   1.858 ++              PNG_PUSH_SAVE_BUFFER_IF_FULL
   1.859 ++              png_warning(png_ptr, "Skipping (ignoring) a chunk between "
   1.860 ++                                   "APNG chunks");
   1.861 ++              png_crc_finish(png_ptr, png_ptr->push_length);
   1.862 ++              png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
   1.863 ++              return;
   1.864 ++          }
   1.865 ++      }
   1.866 ++      else
   1.867 ++#endif
   1.868 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.869 ++      if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
   1.870 ++#else
   1.871 +       if (png_ptr->chunk_name != png_IDAT)
   1.872 ++#endif
   1.873 +       {
   1.874 +          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
   1.875 + 
   1.876 +          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
   1.877 +             png_error(png_ptr, "Not enough compressed data");
   1.878 + 
   1.879 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.880 ++         if (png_ptr->frame_end_fn != NULL)
   1.881 ++            (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
   1.882 ++         png_ptr->num_frames_read++;
   1.883 ++#endif
   1.884 ++
   1.885 +          return;
   1.886 +       }
   1.887 + 
   1.888 +       png_ptr->idat_size = png_ptr->push_length;
   1.889 ++
   1.890 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.891 ++      if (png_ptr->num_frames_read > 0)
   1.892 ++      {
   1.893 ++         png_ensure_sequence_number(png_ptr, 4);
   1.894 ++         png_ptr->idat_size -= 4;
   1.895 ++      }
   1.896 ++#endif
   1.897 +    }
   1.898 + 
   1.899 +    if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
   1.900 +@@ -630,6 +777,16 @@
   1.901 +    if (!(buffer_length > 0) || buffer == NULL)
   1.902 +       png_error(png_ptr, "No IDAT data (internal error)");
   1.903 + 
   1.904 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.905 ++   /* If the app is not APNG-aware, decode only the first frame */
   1.906 ++   if ((png_ptr->apng_flags & PNG_APNG_APP) == 0 &&
   1.907 ++      png_ptr->num_frames_read > 0)
   1.908 ++   {
   1.909 ++      png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
   1.910 ++      return;
   1.911 ++   }
   1.912 ++#endif
   1.913 ++
   1.914 +    /* This routine must process all the data it has been given
   1.915 +     * before returning, calling the row callback as required to
   1.916 +     * handle the uncompressed results.
   1.917 +@@ -1084,6 +1241,18 @@
   1.918 +    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
   1.919 + }
   1.920 + 
   1.921 ++#ifdef PNG_READ_APNG_SUPPORTED
   1.922 ++void PNGAPI
   1.923 ++png_set_progressive_frame_fn(png_structp png_ptr,
   1.924 ++   png_progressive_frame_ptr frame_info_fn,
   1.925 ++   png_progressive_frame_ptr frame_end_fn)
   1.926 ++{
   1.927 ++   png_ptr->frame_info_fn = frame_info_fn;
   1.928 ++   png_ptr->frame_end_fn = frame_end_fn;
   1.929 ++   png_ptr->apng_flags |= PNG_APNG_APP;
   1.930 ++}
   1.931 ++#endif
   1.932 ++
   1.933 + png_voidp PNGAPI
   1.934 + png_get_progressive_ptr(png_const_structrp png_ptr)
   1.935 + {
   1.936 +Index: pngset.c
   1.937 +===================================================================
   1.938 +--- a/pngset.c
   1.939 ++++ b/pngset.c
   1.940 +@@ -241,6 +241,11 @@
   1.941 +    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
   1.942 + 
   1.943 +    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
   1.944 ++
   1.945 ++#ifdef PNG_APNG_SUPPORTED
   1.946 ++   /* for non-animated png. this may be overwritten from an acTL chunk later */
   1.947 ++   info_ptr->num_frames = 1;
   1.948 ++#endif
   1.949 + }
   1.950 + 
   1.951 + #ifdef PNG_oFFs_SUPPORTED
   1.952 +@@ -1110,6 +1115,146 @@
   1.953 + }
   1.954 + #endif /* sPLT */
   1.955 + 
   1.956 ++#ifdef PNG_APNG_SUPPORTED
   1.957 ++png_uint_32 PNGAPI
   1.958 ++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
   1.959 ++    png_uint_32 num_frames, png_uint_32 num_plays)
   1.960 ++{
   1.961 ++    png_debug1(1, "in %s storage function", "acTL");
   1.962 ++
   1.963 ++    if (png_ptr == NULL || info_ptr == NULL)
   1.964 ++    {
   1.965 ++        png_warning(png_ptr,
   1.966 ++                    "Call to png_set_acTL() with NULL png_ptr "
   1.967 ++                    "or info_ptr ignored");
   1.968 ++        return (0);
   1.969 ++    }
   1.970 ++    if (num_frames == 0)
   1.971 ++    {
   1.972 ++        png_warning(png_ptr,
   1.973 ++                    "Ignoring attempt to set acTL with num_frames zero");
   1.974 ++        return (0);
   1.975 ++    }
   1.976 ++    if (num_frames > PNG_UINT_31_MAX)
   1.977 ++    {
   1.978 ++        png_warning(png_ptr,
   1.979 ++                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
   1.980 ++        return (0);
   1.981 ++    }
   1.982 ++    if (num_plays > PNG_UINT_31_MAX)
   1.983 ++    {
   1.984 ++        png_warning(png_ptr,
   1.985 ++                    "Ignoring attempt to set acTL with num_plays > 2^31-1");
   1.986 ++        return (0);
   1.987 ++    }
   1.988 ++
   1.989 ++    info_ptr->num_frames = num_frames;
   1.990 ++    info_ptr->num_plays = num_plays;
   1.991 ++
   1.992 ++    info_ptr->valid |= PNG_INFO_acTL;
   1.993 ++
   1.994 ++    return (1);
   1.995 ++}
   1.996 ++
   1.997 ++/* delay_num and delay_den can hold any 16-bit values including zero */
   1.998 ++png_uint_32 PNGAPI
   1.999 ++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
  1.1000 ++    png_uint_32 width, png_uint_32 height,
  1.1001 ++    png_uint_32 x_offset, png_uint_32 y_offset,
  1.1002 ++    png_uint_16 delay_num, png_uint_16 delay_den,
  1.1003 ++    png_byte dispose_op, png_byte blend_op)
  1.1004 ++{
  1.1005 ++    png_debug1(1, "in %s storage function", "fcTL");
  1.1006 ++
  1.1007 ++    if (png_ptr == NULL || info_ptr == NULL)
  1.1008 ++    {
  1.1009 ++        png_warning(png_ptr,
  1.1010 ++                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
  1.1011 ++                    "ignored");
  1.1012 ++        return (0);
  1.1013 ++    }
  1.1014 ++
  1.1015 ++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
  1.1016 ++                             delay_num, delay_den, dispose_op, blend_op);
  1.1017 ++
  1.1018 ++    if (blend_op == PNG_BLEND_OP_OVER)
  1.1019 ++    {
  1.1020 ++        if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0 &&
  1.1021 ++            png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == 0)
  1.1022 ++        {
  1.1023 ++          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
  1.1024 ++                               "and wasteful for opaque images, ignored");
  1.1025 ++          blend_op = PNG_BLEND_OP_SOURCE;
  1.1026 ++        }
  1.1027 ++    }
  1.1028 ++
  1.1029 ++    info_ptr->next_frame_width = width;
  1.1030 ++    info_ptr->next_frame_height = height;
  1.1031 ++    info_ptr->next_frame_x_offset = x_offset;
  1.1032 ++    info_ptr->next_frame_y_offset = y_offset;
  1.1033 ++    info_ptr->next_frame_delay_num = delay_num;
  1.1034 ++    info_ptr->next_frame_delay_den = delay_den;
  1.1035 ++    info_ptr->next_frame_dispose_op = dispose_op;
  1.1036 ++    info_ptr->next_frame_blend_op = blend_op;
  1.1037 ++
  1.1038 ++    info_ptr->valid |= PNG_INFO_fcTL;
  1.1039 ++
  1.1040 ++    return (1);
  1.1041 ++}
  1.1042 ++
  1.1043 ++void /* PRIVATE */
  1.1044 ++png_ensure_fcTL_is_valid(png_structp png_ptr,
  1.1045 ++    png_uint_32 width, png_uint_32 height,
  1.1046 ++    png_uint_32 x_offset, png_uint_32 y_offset,
  1.1047 ++    png_uint_16 delay_num, png_uint_16 delay_den,
  1.1048 ++    png_byte dispose_op, png_byte blend_op)
  1.1049 ++{
  1.1050 ++    if (width == 0 || width > PNG_UINT_31_MAX)
  1.1051 ++        png_error(png_ptr, "invalid width in fcTL (0 or > 2^31-1)");
  1.1052 ++    if (height == 0 || height > PNG_UINT_31_MAX)
  1.1053 ++        png_error(png_ptr, "invalid height in fcTL (0 or > 2^31-1)");
  1.1054 ++    if (x_offset > PNG_UINT_31_MAX)
  1.1055 ++        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
  1.1056 ++    if (y_offset > PNG_UINT_31_MAX)
  1.1057 ++        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
  1.1058 ++    if (width + x_offset > png_ptr->first_frame_width ||
  1.1059 ++        height + y_offset > png_ptr->first_frame_height)
  1.1060 ++        png_error(png_ptr, "dimensions of a frame are greater than "
  1.1061 ++                           "the ones in IHDR");
  1.1062 ++
  1.1063 ++    if (dispose_op != PNG_DISPOSE_OP_NONE &&
  1.1064 ++        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
  1.1065 ++        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
  1.1066 ++        png_error(png_ptr, "invalid dispose_op in fcTL");
  1.1067 ++
  1.1068 ++    if (blend_op != PNG_BLEND_OP_SOURCE &&
  1.1069 ++        blend_op != PNG_BLEND_OP_OVER)
  1.1070 ++        png_error(png_ptr, "invalid blend_op in fcTL");
  1.1071 ++
  1.1072 ++    PNG_UNUSED(delay_num)
  1.1073 ++    PNG_UNUSED(delay_den)
  1.1074 ++}
  1.1075 ++
  1.1076 ++png_uint_32 PNGAPI
  1.1077 ++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
  1.1078 ++                              png_byte is_hidden)
  1.1079 ++{
  1.1080 ++    png_debug(1, "in png_first_frame_is_hidden()");
  1.1081 ++
  1.1082 ++    if (png_ptr == NULL)
  1.1083 ++        return 0;
  1.1084 ++
  1.1085 ++    if (is_hidden != 0)
  1.1086 ++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  1.1087 ++    else
  1.1088 ++        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
  1.1089 ++
  1.1090 ++    PNG_UNUSED(info_ptr)
  1.1091 ++
  1.1092 ++    return 1;
  1.1093 ++}
  1.1094 ++#endif /* APNG */
  1.1095 ++
  1.1096 + #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  1.1097 + static png_byte
  1.1098 + check_location(png_const_structrp png_ptr, int location)
  1.1099 +Index: pngrutil.c
  1.1100 +===================================================================
  1.1101 +--- a/pngrutil.c
  1.1102 ++++ b/pngrutil.c
  1.1103 +@@ -861,6 +861,11 @@
  1.1104 +    filter_type = buf[11];
  1.1105 +    interlace_type = buf[12];
  1.1106 + 
  1.1107 ++#ifdef PNG_READ_APNG_SUPPORTED
  1.1108 ++   png_ptr->first_frame_width = width;
  1.1109 ++   png_ptr->first_frame_height = height;
  1.1110 ++#endif
  1.1111 ++
  1.1112 +    /* Set internal variables */
  1.1113 +    png_ptr->width = width;
  1.1114 +    png_ptr->height = height;
  1.1115 +@@ -2761,6 +2766,180 @@
  1.1116 + }
  1.1117 + #endif
  1.1118 + 
  1.1119 ++#ifdef PNG_READ_APNG_SUPPORTED
  1.1120 ++void /* PRIVATE */
  1.1121 ++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  1.1122 ++{
  1.1123 ++    png_byte data[8];
  1.1124 ++    png_uint_32 num_frames;
  1.1125 ++    png_uint_32 num_plays;
  1.1126 ++    png_uint_32 didSet;
  1.1127 ++
  1.1128 ++    png_debug(1, "in png_handle_acTL");
  1.1129 ++
  1.1130 ++    if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
  1.1131 ++    {
  1.1132 ++        png_error(png_ptr, "Missing IHDR before acTL");
  1.1133 ++    }
  1.1134 ++    else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
  1.1135 ++    {
  1.1136 ++        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
  1.1137 ++        png_crc_finish(png_ptr, length);
  1.1138 ++        return;
  1.1139 ++    }
  1.1140 ++    else if ((png_ptr->mode & PNG_HAVE_acTL) != 0)
  1.1141 ++    {
  1.1142 ++        png_warning(png_ptr, "Duplicate acTL skipped");
  1.1143 ++        png_crc_finish(png_ptr, length);
  1.1144 ++        return;
  1.1145 ++    }
  1.1146 ++    else if (length != 8)
  1.1147 ++    {
  1.1148 ++        png_warning(png_ptr, "acTL with invalid length skipped");
  1.1149 ++        png_crc_finish(png_ptr, length);
  1.1150 ++        return;
  1.1151 ++    }
  1.1152 ++
  1.1153 ++    png_crc_read(png_ptr, data, 8);
  1.1154 ++    png_crc_finish(png_ptr, 0);
  1.1155 ++
  1.1156 ++    num_frames = png_get_uint_31(png_ptr, data);
  1.1157 ++    num_plays = png_get_uint_31(png_ptr, data + 4);
  1.1158 ++
  1.1159 ++    /* the set function will do error checking on num_frames */
  1.1160 ++    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
  1.1161 ++    if (didSet != 0)
  1.1162 ++        png_ptr->mode |= PNG_HAVE_acTL;
  1.1163 ++}
  1.1164 ++
  1.1165 ++void /* PRIVATE */
  1.1166 ++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  1.1167 ++{
  1.1168 ++    png_byte data[22];
  1.1169 ++    png_uint_32 width;
  1.1170 ++    png_uint_32 height;
  1.1171 ++    png_uint_32 x_offset;
  1.1172 ++    png_uint_32 y_offset;
  1.1173 ++    png_uint_16 delay_num;
  1.1174 ++    png_uint_16 delay_den;
  1.1175 ++    png_byte dispose_op;
  1.1176 ++    png_byte blend_op;
  1.1177 ++
  1.1178 ++    png_debug(1, "in png_handle_fcTL");
  1.1179 ++
  1.1180 ++    png_ensure_sequence_number(png_ptr, length);
  1.1181 ++
  1.1182 ++    if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
  1.1183 ++    {
  1.1184 ++        png_error(png_ptr, "Missing IHDR before fcTL");
  1.1185 ++    }
  1.1186 ++    else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
  1.1187 ++    {
  1.1188 ++        /* for any frames other then the first this message may be misleading,
  1.1189 ++        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
  1.1190 ++        * i can't think of a better message */
  1.1191 ++        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
  1.1192 ++        png_crc_finish(png_ptr, length-4);
  1.1193 ++        return;
  1.1194 ++    }
  1.1195 ++    else if ((png_ptr->mode & PNG_HAVE_fcTL) != 0)
  1.1196 ++    {
  1.1197 ++        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
  1.1198 ++        png_crc_finish(png_ptr, length-4);
  1.1199 ++        return;
  1.1200 ++    }
  1.1201 ++    else if (length != 26)
  1.1202 ++    {
  1.1203 ++        png_warning(png_ptr, "fcTL with invalid length skipped");
  1.1204 ++        png_crc_finish(png_ptr, length-4);
  1.1205 ++        return;
  1.1206 ++    }
  1.1207 ++
  1.1208 ++    png_crc_read(png_ptr, data, 22);
  1.1209 ++    png_crc_finish(png_ptr, 0);
  1.1210 ++
  1.1211 ++    width = png_get_uint_31(png_ptr, data);
  1.1212 ++    height = png_get_uint_31(png_ptr, data + 4);
  1.1213 ++    x_offset = png_get_uint_31(png_ptr, data + 8);
  1.1214 ++    y_offset = png_get_uint_31(png_ptr, data + 12);
  1.1215 ++    delay_num = png_get_uint_16(data + 16);
  1.1216 ++    delay_den = png_get_uint_16(data + 18);
  1.1217 ++    dispose_op = data[20];
  1.1218 ++    blend_op = data[21];
  1.1219 ++
  1.1220 ++    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
  1.1221 ++    {
  1.1222 ++        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
  1.1223 ++        return;
  1.1224 ++    }
  1.1225 ++
  1.1226 ++    if (info_ptr != NULL)
  1.1227 ++    {
  1.1228 ++        if (png_ptr->num_frames_read == 0 &&
  1.1229 ++            (width != info_ptr->width || height != info_ptr->height))
  1.1230 ++        {
  1.1231 ++            png_warning(png_ptr, "size in first frame's fcTL must match "
  1.1232 ++                               "the size in IHDR");
  1.1233 ++            return;
  1.1234 ++        }
  1.1235 ++
  1.1236 ++        /* The set function will do more error checking */
  1.1237 ++        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
  1.1238 ++                                x_offset, y_offset, delay_num, delay_den,
  1.1239 ++                                dispose_op, blend_op);
  1.1240 ++
  1.1241 ++        png_read_reinit(png_ptr, info_ptr);
  1.1242 ++
  1.1243 ++        png_ptr->mode |= PNG_HAVE_fcTL;
  1.1244 ++    }
  1.1245 ++}
  1.1246 ++
  1.1247 ++void /* PRIVATE */
  1.1248 ++png_have_info(png_structp png_ptr, png_infop info_ptr)
  1.1249 ++{
  1.1250 ++    if ((info_ptr->valid & PNG_INFO_acTL) != 0 &&
  1.1251 ++        (info_ptr->valid & PNG_INFO_fcTL) == 0)
  1.1252 ++    {
  1.1253 ++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  1.1254 ++        info_ptr->num_frames++;
  1.1255 ++    }
  1.1256 ++}
  1.1257 ++
  1.1258 ++void /* PRIVATE */
  1.1259 ++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  1.1260 ++{
  1.1261 ++    png_ensure_sequence_number(png_ptr, length);
  1.1262 ++
  1.1263 ++    /* This function is only called from png_read_end(), png_read_info(),
  1.1264 ++    * and png_push_read_chunk() which means that:
  1.1265 ++    * - the user doesn't want to read this frame
  1.1266 ++    * - or this is an out-of-place fdAT
  1.1267 ++    * in either case it is safe to ignore the chunk with a warning */
  1.1268 ++    png_warning(png_ptr, "ignoring fdAT chunk");
  1.1269 ++    png_crc_finish(png_ptr, length - 4);
  1.1270 ++    PNG_UNUSED(info_ptr)
  1.1271 ++}
  1.1272 ++
  1.1273 ++void /* PRIVATE */
  1.1274 ++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
  1.1275 ++{
  1.1276 ++    png_byte data[4];
  1.1277 ++    png_uint_32 sequence_number;
  1.1278 ++
  1.1279 ++    if (length < 4)
  1.1280 ++        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
  1.1281 ++
  1.1282 ++    png_crc_read(png_ptr, data, 4);
  1.1283 ++    sequence_number = png_get_uint_31(png_ptr, data);
  1.1284 ++
  1.1285 ++    if (sequence_number != png_ptr->next_seq_num)
  1.1286 ++        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
  1.1287 ++                           "number found");
  1.1288 ++
  1.1289 ++    png_ptr->next_seq_num++;
  1.1290 ++}
  1.1291 ++#endif /* READ_APNG */
  1.1292 ++
  1.1293 + #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
  1.1294 + /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
  1.1295 + static int
  1.1296 +@@ -4023,6 +4202,38 @@
  1.1297 +          uInt avail_in;
  1.1298 +          png_bytep buffer;
  1.1299 + 
  1.1300 ++#ifdef PNG_READ_APNG_SUPPORTED
  1.1301 ++         png_uint_32 bytes_to_skip = 0;
  1.1302 ++
  1.1303 ++         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
  1.1304 ++         {
  1.1305 ++            png_crc_finish(png_ptr, bytes_to_skip);
  1.1306 ++            bytes_to_skip = 0;
  1.1307 ++
  1.1308 ++            png_ptr->idat_size = png_read_chunk_header(png_ptr);
  1.1309 ++            if (png_ptr->num_frames_read == 0)
  1.1310 ++            {
  1.1311 ++               if (png_ptr->chunk_name != png_IDAT)
  1.1312 ++                  png_error(png_ptr, "Not enough image data");
  1.1313 ++            }
  1.1314 ++            else
  1.1315 ++            {
  1.1316 ++               if (png_ptr->chunk_name == png_IEND)
  1.1317 ++                  png_error(png_ptr, "Not enough image data");
  1.1318 ++               if (png_ptr->chunk_name != png_fdAT)
  1.1319 ++               {
  1.1320 ++                  png_warning(png_ptr, "Skipped (ignored) a chunk "
  1.1321 ++                                       "between APNG chunks");
  1.1322 ++                  bytes_to_skip = png_ptr->idat_size;
  1.1323 ++                  continue;
  1.1324 ++               }
  1.1325 ++
  1.1326 ++               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
  1.1327 ++
  1.1328 ++               png_ptr->idat_size -= 4;
  1.1329 ++            }
  1.1330 ++         }
  1.1331 ++#else
  1.1332 +          while (png_ptr->idat_size == 0)
  1.1333 +          {
  1.1334 +             png_crc_finish(png_ptr, 0);
  1.1335 +@@ -4034,6 +4245,7 @@
  1.1336 +             if (png_ptr->chunk_name != png_IDAT)
  1.1337 +                png_error(png_ptr, "Not enough image data");
  1.1338 +          }
  1.1339 ++#endif /* READ_APNG */
  1.1340 + 
  1.1341 +          avail_in = png_ptr->IDAT_read_size;
  1.1342 + 
  1.1343 +@@ -4097,6 +4309,9 @@
  1.1344 + 
  1.1345 +          png_ptr->mode |= PNG_AFTER_IDAT;
  1.1346 +          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
  1.1347 ++#ifdef PNG_READ_APNG_SUPPORTED
  1.1348 ++         png_ptr->num_frames_read++;
  1.1349 ++#endif
  1.1350 + 
  1.1351 +          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
  1.1352 +             png_chunk_benign_error(png_ptr, "Extra compressed data");
  1.1353 +@@ -4535,4 +4750,80 @@
  1.1354 + 
  1.1355 +    png_ptr->flags |= PNG_FLAG_ROW_INIT;
  1.1356 + }
  1.1357 ++
  1.1358 ++#ifdef PNG_READ_APNG_SUPPORTED
  1.1359 ++/* This function is to be called after the main IDAT set has been read and
  1.1360 ++ * before a new IDAT is read. It resets some parts of png_ptr
  1.1361 ++ * to make them usable by the read functions again */
  1.1362 ++void /* PRIVATE */
  1.1363 ++png_read_reset(png_structp png_ptr)
  1.1364 ++{
  1.1365 ++    png_ptr->mode &= ~PNG_HAVE_IDAT;
  1.1366 ++    png_ptr->mode &= ~PNG_AFTER_IDAT;
  1.1367 ++    png_ptr->row_number = 0;
  1.1368 ++    png_ptr->pass = 0;
  1.1369 ++}
  1.1370 ++
  1.1371 ++void /* PRIVATE */
  1.1372 ++png_read_reinit(png_structp png_ptr, png_infop info_ptr)
  1.1373 ++{
  1.1374 ++    png_ptr->width = info_ptr->next_frame_width;
  1.1375 ++    png_ptr->height = info_ptr->next_frame_height;
  1.1376 ++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
  1.1377 ++    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
  1.1378 ++        png_ptr->width);
  1.1379 ++    if (png_ptr->prev_row != NULL)
  1.1380 ++        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
  1.1381 ++}
  1.1382 ++
  1.1383 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  1.1384 ++/* same as png_read_reset() but for the progressive reader */
  1.1385 ++void /* PRIVATE */
  1.1386 ++png_progressive_read_reset(png_structp png_ptr)
  1.1387 ++{
  1.1388 ++#ifdef PNG_READ_INTERLACING_SUPPORTED
  1.1389 ++    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
  1.1390 ++
  1.1391 ++    /* Start of interlace block */
  1.1392 ++    static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
  1.1393 ++
  1.1394 ++    /* Offset to next interlace block */
  1.1395 ++    static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
  1.1396 ++
  1.1397 ++    /* Start of interlace block in the y direction */
  1.1398 ++    static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
  1.1399 ++
  1.1400 ++    /* Offset to next interlace block in the y direction */
  1.1401 ++    static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
  1.1402 ++
  1.1403 ++    if (png_ptr->interlaced != 0)
  1.1404 ++    {
  1.1405 ++        if ((png_ptr->transformations & PNG_INTERLACE) == 0)
  1.1406 ++            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
  1.1407 ++                                png_pass_ystart[0]) / png_pass_yinc[0];
  1.1408 ++        else
  1.1409 ++            png_ptr->num_rows = png_ptr->height;
  1.1410 ++
  1.1411 ++        png_ptr->iwidth = (png_ptr->width +
  1.1412 ++                           png_pass_inc[png_ptr->pass] - 1 -
  1.1413 ++                           png_pass_start[png_ptr->pass]) /
  1.1414 ++                           png_pass_inc[png_ptr->pass];
  1.1415 ++    }
  1.1416 ++    else
  1.1417 ++#endif /* READ_INTERLACING */
  1.1418 ++    {
  1.1419 ++        png_ptr->num_rows = png_ptr->height;
  1.1420 ++        png_ptr->iwidth = png_ptr->width;
  1.1421 ++    }
  1.1422 ++    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
  1.1423 ++    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
  1.1424 ++        png_error(png_ptr, "inflateReset failed");
  1.1425 ++    png_ptr->zstream.avail_in = 0;
  1.1426 ++    png_ptr->zstream.next_in = 0;
  1.1427 ++    png_ptr->zstream.next_out = png_ptr->row_buf;
  1.1428 ++    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
  1.1429 ++        png_ptr->iwidth) + 1;
  1.1430 ++}
  1.1431 ++#endif /* PROGRESSIVE_READ */
  1.1432 ++#endif /* READ_APNG */
  1.1433 + #endif /* READ */
  1.1434 +Index: pngwutil.c
  1.1435 +===================================================================
  1.1436 +--- a/pngwutil.c
  1.1437 ++++ b/pngwutil.c
  1.1438 +@@ -817,6 +817,11 @@
  1.1439 +    /* Write the chunk */
  1.1440 +    png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
  1.1441 + 
  1.1442 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1443 ++   png_ptr->first_frame_width = width;
  1.1444 ++   png_ptr->first_frame_height = height;
  1.1445 ++#endif
  1.1446 ++
  1.1447 +    if ((png_ptr->do_filter) == PNG_NO_FILTERS)
  1.1448 +    {
  1.1449 +       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
  1.1450 +@@ -998,7 +1003,15 @@
  1.1451 +                optimize_cmf(data, png_image_size(png_ptr));
  1.1452 + #endif
  1.1453 + 
  1.1454 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1455 ++         if (png_ptr->num_frames_written == 0)
  1.1456 ++#endif
  1.1457 +          png_write_complete_chunk(png_ptr, png_IDAT, data, size);
  1.1458 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1459 ++         else
  1.1460 ++            png_write_fdAT(png_ptr, data, size);
  1.1461 ++#endif /* WRITE_APNG */
  1.1462 ++
  1.1463 +          png_ptr->mode |= PNG_HAVE_IDAT;
  1.1464 + 
  1.1465 +          png_ptr->zstream.next_out = data;
  1.1466 +@@ -1044,7 +1057,15 @@
  1.1467 +             optimize_cmf(data, png_image_size(png_ptr));
  1.1468 + #endif
  1.1469 + 
  1.1470 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1471 ++         if (png_ptr->num_frames_written == 0)
  1.1472 ++#endif
  1.1473 +          png_write_complete_chunk(png_ptr, png_IDAT, data, size);
  1.1474 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1475 ++         else
  1.1476 ++            png_write_fdAT(png_ptr, data, size);
  1.1477 ++#endif /* WRITE_APNG */
  1.1478 ++
  1.1479 +          png_ptr->zstream.avail_out = 0;
  1.1480 +          png_ptr->zstream.next_out = NULL;
  1.1481 +          png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
  1.1482 +@@ -1858,6 +1879,82 @@
  1.1483 + }
  1.1484 + #endif
  1.1485 + 
  1.1486 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1487 ++void /* PRIVATE */
  1.1488 ++png_write_acTL(png_structp png_ptr,
  1.1489 ++    png_uint_32 num_frames, png_uint_32 num_plays)
  1.1490 ++{
  1.1491 ++    png_byte buf[8];
  1.1492 ++
  1.1493 ++    png_debug(1, "in png_write_acTL");
  1.1494 ++
  1.1495 ++    png_ptr->num_frames_to_write = num_frames;
  1.1496 ++
  1.1497 ++    if ((png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) != 0)
  1.1498 ++        num_frames--;
  1.1499 ++
  1.1500 ++    png_save_uint_32(buf, num_frames);
  1.1501 ++    png_save_uint_32(buf + 4, num_plays);
  1.1502 ++
  1.1503 ++    png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
  1.1504 ++}
  1.1505 ++
  1.1506 ++void /* PRIVATE */
  1.1507 ++png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
  1.1508 ++    png_uint_32 x_offset, png_uint_32 y_offset,
  1.1509 ++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
  1.1510 ++    png_byte blend_op)
  1.1511 ++{
  1.1512 ++    png_byte buf[26];
  1.1513 ++
  1.1514 ++    png_debug(1, "in png_write_fcTL");
  1.1515 ++
  1.1516 ++    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
  1.1517 ++        png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
  1.1518 ++    if (png_ptr->num_frames_written == 0 &&
  1.1519 ++        (width != png_ptr->first_frame_width ||
  1.1520 ++         height != png_ptr->first_frame_height))
  1.1521 ++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
  1.1522 ++                           "don't match the ones in IHDR");
  1.1523 ++
  1.1524 ++    /* more error checking */
  1.1525 ++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
  1.1526 ++                             delay_num, delay_den, dispose_op, blend_op);
  1.1527 ++
  1.1528 ++    png_save_uint_32(buf, png_ptr->next_seq_num);
  1.1529 ++    png_save_uint_32(buf + 4, width);
  1.1530 ++    png_save_uint_32(buf + 8, height);
  1.1531 ++    png_save_uint_32(buf + 12, x_offset);
  1.1532 ++    png_save_uint_32(buf + 16, y_offset);
  1.1533 ++    png_save_uint_16(buf + 20, delay_num);
  1.1534 ++    png_save_uint_16(buf + 22, delay_den);
  1.1535 ++    buf[24] = dispose_op;
  1.1536 ++    buf[25] = blend_op;
  1.1537 ++
  1.1538 ++    png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
  1.1539 ++
  1.1540 ++    png_ptr->next_seq_num++;
  1.1541 ++}
  1.1542 ++
  1.1543 ++void /* PRIVATE */
  1.1544 ++png_write_fdAT(png_structp png_ptr,
  1.1545 ++    png_const_bytep data, png_size_t length)
  1.1546 ++{
  1.1547 ++    png_byte buf[4];
  1.1548 ++
  1.1549 ++    png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
  1.1550 ++
  1.1551 ++    png_save_uint_32(buf, png_ptr->next_seq_num);
  1.1552 ++    png_write_chunk_data(png_ptr, buf, 4);
  1.1553 ++
  1.1554 ++    png_write_chunk_data(png_ptr, data, length);
  1.1555 ++
  1.1556 ++    png_write_chunk_end(png_ptr);
  1.1557 ++
  1.1558 ++    png_ptr->next_seq_num++;
  1.1559 ++}
  1.1560 ++#endif /* WRITE_APNG */
  1.1561 ++
  1.1562 + /* Initializes the row writing capability of libpng */
  1.1563 + void /* PRIVATE */
  1.1564 + png_write_start_row(png_structrp png_ptr)
  1.1565 +@@ -2752,4 +2849,39 @@
  1.1566 +    }
  1.1567 + #endif /* WRITE_FLUSH */
  1.1568 + }
  1.1569 ++
  1.1570 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  1.1571 ++void /* PRIVATE */
  1.1572 ++png_write_reset(png_structp png_ptr)
  1.1573 ++{
  1.1574 ++    png_ptr->row_number = 0;
  1.1575 ++    png_ptr->pass = 0;
  1.1576 ++    png_ptr->mode &= ~PNG_HAVE_IDAT;
  1.1577 ++}
  1.1578 ++
  1.1579 ++void /* PRIVATE */
  1.1580 ++png_write_reinit(png_structp png_ptr, png_infop info_ptr,
  1.1581 ++                 png_uint_32 width, png_uint_32 height)
  1.1582 ++{
  1.1583 ++    if (png_ptr->num_frames_written == 0 &&
  1.1584 ++        (width != png_ptr->first_frame_width ||
  1.1585 ++         height != png_ptr->first_frame_height))
  1.1586 ++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
  1.1587 ++                           "don't match the ones in IHDR");
  1.1588 ++    if (width > png_ptr->first_frame_width ||
  1.1589 ++        height > png_ptr->first_frame_height)
  1.1590 ++        png_error(png_ptr, "width and/or height for a frame greater than "
  1.1591 ++                           "the ones in IHDR");
  1.1592 ++
  1.1593 ++    png_set_IHDR(png_ptr, info_ptr, width, height,
  1.1594 ++                 info_ptr->bit_depth, info_ptr->color_type,
  1.1595 ++                 info_ptr->interlace_type, info_ptr->compression_type,
  1.1596 ++                 info_ptr->filter_type);
  1.1597 ++
  1.1598 ++    png_ptr->width = width;
  1.1599 ++    png_ptr->height = height;
  1.1600 ++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
  1.1601 ++    png_ptr->usr_width = png_ptr->width;
  1.1602 ++}
  1.1603 ++#endif /* WRITE_APNG */
  1.1604 + #endif /* WRITE */
  1.1605 +Index: scripts/symbols.def
  1.1606 +===================================================================
  1.1607 +--- a/scripts/symbols.def
  1.1608 ++++ b/scripts/symbols.def
  1.1609 +@@ -250,3 +250,23 @@
  1.1610 +  png_get_palette_max @243
  1.1611 +  png_set_option @244
  1.1612 +  png_image_write_to_memory @245
  1.1613 ++ png_get_acTL @246
  1.1614 ++ png_set_acTL @247
  1.1615 ++ png_get_num_frames @248
  1.1616 ++ png_get_num_plays @249
  1.1617 ++ png_get_next_frame_fcTL @250
  1.1618 ++ png_set_next_frame_fcTL @251
  1.1619 ++ png_get_next_frame_width @252
  1.1620 ++ png_get_next_frame_height @253
  1.1621 ++ png_get_next_frame_x_offset @254
  1.1622 ++ png_get_next_frame_y_offset @255
  1.1623 ++ png_get_next_frame_delay_num @256
  1.1624 ++ png_get_next_frame_delay_den @257
  1.1625 ++ png_get_next_frame_dispose_op @258
  1.1626 ++ png_get_next_frame_blend_op @259
  1.1627 ++ png_get_first_frame_is_hidden @260
  1.1628 ++ png_set_first_frame_is_hidden @261
  1.1629 ++ png_read_frame_head @262
  1.1630 ++ png_set_progressive_frame_fn @263
  1.1631 ++ png_write_frame_head @264
  1.1632 ++ png_write_frame_tail @265