Index: libpng-1.2.10/pngread.c
===================================================================
--- libpng-1.2.10/pngread.c	(révision 2)
+++ libpng-1.2.10/pngread.c	(copie de travail)
@@ -397,6 +397,10 @@
 #if defined(PNG_READ_zTXt_SUPPORTED)
       PNG_zTXt;
 #endif
+      PNG_aCTL;
+      PNG_fCTL;
+      PNG_aDAT;
+      png_fEND;
 #endif /* PNG_USE_LOCAL_ARRAYS */
       png_byte chunk_length[4];
       png_uint_32 length;
@@ -518,12 +522,116 @@
       else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
          png_handle_iTXt(png_ptr, info_ptr, length);
 #endif
+#if defined(PNG_READ_APNG_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_aCTL, 4))
+         png_handle_aCTL(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_fCTL, 4))
+         png_handle_fCTL(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_aDAT, 4))
+         png_handle_aDAT(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_fEND, 4))
+         png_handle_fEND(png_ptr, info_ptr, length);
+#endif
       else
          png_handle_unknown(png_ptr, info_ptr, length);
    }
 }
 #endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+void PNGAPI
+png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
+{
+    png_byte garbage[4];
+    png_byte have_chunk_after_IDAT;
+    png_byte have_fEND;
+    
+    png_debug(0, "Reading frame head\n");
+    
+    if (!(png_ptr->mode & PNG_HAVE_aCTL))
+        png_error(png_ptr, "attempt to png_read_frame_head() but "
+                           "no aCTL present");
+    
+    /* do nothing for the main IDAT */
+    if (png_ptr->num_frames_read == 0)
+        return;
+    
+    png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+    
+    png_read_reset(png_ptr);
+    png_ptr->mode &= ~PNG_HAVE_fCTL;
+    
+    have_chunk_after_IDAT = 0;
+    have_fEND = 0;
+    for (;;)
+    {
+#ifdef PNG_USE_LOCAL_ARRAYS
+        PNG_IDAT;
+        PNG_aDAT;
+        PNG_fCTL;
+        PNG_fEND;
+#endif
+        png_byte chunk_length[4];
+        png_uint_32 length;
+        
+        png_read_data(png_ptr, chunk_length, 4);
+        length = png_get_uint_31(png_ptr,chunk_length);
+        
+        png_reset_crc(png_ptr);
+        png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+        
+        if (!png_memcmp(png_ptr->chunk_name, png_fEND, 4))
+        {
+            if (have_fEND || png_ptr->num_frames_read == 0)
+                png_error(png_ptr, "out of place fEND chunk");
+            if (length != 0)
+                png_error(png_ptr, "fEND with non-zero length");
+            png_crc_finish(png_ptr, length);
+            png_read_data(png_ptr, garbage, 4); /* aDAT crc */
+            have_fEND = 1;
+            have_chunk_after_IDAT = 1;
+        }
+        else if (!png_memcmp(png_ptr->chunk_name, png_aDAT, 4))
+        {
+            if (png_ptr->num_frames_read > 1 && !have_fEND)
+                png_error(png_ptr, "missing fEND chunk");
+            
+            png_read_data(png_ptr, chunk_length, 4);
+            length = png_get_uint_31(png_ptr, chunk_length);
+            
+            png_reset_crc(png_ptr);
+            png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+            if (png_memcmp(png_ptr->chunk_name, png_fCTL, 4))
+                png_error(png_ptr, "expected fCTL inside an aDAT not found");
+            
+            png_handle_fCTL(png_ptr, info_ptr, length);
+            
+            png_read_data(png_ptr, chunk_length, 4);
+            length = png_get_uint_31(png_ptr, chunk_length);
+            
+            png_reset_crc(png_ptr);
+            png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+            if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+                png_error(png_ptr, "expected IDAT inside an aDAT not found");
+            
+            png_ptr->idat_size = length;
+            png_ptr->mode |= PNG_HAVE_IDAT;
+            
+            break;
+        }
+        else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+        {
+            /* discard trailing IDATs */
+            if (have_chunk_after_IDAT)
+                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
+            png_crc_finish(png_ptr, length);
+        }
+        else
+            png_error(png_ptr, "png_read_frame_head(): unexpected chunk type");
+    }
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
+
 /* optional call to update the users info_ptr structure */
 void PNGAPI
 png_read_update_info(png_structp png_ptr, png_infop info_ptr)
@@ -715,6 +823,9 @@
             png_error(png_ptr, "Extra compressed data");
          png_ptr->mode |= PNG_AFTER_IDAT;
          png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+#if defined(PNG_READ_APNG_SUPPORTED)
+         png_ptr->num_frames_read++;
+#endif
          break;
       }
       if (ret != Z_OK)
@@ -904,10 +1015,19 @@
 {
    png_byte chunk_length[4];
    png_uint_32 length;
+#if defined(PNG_READ_APNG_SUPPORTED)
+   png_byte garbage[4];
+   png_byte have_chunk_after_IDAT;
+   png_byte have_fEND;
+#endif
 
    png_debug(1, "in png_read_end\n");
    png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
-
+   
+#if defined(PNG_READ_APNG_SUPPORTED)
+   have_chunk_after_IDAT = 0;
+   have_fEND = 0;
+#endif
    do
    {
 #ifdef PNG_USE_LOCAL_ARRAYS
@@ -966,6 +1086,12 @@
 #if defined(PNG_READ_zTXt_SUPPORTED)
       PNG_zTXt;
 #endif
+#if defined(PNG_READ_APNG_SUPPORTED)
+      PNG_aCTL;
+      PNG_fCTL;
+      PNG_aDAT;
+      PNG_fEND;
+#endif
 #endif /* PNG_USE_LOCAL_ARRAYS */
 
       png_read_data(png_ptr, chunk_length, 4);
@@ -976,6 +1102,16 @@
 
       png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+      if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+      {
+         if (png_ptr->num_frames_read > 1 && !have_fEND && 
+             png_memcmp(png_ptr->chunk_name, png_fEND, 4))
+            png_error(png_ptr, "missing fEND chunk");
+         have_chunk_after_IDAT = 1;
+      }
+#endif
+      
       if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
          png_handle_IHDR(png_ptr, info_ptr, length);
       else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
@@ -1002,7 +1138,11 @@
           */
          if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
             png_error(png_ptr, "Too many IDAT's found");
+#if defined(PNG_READ_APNG_SUPPORTED)
+         if (have_chunk_after_IDAT)
+            png_error(png_ptr, "out of place IDAT");
          png_crc_finish(png_ptr, length);
+#endif
       }
       else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
          png_handle_PLTE(png_ptr, info_ptr, length);
@@ -1074,6 +1214,24 @@
       else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
          png_handle_iTXt(png_ptr, info_ptr, length);
 #endif
+#if defined(PNG_READ_APNG_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_aCTL, 4))
+         png_handle_aCTL(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_fCTL, 4))
+         png_handle_fCTL(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_aDAT, 4))
+         png_handle_aDAT(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_fEND, 4))
+      {
+         if (have_fEND)
+            png_error(png_ptr, "out of place fEND chunk");
+         if (length != 0)
+            png_error(png_ptr, "fEND with non-zero length");
+         png_crc_finish(png_ptr, length);
+         png_read_data(png_ptr, garbage, 4); /* aDAT crc */
+         have_fEND = 1;
+      }
+#endif
       else
          png_handle_unknown(png_ptr, info_ptr, length);
    } while (!(png_ptr->mode & PNG_HAVE_IEND));
Index: libpng-1.2.10/png.c
===================================================================
--- libpng-1.2.10/png.c	(révision 2)
+++ libpng-1.2.10/png.c	(copie de travail)
@@ -51,6 +51,10 @@
 PNG_tIME;
 PNG_tRNS;
 PNG_zTXt;
+PNG_aCTL;
+PNG_fCTL;
+PNG_aDAT;
+PNG_fEND;
 
 #ifdef PNG_READ_SUPPORTED
 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Index: libpng-1.2.10/pngget.c
===================================================================
--- libpng-1.2.10/pngget.c	(révision 2)
+++ libpng-1.2.10/pngget.c	(copie de travail)
@@ -794,6 +794,106 @@
 }
 #endif
 
+#if defined(PNG_APNG_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_aCTL(png_structp png_ptr, png_infop info_ptr,
+             png_uint_32 *num_frames, png_uint_32 *num_iterations)
+{
+    png_debug1(1, "in %s retrieval function\n", "aCTL");
+    
+    if ((info_ptr->valid & PNG_INFO_aCTL) &&
+        png_ptr != NULL && info_ptr != NULL &&
+        num_frames != NULL && num_iterations != NULL)
+    {
+        *num_frames = info_ptr->num_frames;
+        *num_iterations = info_ptr->num_iterations;
+        return 1;
+    }
+    
+    return 0;
+}
+
+png_uint_32 PNGAPI
+png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_num_frames()\n");
+    
+    return info_ptr->num_frames;
+}
+
+png_uint_32 PNGAPI
+png_get_num_iterations(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_num_iterations()\n");
+    
+    return info_ptr->num_iterations;
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_fCTL(png_structp png_ptr, png_infop info_ptr,
+             png_uint_32 *x_offset, png_uint_32 *y_offset,
+             png_uint_16 *delay_num, png_uint_16 *delay_den,
+             png_byte *render_op)
+{
+    png_debug1(1, "in %s retrieval function\n", "fCTL");
+    
+    if ((info_ptr->valid & PNG_INFO_fCTL) &&
+        png_ptr != NULL && info_ptr != NULL &&
+        x_offset != NULL && x_offset != NULL && 
+        delay_num != NULL && delay_den != NULL && render_op != NULL)
+    {
+        *x_offset = info_ptr->next_frame_x_offset;
+        *y_offset = info_ptr->next_frame_y_offset;
+        *delay_num = info_ptr->next_frame_delay_num;
+        *delay_den = info_ptr->next_frame_delay_den;
+        *render_op = info_ptr->next_frame_render_op;
+        return 1;
+    }
+    
+    return 0;
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_next_frame_x_offset()\n");
+    
+    return info_ptr->next_frame_x_offset;
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_next_frame_y_offset()\n");
+    
+    return info_ptr->next_frame_y_offset;
+}
+
+png_uint_16 PNGAPI
+png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_next_frame_delay_num()\n");
+    
+    return info_ptr->next_frame_delay_num;
+}
+
+png_uint_16 PNGAPI
+png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_next_frame_delay_den()\n");
+    
+    return info_ptr->next_frame_delay_den;
+}
+
+png_byte PNGAPI
+png_get_next_frame_render_op(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_get_next_frame_render_op()\n");
+    
+    return info_ptr->next_frame_render_op;
+}
+#endif /* PNG_APNG_SUPPORTED */
+
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
 png_uint_32 PNGAPI
 png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
Index: libpng-1.2.10/png.h
===================================================================
--- libpng-1.2.10/png.h	(révision 2)
+++ libpng-1.2.10/png.h	(copie de travail)
@@ -893,6 +893,16 @@
    png_fixed_point int_y_blue;
 #endif
 
+#if defined(PNG_APNG_SUPPORTED)
+   png_uint_32 num_frames;
+   png_uint_32 num_iterations;
+   png_uint_32 next_frame_x_offset;
+   png_uint_32 next_frame_y_offset;
+   png_uint_16 next_frame_delay_num;
+   png_uint_16 next_frame_delay_den;
+   png_byte next_frame_render_op;
+#endif
+
 } png_info;
 
 typedef png_info FAR * png_infop;
@@ -994,6 +1004,8 @@
 #define PNG_INFO_sPLT 0x2000   /* ESR, 1.0.6 */
 #define PNG_INFO_sCAL 0x4000   /* ESR, 1.0.6 */
 #define PNG_INFO_IDAT 0x8000L  /* ESR, 1.0.6 */
+#define PNG_INFO_aCTL 0x10000L
+#define PNG_INFO_fCTL 0x20000L
 
 /* This is used for the transformation routines, as some of them
  * change these values for the row.  It also should enable using
@@ -1034,7 +1046,10 @@
 typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
 typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
    png_uint_32, int));
+#if defined(PNG_APNG_SUPPORTED)
+typedef void (PNGAPI *png_progressive_frame_ptr) PNGARG((png_structp, png_uint_32));
 #endif
+#endif
 
 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
@@ -1360,8 +1375,33 @@
    png_uint_32 user_height_max;
 #endif
 
+#if defined(PNG_APNG_SUPPORTED)
+   png_uint_32 apng_flags;
+   png_uint_32 num_frames_expected;  /* to read or write, according to aCTL */
+#endif
+
+#if defined(PNG_READ_APNG_SUPPORTED)
+   png_uint_32 num_frames_read;      /* incremented after all image data of */
+                                     /* a frame is read */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+   png_progressive_frame_ptr frame_fn; /* frame read callback */
+#endif
+#endif
+
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+   png_uint_32 num_frames_written;   /* only used when writing APNGs */
+   png_uint_32 aDAT_length;          /* aDAT chunk length */
+   png_uint_32 aDAT_crc;
+#endif
+
 };
 
+/* png_struct.apng_flags: */
+/* only count the size of IDATs, don't write them */
+#define PNG_DO_NOT_WRITE_IDAT        0x0001
+#define PNG_DO_ADAT_CRC              0x0002
+/* used for progressive reading */
+#define PNG_INSIDE_aDAT              0x0004
 
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
@@ -1681,6 +1721,16 @@
 extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
    png_bytepp image));
 
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+extern PNG_EXPORT (void,png_write_frame_head) PNGARG((png_structp png_ptr,
+   png_infop png_info, png_bytepp row_pointers,
+   png_uint_32 x_offset, png_uint_32 y_offset, png_uint_16 delay_num,
+   png_uint_16 delay_den, png_byte render_op));
+
+extern PNG_EXPORT (void,png_write_frame_tail) PNGARG((png_structp png_ptr,
+   png_infop png_info));
+#endif
+   
 /* writes the end of the PNG file. */
 extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
    png_infop info_ptr));
@@ -1929,6 +1979,10 @@
    png_voidp progressive_ptr,
    png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
    png_progressive_end_ptr end_fn));
+#if defined(PNG_READ_APNG_SUPPORTED)
+extern PNG_EXPORT(void,png_set_progressive_frame_fn) PNGARG((png_structp png_ptr,
+   png_progressive_frame_ptr frame_fn));
+#endif
 
 /* returns the user pointer associated with the push read functions */
 extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
@@ -2357,6 +2411,42 @@
 #endif
 #endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
 
+#if defined(PNG_APNG_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_aCTL) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, 
+   png_uint_32 *num_frames, png_uint_32 *num_iterations));
+extern PNG_EXPORT(png_uint_32,png_set_aCTL) PNGARG((png_structp png_ptr, 
+   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_iterations));
+extern PNG_EXPORT(png_uint_32,png_get_num_frames) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32,png_get_num_iterations) 
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+
+extern PNG_EXPORT(png_uint_32,png_get_next_frame_fCTL) 
+   PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 *x_offset, 
+   png_uint_32 *y_offset, png_uint_16 *delay_num, png_uint_16 *delay_den, 
+   png_byte *render_op));
+extern PNG_EXPORT(png_uint_32,png_set_next_frame_fCTL) 
+   PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 x_offset, 
+   png_uint_32 y_offset, png_uint_16 delay_num, png_uint_16 delay_den, 
+   png_byte render_op));
+extern PNG_EXPORT(png_uint_32,png_get_next_frame_x_offset)
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32,png_get_next_frame_y_offset)
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_num)
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_den)
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_byte,png_get_next_frame_render_op)
+   PNGARG((png_structp png_ptr, png_infop info_ptr));
+#endif /* PNG_APNG_SUPPORTED */
+
+#if defined(PNG_READ_APNG_SUPPORTED)
+extern PNG_EXPORT(void,png_read_frame_head) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+#endif
+
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
 /* provide a list of chunks and how they are to be handled, if the built-in
    handling or default unknown chunk handling is not desired.  Any chunks not
@@ -2659,6 +2749,8 @@
 #define PNG_WROTE_INFO_BEFORE_PLTE 0x400
 #define PNG_BACKGROUND_IS_GRAY     0x800
 #define PNG_HAVE_PNG_SIGNATURE    0x1000
+#define PNG_HAVE_aCTL             0x2000
+#define PNG_HAVE_fCTL             0x4000
 
 /* flags for the transformations the PNG library does on the image data */
 #define PNG_BGR                0x0001
@@ -2802,6 +2894,10 @@
 #define PNG_tIME const png_byte png_tIME[5] = {116,  73,  77,  69, '\0'}
 #define PNG_tRNS const png_byte png_tRNS[5] = {116,  82,  78,  83, '\0'}
 #define PNG_zTXt const png_byte png_zTXt[5] = {122,  84,  88, 116, '\0'}
+#define PNG_aCTL const png_byte png_aCTL[5] = { 97,  67,  84,  76, '\0'}
+#define PNG_fCTL const png_byte png_fCTL[5] = {102,  67,  84,  76, '\0'}
+#define PNG_aDAT const png_byte png_aDAT[5] = { 97,  68,  65,  84, '\0'}
+#define PNG_fEND const png_byte png_fEND[5] = {102,  69,  78,  68, '\0'}
 
 #ifdef PNG_USE_GLOBAL_ARRAYS
 PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5];
@@ -2825,6 +2921,10 @@
 PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5];
 PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5];
 PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_aCTL[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_fCTL[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_aDAT[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_fEND[5];
 #endif /* PNG_USE_GLOBAL_ARRAYS */
 
 #if defined(PNG_1_0_X) || defined (PNG_1_2_X)
@@ -3099,6 +3199,15 @@
 #endif
 #endif
 
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+PNG_EXTERN void png_write_aCTL PNGARG((png_structp png_ptr,
+   png_uint_32 num_frames, png_uint_32 num_iterations));
+
+PNG_EXTERN void png_write_fCTL PNGARG((png_structp png_ptr, 
+   png_uint_32 x_offset, png_uint_32 y_offset, png_uint_16 delay_num, 
+   png_uint_16 delay_den, png_byte render_op));
+#endif
+
 /* Called when finished processing a row of data */
 PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
 
@@ -3150,6 +3259,16 @@
 PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
    png_infop info_ptr));
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+/* private, reset some things to become ready for reading next frame */
+PNG_EXTERN void png_read_reset PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_progressive_read_reset PNGARG((png_structp png_ptr));
+#endif
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+/* private, reset some things to become ready for writing next frame */
+PNG_EXTERN void png_write_reset PNGARG((png_structp png_ptr));
+#endif
+
 /* these are the functions that do the transformations */
 #if defined(PNG_READ_FILLER_SUPPORTED)
 PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
@@ -3365,6 +3484,17 @@
    png_uint_32 length));
 #endif
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+PNG_EXTERN void png_handle_aCTL PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+PNG_EXTERN void png_handle_fCTL PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+PNG_EXTERN void png_handle_aDAT PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+PNG_EXTERN void png_handle_fEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+#endif
+
 PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
    png_infop info_ptr, png_uint_32 length));
 
Index: libpng-1.2.10/pngwrite.c
===================================================================
--- libpng-1.2.10/pngwrite.c	(révision 2)
+++ libpng-1.2.10/pngwrite.c	(copie de travail)
@@ -261,6 +261,25 @@
       }
    }
 #endif
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+   if (info_ptr->valid & PNG_INFO_aCTL)
+   {
+      if (!(info_ptr->valid & PNG_INFO_fCTL))
+         png_error(png_ptr, "Unable to write aCTL when fCTL not set");
+      png_write_aCTL(png_ptr, info_ptr->num_frames, info_ptr->num_iterations);
+   }
+   if (info_ptr->valid & PNG_INFO_fCTL)
+   {
+      if (!(info_ptr->valid & PNG_INFO_aCTL))
+         png_error(png_ptr, "Unable to write fCTL when aCTL not set");
+      png_write_fCTL(png_ptr,
+                     info_ptr->next_frame_x_offset,
+                     info_ptr->next_frame_y_offset,
+                     info_ptr->next_frame_delay_num,
+                     info_ptr->next_frame_delay_den,
+                     info_ptr->next_frame_render_op);
+   }
+#endif
 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
    if (info_ptr->unknown_chunks_num)
    {
@@ -299,6 +318,10 @@
       return;
    if (!(png_ptr->mode & PNG_HAVE_IDAT))
       png_error(png_ptr, "No IDATs written into file");
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+   if (png_ptr->num_frames_expected != png_ptr->num_frames_written)
+      png_error(png_ptr, "Not enough frames written");
+#endif
 
    /* see if user wants us to write information chunks */
    if (info_ptr != NULL)
@@ -1510,4 +1533,89 @@
       /* quiet compiler warnings */ return;
 }
 #endif
+
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+void PNGAPI
+png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
+    png_bytepp row_pointers, png_uint_32 x_offset, png_uint_32 y_offset, 
+    png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+    PNG_aDAT;
+#endif
+    png_byte prepared_length[4];
+    png_byte data[17];
+    
+    png_debug(1, "in png_write_frame_head\n");
+    
+    /* there is a chance these have been set after png_write_info was called,
+    * so they would be set but not written. is there a way to be sure? */
+    if (!(info_ptr->valid & PNG_INFO_aCTL))
+        png_error(png_ptr, "png_write_frame_head(): aCTL not set");
+    if (!(info_ptr->valid & PNG_INFO_fCTL))
+        png_error(png_ptr, "png_write_frame_head(): fCTL not set");
+    
+    /* do nothing for the regular IDAT */
+    if(png_ptr->num_frames_written == 0)
+        return;
+    
+    /* figure out the aDAT data length */
+    png_ptr->aDAT_length = 41; /* fCTL + fEND */
+    png_write_reset(png_ptr);
+    png_ptr->apng_flags |= PNG_DO_NOT_WRITE_IDAT;
+    png_write_image(png_ptr, row_pointers);
+    png_ptr->apng_flags &= ~PNG_DO_NOT_WRITE_IDAT;
+    png_write_reset(png_ptr);
+    
+    png_ptr->apng_flags |= PNG_DO_ADAT_CRC;
+    png_ptr->aDAT_crc = crc32(0, Z_NULL, 0);
+    
+    png_save_uint_32(prepared_length, png_ptr->aDAT_length);
+    png_write_data(png_ptr, prepared_length, 4);
+    
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, (png_bytep)png_aDAT, 4);
+    png_write_data(png_ptr, (png_bytep)png_aDAT, 4);
+    
+    png_write_fCTL(png_ptr, x_offset, y_offset, 
+                   delay_num, delay_den, render_op);
+}
+
+void PNGAPI
+png_write_frame_tail(png_structp png_ptr, png_infop png_info)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+    PNG_fEND;
+#endif
+    png_byte buf[4];
+    
+    png_debug(1, "in png_write_frame_tail\n");
+    
+    png_ptr->num_frames_written++;
+    
+    /* do nothing else for the regular IDAT */
+    if(png_ptr->num_frames_written == 1)
+        return;
+    
+    /* write fEND chunk */
+    /* chunk length */
+    buf[0] = buf[1] = buf[2] = buf[3] = 0;
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+    png_write_data(png_ptr, buf, 4);
+    /* chunk name */
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, png_fEND, 4);
+    png_calculate_crc(png_ptr, (png_bytep)png_fEND, 4);
+    png_write_data(png_ptr, (png_bytep)png_fEND, 4);
+    /* chunk crc */
+    png_save_uint_32(buf, png_ptr->crc);
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+    png_write_data(png_ptr, buf, 4);
+    
+    /* write the aDAT crc */
+    png_save_uint_32(buf, png_ptr->aDAT_crc);
+    png_write_data(png_ptr, buf, (png_size_t)4);
+    
+    /* don't need to unset PNG_DO_ADAT_CRC in png_ptr->apng_flags */
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+
 #endif /* PNG_WRITE_SUPPORTED */
Index: libpng-1.2.10/pngpread.c
===================================================================
--- libpng-1.2.10/pngpread.c	(révision 2)
+++ libpng-1.2.10/pngpread.c	(copie de travail)
@@ -190,6 +190,12 @@
 #if defined(PNG_READ_zTXt_SUPPORTED)
       PNG_zTXt;
 #endif
+#if defined(PNG_READ_APNG_SUPPORTED)
+      PNG_aCTL;
+      PNG_fCTL;
+      PNG_aDAT;
+      PNG_fEND;
+#endif
 #endif /* PNG_USE_LOCAL_ARRAYS */
    /* First we make sure we have enough data for the 4 byte chunk name
     * and the 4 byte chunk length before proceeding with decoding the
@@ -213,7 +219,74 @@
       png_crc_read(png_ptr, png_ptr->chunk_name, 4);
       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
    }
-
+   
+#if defined(PNG_READ_APNG_SUPPORTED)
+   /* read the aDAT contents */
+   if (png_ptr->apng_flags & PNG_INSIDE_aDAT)
+   {
+      if (!(png_ptr->mode & PNG_HAVE_fCTL))
+      {
+         if (png_memcmp(png_ptr->chunk_name, png_fCTL, 4))
+            png_error(png_ptr, "unexpected chunk type when fCTL expected "
+                               "inside aDAT");
+         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+         {
+            png_push_save_buffer(png_ptr);
+            return;
+         }
+         png_handle_fCTL(png_ptr, info_ptr, png_ptr->push_length);
+         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+         return;
+      }
+      else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+      {
+         if (!(png_ptr->mode & PNG_HAVE_IDAT))
+         {
+            /* frame data follows */
+            png_ptr->idat_size = png_ptr->push_length;
+            png_ptr->mode |= PNG_HAVE_IDAT;
+            png_ptr->process_mode = PNG_READ_IDAT_MODE;
+            return;
+         }
+         else
+         {
+            /* skip trailing IDATs */
+            if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+            {
+               png_push_save_buffer(png_ptr);
+               return;
+            }
+            png_push_crc_skip(png_ptr, png_ptr->push_length);
+            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+            return;
+         }
+      }
+      else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_fEND, 4))
+      {
+         png_byte garbage[4];
+         
+         if (!(png_ptr->mode & PNG_HAVE_IDAT))
+            png_error(png_ptr, "frame data inside aDAT missing");
+         if (png_ptr->push_length != 0)
+            png_error(png_ptr, "fEND with non-zero length");
+         
+         /* wait for fEND crc and aDAT crc */
+         if (png_ptr->buffer_size < 8)
+         {
+            png_push_save_buffer(png_ptr);
+            return;
+         }
+         
+         png_push_crc_skip(png_ptr, png_ptr->push_length);
+         png_read_data(png_ptr, garbage, 4); /* aDAT crc */
+         
+         png_ptr->apng_flags &= ~PNG_INSIDE_aDAT;
+         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+         return;
+      }
+   }
+#endif /* PNG_READ_APNG_SUPPORTED */
+   
    if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
    {
       if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -483,6 +556,49 @@
       png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
    }
 #endif
+#if defined(PNG_READ_APNG_SUPPORTED)
+   else if (!png_memcmp(png_ptr->chunk_name, png_aCTL, 4))
+   {
+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+      {
+         png_push_save_buffer(png_ptr);
+         return;
+      }
+      png_handle_aCTL(png_ptr, info_ptr, png_ptr->push_length);
+   }
+   else if (!png_memcmp(png_ptr->chunk_name, png_fCTL, 4))
+   {
+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+      {
+         png_push_save_buffer(png_ptr);
+         return;
+      }
+      if (png_ptr->num_frames_read == 0)
+      {
+         png_warning(png_ptr, "skipping out of place fCTL");
+         png_crc_finish(png_ptr, png_ptr->push_length);
+      }
+      else
+         png_handle_fCTL(png_ptr, info_ptr, png_ptr->push_length);
+   }
+   else if (!png_memcmp(png_ptr->chunk_name, png_aDAT, 4))
+   {
+      if (png_ptr->num_frames_read == 0)
+         png_error(png_ptr, "out of place aDAT");
+      png_progressive_read_reset(png_ptr);
+      png_ptr->apng_flags |= PNG_INSIDE_aDAT;
+      png_ptr->mode &= ~PNG_HAVE_fCTL;
+   }
+   else if (!png_memcmp(png_ptr->chunk_name, png_fEND, 4))
+   {
+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+      {
+         png_push_save_buffer(png_ptr);
+         return;
+      }
+      png_handle_fEND(png_ptr, info_ptr, png_ptr->push_length);
+   }
+#endif /* PNG_READ_APNG_SUPPORTED */
    else
    {
       if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -673,6 +789,11 @@
       if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
       {
          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+#if defined(PNG_READ_APNG_SUPPORTED)
+         if (png_ptr->frame_fn != NULL)
+            png_ptr->frame_fn(png_ptr, png_ptr->num_frames_read);
+         png_ptr->num_frames_read++;
+#endif
          if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
             png_error(png_ptr, "Not enough compressed data");
          return;
@@ -1565,6 +1686,15 @@
    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
 }
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+void PNGAPI
+png_set_progressive_frame_fn(png_structp png_ptr,
+   png_progressive_frame_ptr frame_fn)
+{
+   png_ptr->frame_fn = frame_fn;
+}
+#endif
+
 png_voidp PNGAPI
 png_get_progressive_ptr(png_structp png_ptr)
 {
Index: libpng-1.2.10/pngset.c
===================================================================
--- libpng-1.2.10/pngset.c	(révision 2)
+++ libpng-1.2.10/pngset.c	(copie de travail)
@@ -362,6 +362,11 @@
       info_ptr->rowbytes = (png_size_t)0;
    else
       info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width);
+   
+#if defined(PNG_APNG_SUPPORTED)
+   /* for non-animated png. this may be overritten from an aCTL chunk later */
+   info_ptr->num_frames = 1;
+#endif
 }
 
 #if defined(PNG_oFFs_SUPPORTED)
@@ -993,6 +998,91 @@
 }
 #endif /* PNG_sPLT_SUPPORTED */
 
+#if defined(PNG_APNG_SUPPORTED)
+png_uint_32 PNGAPI
+png_set_aCTL(png_structp png_ptr, png_infop info_ptr, 
+             png_uint_32 num_frames, png_uint_32 num_iterations)
+{
+    png_debug1(1, "in %s storage function\n", "aCTL");
+
+    if (png_ptr == NULL || info_ptr == NULL)
+    {
+        png_warning(png_ptr, 
+                    "Call to png_set_aCTL() with NULL png_ptr "
+                    "or info_ptr ignored");
+        return 0;
+    }
+    if(num_frames == 0)
+    {
+        png_warning(png_ptr, 
+                    "Ignoring attempt to set aCTL with num_frames zero");
+        return 0;
+    }
+    if(num_frames > PNG_UINT_31_MAX)
+    {
+        png_warning(png_ptr, 
+                    "Ignoring attempt to set aCTL with num_frames > 2^31-1");
+        return 0;
+    }
+    if(num_iterations > PNG_UINT_31_MAX)
+    {
+        png_warning(png_ptr, 
+                    "Ignoring attempt to set aCTL with num_iterations "
+                    "> 2^31-1");
+        return 0;
+    }
+    
+    info_ptr->num_frames = num_frames;
+    info_ptr->num_iterations = num_iterations;
+    
+    info_ptr->valid |= PNG_INFO_aCTL;
+    
+    return 1;
+}
+
+/* delay_num and delay_den can hold any values including zero */
+png_uint_32 PNGAPI
+png_set_next_frame_fCTL(png_structp png_ptr, png_infop info_ptr, 
+             png_uint_32 x_offset, png_uint_32 y_offset,
+             png_uint_16 delay_num, png_uint_16 delay_den,
+             png_byte render_op)
+{
+    png_debug1(1, "in %s storage function\n", "fCTL");
+
+    if (png_ptr == NULL || info_ptr == NULL)
+    {
+        png_warning(png_ptr, 
+                    "Call to png_set_fCTL() with NULL png_ptr or info_ptr "
+                    "ignored");
+        return 0;
+    }
+    if (render_op & 0xE0)
+    {
+        /* Bits 5 through 7 are reserved and must be set to zero (APNG spec) */
+        png_warning(png_ptr, 
+                    "Ignoring attempt to set fCTL with invalid render_op");
+        return 0;
+    }
+    //!!?? some more error-checking on render_op's displose bits
+    if(x_offset > PNG_UINT_31_MAX || y_offset > PNG_UINT_31_MAX)
+    {
+        png_warning(png_ptr, 
+                    "Ignoring attempt to set fCTL with x_offset or y_offset "
+                    "> 2^31-1");
+        return 0;
+    }
+    info_ptr->next_frame_x_offset = x_offset;
+    info_ptr->next_frame_y_offset = y_offset;
+    info_ptr->next_frame_delay_num = delay_num;
+    info_ptr->next_frame_delay_den = delay_den;
+    info_ptr->next_frame_render_op = render_op;
+    
+    info_ptr->valid |= PNG_INFO_fCTL;
+    
+    return 1;
+}
+#endif /* PNG_APNG_SUPPORTED */
+
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
 void PNGAPI
 png_set_unknown_chunks(png_structp png_ptr,
Index: libpng-1.2.10/pngrutil.c
===================================================================
--- libpng-1.2.10/pngrutil.c	(révision 2)
+++ libpng-1.2.10/pngrutil.c	(copie de travail)
@@ -2131,6 +2131,140 @@
 }
 #endif
 
+#if defined(PNG_READ_APNG_SUPPORTED)
+void /* PRIVATE */
+png_handle_aCTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    png_byte data[8];
+    png_uint_32 num_frames;
+    png_uint_32 num_iterations;
+    png_uint_32 didSet;
+    
+    png_debug(1, "in png_handle_aCTL\n");
+
+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
+    {
+        png_error(png_ptr, "Missing IHDR before aCTL");
+    }
+    else if (png_ptr->mode & PNG_HAVE_IDAT)
+    {
+        png_warning(png_ptr, "Invalid aCTL after IDAT skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (png_ptr->mode & PNG_HAVE_aCTL)
+    {
+        png_warning(png_ptr, "Duplicate aCTL skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (length != 8)
+    {
+        png_warning(png_ptr, "aCTL with invalid length skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    
+    png_crc_read(png_ptr, data, 8);
+    png_crc_finish(png_ptr, 0);
+    
+    num_frames = png_get_uint_31(png_ptr, data);
+    num_iterations = png_get_uint_31(png_ptr, data + 4);
+    
+    /* the set function will do error checking on num_frames */
+    didSet = png_set_aCTL(png_ptr, info_ptr, num_frames, num_iterations);
+    if(didSet)
+        png_ptr->mode |= PNG_HAVE_aCTL;
+}
+
+void /* PRIVATE */
+png_handle_fCTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    png_byte data[17];
+    png_uint_32 sequence_number;
+    png_uint_32 x_offset;
+    png_uint_32 y_offset;
+    png_uint_16 delay_num;
+    png_uint_16 delay_den;
+    png_byte render_op;
+    png_uint_32 didSet;
+    
+    png_debug(1, "in png_handle_fCTL\n");
+    
+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
+    {
+        png_error(png_ptr, "Missing IHDR before fCTL");
+    }
+    else if (png_ptr->mode & PNG_HAVE_IDAT)
+    {
+        /* for any frames other then the first this message may be misleading,
+        * but correct. PNG_HAVE_IDAT is unset when the frame head is read
+        * i can't think of a better message */
+        png_warning(png_ptr, "Invalid fCTL after IDAT skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (png_ptr->mode & PNG_HAVE_fCTL)
+    {
+        png_warning(png_ptr, "Duplicate fCTL within one frame skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (length != 17)
+    {
+        png_warning(png_ptr, "fCTL with invalid length skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    
+    png_crc_read(png_ptr, data, 17);
+    png_crc_finish(png_ptr, 0);
+    
+    sequence_number = png_get_uint_31(png_ptr, data);
+    x_offset = png_get_uint_31(png_ptr, data + 4);
+    y_offset = png_get_uint_31(png_ptr, data + 8);
+    delay_num = png_get_uint_16(data + 12);
+    delay_den = png_get_uint_16(data + 14);
+    render_op = data[16];
+    
+    if (sequence_number != png_ptr->num_frames_read)
+        png_error(png_ptr, 
+                  "png_handle_fCTL: out-of-sequence frame");
+    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
+        png_error(png_ptr, 
+                  "png_handle_fCTL: fCTL for the first frame with "
+                  "non-zero x_offset or y_offset not allowed");
+
+    /* the set function will do error checking on render_op */
+    didSet = png_set_next_frame_fCTL(png_ptr, info_ptr, x_offset, y_offset, 
+                                     delay_num, delay_den, render_op);
+    if(!didSet)
+        png_error(png_ptr, "invalid fCTL chunk");
+    
+    png_ptr->mode |= PNG_HAVE_fCTL; 
+}
+
+void /* PRIVATE */
+png_handle_aDAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    /* this function is only called from png_read_end() and png_read_info()
+    * which means that:
+    * - the user doesn't want to read this frame
+    * - or this is an out-of-place aDAT
+    * in either case it is safe to ignore the chunk with a warning */
+    png_warning(png_ptr, "ignoring aDAT chunk");
+    png_crc_finish(png_ptr, length);
+}
+
+void /* PRIVATE */
+png_handle_fEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    /* fEND must always be inside aDAT, so if got here, it's a problem */
+    png_warning(png_ptr, "ignoring out-of-place fEND chunk");
+    png_crc_finish(png_ptr, length);
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
+
 /* This function is called when we haven't found a handler for a
    chunk.  If there isn't a problem with the chunk itself (ie bad
    chunk name, CRC, or a critical chunk), the chunk is silently ignored
@@ -3095,8 +3229,10 @@
    if (row_bytes > (png_uint_32)65536L)
       png_error(png_ptr, "This image requires a row greater than 64KB");
 #endif
-   png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
-   png_ptr->row_buf = png_ptr->big_row_buf+32;
+   if (png_ptr->big_row_buf == NULL)
+      png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
+   if (png_ptr->row_buf == NULL)
+      png_ptr->row_buf = png_ptr->big_row_buf+32;
 #if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
    png_ptr->row_buf_size = row_bytes;
 #endif
@@ -3121,4 +3257,64 @@
 
    png_ptr->flags |= PNG_FLAG_ROW_INIT;
 }
+
+#if defined(PNG_READ_APNG_SUPPORTED)
+/* This function is to be called after the main IDAT set has been read and
+ * before a new IDAT is read. It resets some parts of png_ptr
+ * to make them usable by the read functions again */
+void /* PRIVATE */
+png_read_reset(png_structp png_ptr)
+{
+    png_ptr->mode &= ~PNG_HAVE_IDAT;
+    png_ptr->mode &= ~PNG_AFTER_IDAT;
+    png_ptr->row_number = 0;
+    png_ptr->pass = 0;
+    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
+}
+
+/* same as png_read_reset() but for the progressive reader */
+void /* PRIVATE */
+png_progressive_read_reset(png_structp png_ptr)
+{
+    png_uint_32 row_bytes;
+    
+    png_read_reset(png_ptr);
+
+    if (png_ptr->interlaced)
+    {
+        if (!(png_ptr->transformations & PNG_INTERLACE))
+            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+                                png_pass_ystart[0]) / png_pass_yinc[0];
+        else
+           png_ptr->num_rows = png_ptr->height;
+
+        png_ptr->iwidth = (png_ptr->width +
+                          png_pass_inc[png_ptr->pass] - 1 -
+                          png_pass_start[png_ptr->pass]) /
+                          png_pass_inc[png_ptr->pass];
+
+        row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
+
+        png_ptr->irowbytes = (png_size_t)row_bytes;
+        if((png_uint_32)png_ptr->irowbytes != row_bytes)
+            png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
+    }
+    else
+    {
+        png_ptr->num_rows = png_ptr->height;
+        png_ptr->iwidth = png_ptr->width;
+        png_ptr->irowbytes = png_ptr->rowbytes + 1;
+    }
+    
+    png_ptr->flags &= ~PNG_FLAG_ZLIB_FINISHED;
+    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
+        png_error(png_ptr, "inflateReset failed");
+    png_ptr->zstream.avail_in = 0;
+    png_ptr->zstream.next_in = 0;
+    png_ptr->zstream.next_out = png_ptr->row_buf;
+    png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+    
+    //~ bzero(&(png_ptr->row_info), sizeof(png_ptr->row_info));
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
 #endif /* PNG_READ_SUPPORTED */
Index: libpng-1.2.10/pngwutil.c
===================================================================
--- libpng-1.2.10/pngwutil.c	(révision 2)
+++ libpng-1.2.10/pngwutil.c	(copie de travail)
@@ -605,6 +605,15 @@
 #endif
    png_debug(1, "in png_write_IDAT\n");
 
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+   if (png_ptr->apng_flags & PNG_DO_NOT_WRITE_IDAT)
+   {
+      /* only record the size of the data that would be written */
+      png_ptr->aDAT_length += length + 12;
+      return;
+   }
+#endif
+
    /* Optimize the CMF field in the zlib stream. */
    /* This hack of the zlib stream is compliant to the stream specification. */
    if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
@@ -646,6 +655,20 @@
 
    png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
    png_ptr->mode |= PNG_HAVE_IDAT;
+
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+   if (png_ptr->apng_flags & PNG_DO_ADAT_CRC)
+   {
+      png_byte buf[4];
+      png_save_uint_32(buf, length);
+      png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+      png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, (png_bytep)png_IDAT, 4);
+      png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, data, length);
+      /* png_ptr->crc now holds crc on the IDAT just written */
+      png_save_uint_32(buf, png_ptr->crc);
+      png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+   }
+#endif
 }
 
 /* write an IEND chunk */
@@ -1688,6 +1711,79 @@
 }
 #endif
 
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+void /* PRIVATE */
+png_write_aCTL(png_structp png_ptr,
+   png_uint_32 num_frames, png_uint_32 num_iterations)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+    PNG_aCTL;
+#endif
+    png_byte data[8];
+    
+    png_debug(1, "in png_write_aCTL\n");
+    
+    if (num_frames == 0)
+        png_error(png_ptr, "png_write_aCTL: invalid number of frames (0)");
+    if (num_frames > PNG_UINT_31_MAX)
+        png_error(png_ptr, "png_write_aCTL: invalid number of frames "
+                           "(> 2^31-1)");
+    if (num_iterations > PNG_UINT_31_MAX)
+        png_error(png_ptr, "png_write_aCTL: invalid number of iterations "
+                           "(> 2^31-1)");
+    
+    png_ptr->num_frames_expected = num_frames;
+    
+    png_save_uint_32(data, num_frames);
+    png_save_uint_32(data + 4, num_iterations);
+    
+    png_write_chunk(png_ptr, (png_bytep)png_aCTL, data, (png_size_t)8);
+}
+
+void /* PRIVATE */
+png_write_fCTL(png_structp png_ptr, png_uint_32 x_offset, png_uint_32 y_offset,
+    png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+    PNG_fCTL;
+#endif
+    png_byte data[17];
+    png_byte buf[4];
+    
+    png_debug(1, "in png_write_fCTL\n");
+    
+    if (render_op & 0xE0)
+        /* Bits 5 through 7 are reserved and must be set to zero (APNG spec) */
+        png_error(png_ptr, "png_write_fCTL: invalid render_op");
+    //!!?? some more error-checking on render_op's displose bits
+    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
+        png_error(png_ptr, 
+                    "png_write_fCTL: fCTL for the first frame with "
+                    "non-zero x_offset or y_offset not allowed");
+    if (x_offset > PNG_UINT_31_MAX)
+        png_error(png_ptr, "png_write_fCTL: invalid x_offset (> 2^31-1)");
+    if (y_offset > PNG_UINT_31_MAX)
+        png_error(png_ptr, "png_write_fCTL: invalid y_offset (> 2^31-1)");
+    
+    png_save_uint_32(buf, 17);
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, png_fCTL, 4);
+    
+    png_save_uint_32(data, png_ptr->num_frames_written);
+    png_save_uint_32(data + 4, x_offset);
+    png_save_uint_32(data + 8, y_offset);
+    png_save_uint_16(data + 12, delay_num);
+    png_save_uint_16(data + 14, delay_den);
+    data[16] = render_op;
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, data, 17);
+    
+    png_write_chunk(png_ptr, (png_bytep)png_fCTL, data, (png_size_t)17);
+    
+    png_save_uint_32(buf, png_ptr->crc);
+    png_ptr->aDAT_crc = crc32(png_ptr->aDAT_crc, buf, 4);
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+
 /* initializes the row writing capability of libpng */
 void /* PRIVATE */
 png_write_start_row(png_structp png_ptr)
@@ -1715,14 +1811,16 @@
       png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
 
    /* set up row buffer */
-   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+   if (png_ptr->row_buf == NULL)
+      png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
    png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
 
    /* set up filtering buffer, if using this filter */
    if (png_ptr->do_filter & PNG_FILTER_SUB)
    {
-      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
-         (png_ptr->rowbytes + 1));
+      if (png_ptr->sub_row == NULL)
+         png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+            (png_ptr->rowbytes + 1));
       png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
    }
 
@@ -1730,27 +1828,31 @@
    if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
    {
      /* set up previous row buffer */
-      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+      if (png_ptr->prev_row == NULL)
+         png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
       png_memset(png_ptr->prev_row, 0, buf_size);
 
       if (png_ptr->do_filter & PNG_FILTER_UP)
       {
-         png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
-            (png_ptr->rowbytes + 1));
+         if (png_ptr->up_row == NULL)
+            png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+               (png_ptr->rowbytes + 1));
          png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
       }
 
       if (png_ptr->do_filter & PNG_FILTER_AVG)
       {
-         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
-            (png_ptr->rowbytes + 1));
+         if (png_ptr->avg_row == NULL)
+            png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+               (png_ptr->rowbytes + 1));
          png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
       }
 
       if (png_ptr->do_filter & PNG_FILTER_PAETH)
       {
-         png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
-            (png_ptr->rowbytes + 1));
+         if (png_ptr->paeth_row == NULL)
+            png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
+               (png_ptr->rowbytes + 1));
          png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
       }
    }
@@ -2742,4 +2844,13 @@
    }
 #endif
 }
+
+#if defined(PNG_WRITE_APNG_SUPPORTED)
+void PNGAPI
+png_write_reset(png_structp png_ptr)
+{
+    png_ptr->row_number = 0;
+    png_ptr->pass = 0;
+}
+#endif
 #endif /* PNG_WRITE_SUPPORTED */
Index: libpng-1.2.10/pngconf.h
===================================================================
--- libpng-1.2.10/pngconf.h	(révision 50)
+++ libpng-1.2.10/pngconf.h	(copie de travail)
@@ -894,6 +894,10 @@
 #  define PNG_READ_zTXt_SUPPORTED
 #  define PNG_zTXt_SUPPORTED
 #endif
+#ifndef PNG_NO_READ_APNG
+#  define PNG_READ_APNG_SUPPORTED
+#  define PNG_APNG_SUPPORTED
+#endif
 #ifndef PNG_NO_READ_UNKNOWN_CHUNKS
 #  define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
 #  ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
@@ -1036,6 +1040,12 @@
 #    define PNG_zTXt_SUPPORTED
 #  endif
 #endif
+#ifndef PNG_NO_WRITE_APNG
+#  define PNG_WRITE_APNG_SUPPORTED
+#  ifndef PNG_APNG_SUPPORTED
+#    define PNG_APNG_SUPPORTED
+#  endif
+#endif
 #ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
 #  define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
 #  ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
