Merge branch 'upstream' into tizen 65/302465/1 accepted/tizen_unified accepted/tizen_unified_riscv tizen accepted/tizen/unified/20231228.165752 accepted/tizen/unified/riscv/20240103.054654
authorJiyong <jiyong.min@samsung.com>
Thu, 7 Dec 2023 05:47:53 +0000 (14:47 +0900)
committerJiyong <jiyong.min@samsung.com>
Thu, 7 Dec 2023 07:03:45 +0000 (16:03 +0900)
Change-Id: I6475d1aa957032f907b9d81f0d83ee6b3140797e

1  2 
packaging/libpng.spec
png.c
png.h
pngget.c
pngpriv.h
pngset.c
pngtest.c
pngwrite.c
scripts/pnglibconf.dfa

diff --combined packaging/libpng.spec
index df06560,0000000..4d79b1f
mode 100644,000000..100644
--- /dev/null
@@@ -1,73 -1,0 +1,73 @@@
- Version:        1.6.39
 +Name:           libpng
++Version:        1.6.40
 +Release:        0
 +License:        Libpng
 +Summary:        A library of functions for manipulating PNG image format files
 +Url:            http://www.libpng.org/pub/png/libpng.html
 +Group:          System/Libraries
 +Source:         %{name}-%{version}.tar.bz2
 +Source1001:     libpng.manifest
 +
 +BuildRequires:  cmake
 +BuildRequires:  zlib-devel
 +
 +%description
 +The libpng package contains a library of functions for creating and
 +manipulating PNG (Portable Network Graphics) image format files.  PNG
 +is a bit-mapped graphics format similar to the GIF format.  PNG was
 +created to replace the GIF format, since GIF uses a patented data
 +compression algorithm.
 +
 +Libpng should be installed if you need to manipulate PNG format image
 +files.
 +
 +%package devel
 +Summary:        Development tools for programs to manipulate PNG image format files
 +Group:          Development/Libraries
 +Requires:       %{name} = %{version}-%{release}
 +Requires:       zlib-devel
 +
 +%description devel
 +The libpng-devel package contains header files and documentation necessary
 +for developing programs using the PNG (Portable Network Graphics) library.
 +
 +%prep
 +%setup -q
 +cp %{SOURCE1001} .
 +
 +%build
 +%ifarch %{arm}
 +CFLAGS+=" -D_ARCH_ARM_ -mfpu=neon"
 +%endif
 +
 +%cmake . -DPNG_STATIC=OFF \
 +         -DSKIP_INSTALL_PROGRAMS=ON \
 +         -DSKIP_INSTALL_EXPORT=ON \
 +%ifarch %{arm}
 +         -DPNG_ARM_NEON=on \
 +%else
 +         -DPNG_ARM_NEON=off \
 +%endif
 +         %{?ubsan: -DPNG_ARM_NEON=off}
 +
 +make %{?jobs:-j%jobs}
 +
 +%install
 +%make_install
 +rm -rf %{buildroot}/usr/share/man
 +
 +%post -p /sbin/ldconfig
 +%postun -p /sbin/ldconfig
 +
 +%files
 +%manifest %{name}.manifest
 +%license LICENSE
 +%{_libdir}/libpng*.so.*
 +
 +%files devel
 +%manifest %{name}.manifest
 +%{_bindir}/*
 +%{_includedir}/*
 +%{_libdir}/libpng*.so
 +%{_libdir}/pkgconfig/*
 +
diff --combined png.c
index 4f3e8bb,d6471b0..d6471b0
mode 100755,100644..100755
--- 1/png.c
--- 2/png.c
+++ b/png.c
@@@ -1,7 -1,7 +1,7 @@@
  
  /* png.c - location for general purpose libpng functions
   *
-  * Copyright (c) 2018-2022 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@@ -14,7 -14,7 +14,7 @@@
  #include "pngpriv.h"
  
  /* Generate a compiler error if there is an old png.h in the search path. */
- typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
+ typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;
  
  #ifdef __GNUC__
  /* The version tests may need to be added to, but the problem warning has
@@@ -815,8 -815,8 +815,8 @@@ png_get_copyright(png_const_structrp pn
     return PNG_STRING_COPYRIGHT
  #else
     return PNG_STRING_NEWLINE \
-       "libpng version 1.6.39" PNG_STRING_NEWLINE \
-       "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
+       "libpng version 1.6.40" PNG_STRING_NEWLINE \
+       "Copyright (c) 2018-2023 Cosmin Truta" PNG_STRING_NEWLINE \
        "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
        PNG_STRING_NEWLINE \
        "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
diff --combined png.h
--- 1/png.h
--- 2/png.h
+++ b/png.h
@@@ -1,9 -1,9 +1,9 @@@
  
  /* png.h - header file for PNG reference library
   *
-  * libpng version 1.6.39 - November 20, 2022
+  * libpng version 1.6.40
   *
-  * Copyright (c) 2018-2022 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@@ -15,7 -15,7 +15,7 @@@
   *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
   *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
   *     Glenn Randers-Pehrson
-  *   libpng versions 1.6.36, December 2018, through 1.6.39, November 2022:
+  *   libpng versions 1.6.36, December 2018, through 1.6.40, June 2023:
   *     Cosmin Truta
   *   See also "Contributing Authors", below.
   */
@@@ -27,8 -27,8 +27,8 @@@
   * PNG Reference Library License version 2
   * ---------------------------------------
   *
-  *  * Copyright (c) 1995-2022 The PNG Reference Library Authors.
-  *  * Copyright (c) 2018-2022 Cosmin Truta.
+  *  * Copyright (c) 1995-2023 The PNG Reference Library Authors.
+  *  * Copyright (c) 2018-2023 Cosmin Truta.
   *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
   *  * Copyright (c) 1996-1997 Andreas Dilger.
   *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
   *    ...
   *    1.5.30                  15    10530  15.so.15.30[.0]
   *    ...
-  *    1.6.39                  16    10639  16.so.16.39[.0]
+  *    1.6.40                  16    10640  16.so.16.40[.0]
   *
   *    Henceforth the source version will match the shared-library major and
   *    minor numbers; the shared-library major version number will be used for
   */
  
  /* Version information for png.h - this should match the version in png.c */
- #define PNG_LIBPNG_VER_STRING "1.6.39"
- #define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n"
+ #define PNG_LIBPNG_VER_STRING "1.6.40"
+ #define PNG_HEADER_VERSION_STRING " libpng version 1.6.40 - June 21, 2023\n"
  
  #define PNG_LIBPNG_VER_SONUM   16
  #define PNG_LIBPNG_VER_DLLNUM  16
  /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
  #define PNG_LIBPNG_VER_MAJOR   1
  #define PNG_LIBPNG_VER_MINOR   6
- #define PNG_LIBPNG_VER_RELEASE 39
+ #define PNG_LIBPNG_VER_RELEASE 40
  
  /* This should be zero for a public release, or non-zero for a
   * development version.  [Deprecated]
   * From version 1.0.1 it is:
   * XXYYZZ, where XX=major, YY=minor, ZZ=release
   */
- #define PNG_LIBPNG_VER 10639 /* 1.6.39 */
+ #define PNG_LIBPNG_VER 10640 /* 1.6.40 */
  
  /* Library configuration: these options cannot be changed after
   * the library has been built.
  #   include "pnglibconf.h"
  #endif
  
 +#define PNG_APNG_SUPPORTED
 +#define PNG_READ_APNG_SUPPORTED
 +#define PNG_WRITE_APNG_SUPPORTED
 +
  #ifndef PNG_VERSION_INFO_ONLY
  /* Machine specific configuration. */
  #  include "pngconf.h"
@@@ -429,21 -425,10 +429,21 @@@ extern "C" 
   * See pngconf.h for base types that vary by machine/system
   */
  
 +#ifdef PNG_APNG_SUPPORTED
 +/* dispose_op flags from inside fcTL */
 +#define PNG_DISPOSE_OP_NONE        0x00U
 +#define PNG_DISPOSE_OP_BACKGROUND  0x01U
 +#define PNG_DISPOSE_OP_PREVIOUS    0x02U
 +
 +/* blend_op flags from inside fcTL */
 +#define PNG_BLEND_OP_SOURCE        0x00U
 +#define PNG_BLEND_OP_OVER          0x01U
 +#endif /* PNG_APNG_SUPPORTED */
 +
  /* This triggers a compiler error in png.c, if png.c and png.h
   * do not agree upon the version number.
   */
- typedef char* png_libpng_version_1_6_39;
+ typedef char* png_libpng_version_1_6_40;
  
  /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
   *
@@@ -591,32 -576,6 +591,32 @@@ typedef struct png_text_struc
     png_charp lang_key;     /* keyword translated UTF-8 string, 0 or more
                                chars or a NULL pointer */
  } png_text;
 +
 +/* VD_TIZEN_ONLY */
 +/* Adding PNG Color pick feature.*/
 +typedef enum _Png_Color_Pick_Region_
 +{
 +        PNG_COLORPICK_TOP = 0,
 +        PNG_COLORPICK_MIDDLE,
 +        PNG_COLORPICK_BOTTOM,
 +}PngColorPickRegion;
 +
 +struct _Png_Color_Pick_Struct_
 +{
 +      unsigned int sumR;
 +      unsigned int sumG;
 +      unsigned int sumB;
 +      int enable;
 +      int     perc;
 +      int x1;
 +      int y1;
 +      int x2;
 +      int y2;
 +      PngColorPickRegion region;
 +};
 +typedef struct _Png_Color_Pick_Struct_ PngPickColor; /* TODO : PngPickColor will be changed to PngColorPick in future*/
 +/* VD_TIZEN_ONLY_END */
 +
  typedef png_text * png_textp;
  typedef const png_text * png_const_textp;
  typedef png_text * * png_textpp;
@@@ -787,10 -746,6 +787,10 @@@ typedef png_unknown_chunk * * png_unkno
  #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
  #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
  #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
 +#ifdef PNG_APNG_SUPPORTED
 +#define PNG_INFO_acTL 0x20000U
 +#define PNG_INFO_fcTL 0x40000U
 +#endif
  
  /* This is used for the transformation routines, as some of them
   * change these values for the row.  It also should enable using
@@@ -828,10 -783,6 +828,10 @@@ typedef PNG_CALLBACK(void, *png_write_s
  #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
  typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
 +#ifdef PNG_APNG_SUPPORTED
 +typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
 +    png_uint_32));
 +#endif
  
  /* The following callback receives png_uint_32 row_number, int pass for the
   * png_bytep data of the row.  When transforming an interlaced image the
@@@ -3275,90 -3226,6 +3275,90 @@@ PNG_EXPORT(244, int, png_set_option, (p
  /*******************************************************************************
   *  END OF HARDWARE AND SOFTWARE OPTIONS
   ******************************************************************************/
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
 +   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
 +
 +PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
 +   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
 +
 +PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
 +   png_infop info_ptr));
 +
 +PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
 +   png_infop info_ptr));
 +
 +PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
 +   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
 +   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
 +   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
 +   png_byte *blend_op));
 +
 +PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
 +   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
 +   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
 +   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 +   png_byte blend_op));
 +
 +PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
 +   (png_structp png_ptr, png_infop info_ptr));
 +PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
 +   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
 +
 +#ifdef PNG_READ_APNG_SUPPORTED
 +PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
 +   png_infop info_ptr));
 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 +PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
 +   png_progressive_frame_ptr frame_info_fn,
 +   png_progressive_frame_ptr frame_end_fn));
 +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 +#endif /* PNG_READ_APNG_SUPPORTED */
 +
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
 +   png_infop info_ptr, png_bytepp row_pointers,
 +   png_uint_32 width, png_uint_32 height,
 +   png_uint_32 x_offset, png_uint_32 y_offset,
 +   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 +   png_byte blend_op));
 +
 +PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
 +   png_infop info_ptr));
 +#endif /* PNG_WRITE_APNG_SUPPORTED */
 +#endif /* PNG_APNG_SUPPORTED */
 +
 +#ifndef __TIZEN__
 +#define __TIZEN__
 +#endif
 +#ifdef __TIZEN__
 +/* Read the whole image into memory at once. */
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_EXPORT(270, void, png_read_image_with_pick_color, (png_structp png_ptr,
 +   png_bytepp image,
 +   PngPickColor *pickcolor));
 +#else
 +PNG_EXPORT(250, void, png_read_image_with_pick_color, (png_structp png_ptr,
 +   png_bytepp image,
 +   PngPickColor *pickcolor));
 +#endif
 +#endif
  
  /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
   * defs, and in scripts/symbols.def.
   * one to use is one more than this.)
   */
  #ifdef PNG_EXPORT_LAST_ORDINAL
 +#ifdef __TIZEN__
 +#ifdef PNG_APNG_SUPPORTED
 +  PNG_EXPORT_LAST_ORDINAL(270);
 +#else
 +  PNG_EXPORT_LAST_ORDINAL(250);
 +#endif /* PNG_APNG_SUPPORTED */
 +#else
 +#ifdef PNG_APNG_SUPPORTED
 +  PNG_EXPORT_LAST_ORDINAL(269);
 +#else
    PNG_EXPORT_LAST_ORDINAL(249);
 +#endif /* PNG_APNG_SUPPORTED */
 +#endif /* __TIZEN__ */
  #endif
  
  #ifdef __cplusplus
diff --combined pngget.c
+++ b/pngget.c
@@@ -1,7 -1,7 +1,7 @@@
  
  /* pngget.c - retrieval of values from info struct
   *
-  * Copyright (c) 2018 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@@ -21,7 -21,18 +21,18 @@@ png_get_valid(png_const_structrp png_pt
      png_uint_32 flag)
  {
     if (png_ptr != NULL && info_ptr != NULL)
+    {
+ #ifdef PNG_READ_tRNS_SUPPORTED
+       /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the
+        * 'valid' flag for the detection of duplicate chunks. Do not report a
+        * valid tRNS chunk in this case.
+        */
+       if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
+          return(0);
+ #endif
        return(info_ptr->valid & flag);
+    }
  
     return(0);
  }
@@@ -1246,166 -1257,4 +1257,166 @@@ png_get_palette_max(png_const_structp p
  #  endif
  #endif
  
 +#ifdef 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_plays)
 +{
 +    png_debug1(1, "in %s retrieval function", "acTL");
 +
 +    if (png_ptr != NULL && info_ptr != NULL &&
 +        (info_ptr->valid & PNG_INFO_acTL) &&
 +        num_frames != NULL && num_plays != NULL)
 +    {
 +        *num_frames = info_ptr->num_frames;
 +        *num_plays = info_ptr->num_plays;
 +        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()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->num_frames);
 +    return (0);
 +}
 +
 +png_uint_32 PNGAPI
 +png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_get_num_plays()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->num_plays);
 +    return (0);
 +}
 +
 +png_uint_32 PNGAPI
 +png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
 +             png_uint_32 *width, png_uint_32 *height,
 +             png_uint_32 *x_offset, png_uint_32 *y_offset,
 +             png_uint_16 *delay_num, png_uint_16 *delay_den,
 +             png_byte *dispose_op, png_byte *blend_op)
 +{
 +    png_debug1(1, "in %s retrieval function", "fcTL");
 +
 +    if (png_ptr != NULL && info_ptr != NULL &&
 +        (info_ptr->valid & PNG_INFO_fcTL) &&
 +        width != NULL && height != NULL &&
 +        x_offset != NULL && y_offset != NULL &&
 +        delay_num != NULL && delay_den != NULL &&
 +        dispose_op != NULL && blend_op != NULL)
 +    {
 +        *width = info_ptr->next_frame_width;
 +        *height = info_ptr->next_frame_height;
 +        *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;
 +        *dispose_op = info_ptr->next_frame_dispose_op;
 +        *blend_op = info_ptr->next_frame_blend_op;
 +        return (1);
 +    }
 +
 +    return (0);
 +}
 +
 +png_uint_32 PNGAPI
 +png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_get_next_frame_width()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_width);
 +    return (0);
 +}
 +
 +png_uint_32 PNGAPI
 +png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_get_next_frame_height()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_height);
 +    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()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_x_offset);
 +    return (0);
 +}
 +
 +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()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_y_offset);
 +    return (0);
 +}
 +
 +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()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_delay_num);
 +    return (0);
 +}
 +
 +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()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_delay_den);
 +    return (0);
 +}
 +
 +png_byte PNGAPI
 +png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_get_next_frame_dispose_op()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_dispose_op);
 +    return (0);
 +}
 +
 +png_byte PNGAPI
 +png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_get_next_frame_blend_op()");
 +
 +    if (png_ptr != NULL && info_ptr != NULL)
 +        return (info_ptr->next_frame_blend_op);
 +    return (0);
 +}
 +
 +png_byte PNGAPI
 +png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_first_frame_is_hidden()");
 +
 +    if (png_ptr != NULL)
 +       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
 +
 +    PNG_UNUSED(info_ptr)
 +
 +    return 0;
 +}
 +#endif /* PNG_APNG_SUPPORTED */
  #endif /* READ || WRITE */
diff --combined pngpriv.h
+++ b/pngpriv.h
@@@ -1,7 -1,7 +1,7 @@@
  
  /* pngpriv.h - private declarations for use inside libpng
   *
-  * Copyright (c) 2018-2022 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
  #define PNG_BACKGROUND_IS_GRAY     0x800U
  #define PNG_HAVE_PNG_SIGNATURE    0x1000U
  #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
-                    /*             0x4000U (unused) */
+ #define PNG_WROTE_eXIf            0x4000U
  #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
 +#ifdef PNG_APNG_SUPPORTED
 +#define PNG_HAVE_acTL            0x10000U
 +#define PNG_HAVE_fcTL            0x20000U
 +#endif
  
  /* Flags for the transformations the PNG library does on the image data */
  #define PNG_BGR                 0x0001U
  #define png_tRNS PNG_U32(116,  82,  78,  83)
  #define png_zTXt PNG_U32(122,  84,  88, 116)
  
 +#ifdef PNG_APNG_SUPPORTED
 +#define png_acTL PNG_U32( 97,  99,  84,  76)
 +#define png_fcTL PNG_U32(102,  99,  84,  76)
 +#define png_fdAT PNG_U32(102, 100,  65,  84)
 +
 +/* For png_struct.apng_flags: */
 +#define PNG_FIRST_FRAME_HIDDEN       0x0001U
 +#define PNG_APNG_APP                 0x0002U
 +#endif
 +
  /* The following will work on (signed char*) strings, whereas the get_uint_32
   * macro will fail on top-bit-set values because of the sign extension.
   */
@@@ -1649,47 -1635,6 +1649,47 @@@ PNG_INTERNAL_FUNCTION(void,png_colorspa
      */
  #endif
  
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
 +   png_uint_32 width, png_uint_32 height,
 +   png_uint_32 x_offset, png_uint_32 y_offset,
 +   png_uint_16 delay_num, png_uint_16 delay_den,
 +   png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
 +
 +#ifdef PNG_READ_APNG_SUPPORTED
 +PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
 +   png_uint_32 length),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
 +   png_uint_32 length),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
 +   png_uint_32 length),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
 +   png_uint_32 length),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
 +   png_infop info_ptr),PNG_EMPTY);
 +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 +PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
 +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 +#endif /* PNG_READ_APNG_SUPPORTED */
 +
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
 +   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
 +   png_uint_32 width, png_uint_32 height,
 +   png_uint_32 x_offset, png_uint_32 y_offset,
 +   png_uint_16 delay_num, png_uint_16 delay_den,
 +   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
 +   png_const_bytep data, png_size_t length),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
 +PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
 +   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
 +#endif /* PNG_WRITE_APNG_SUPPORTED */
 +#endif /* PNG_APNG_SUPPORTED */
 +
  /* Added at libpng version 1.4.0 */
  #ifdef PNG_COLORSPACE_SUPPORTED
  /* These internal functions are for maintaining the colorspace structure within
@@@ -1965,7 -1910,7 +1965,7 @@@ PNG_INTERNAL_FUNCTION(void,png_ascii_fr
   */
  #define PNG_FP_INVALID  512  /* Available for callers as a distinct value */
  
- /* Result codes for the parser (boolean - true meants ok, false means
+ /* Result codes for the parser (boolean - true means ok, false means
   * not ok yet.)
   */
  #define PNG_FP_MAYBE      0  /* The number may be valid in the future */
diff --combined pngset.c
+++ b/pngset.c
@@@ -1,7 -1,7 +1,7 @@@
  
  /* pngset.c - storage of image information into info struct
   *
-  * Copyright (c) 2018-2022 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@@ -137,46 -137,40 +137,40 @@@ png_set_cHRM_XYZ(png_const_structrp png
  #ifdef PNG_eXIf_SUPPORTED
  void PNGAPI
  png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
-     png_bytep eXIf_buf)
+     png_bytep exif)
  {
    png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
    PNG_UNUSED(info_ptr)
-   PNG_UNUSED(eXIf_buf)
+   PNG_UNUSED(exif)
  }
  
  void PNGAPI
  png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
-     png_uint_32 num_exif, png_bytep eXIf_buf)
+     png_uint_32 num_exif, png_bytep exif)
  {
-    int i;
+    png_bytep new_exif;
  
     png_debug1(1, "in %s storage function", "eXIf");
  
-    if (png_ptr == NULL || info_ptr == NULL)
+    if (png_ptr == NULL || info_ptr == NULL ||
+        (png_ptr->mode & PNG_WROTE_eXIf) != 0)
        return;
  
-    if (info_ptr->exif)
-    {
-       png_free(png_ptr, info_ptr->exif);
-       info_ptr->exif = NULL;
-    }
+    new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
  
-    info_ptr->num_exif = num_exif;
-    info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
-        info_ptr->num_exif));
-    if (info_ptr->exif == NULL)
+    if (new_exif == NULL)
     {
        png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
        return;
     }
  
-    info_ptr->free_me |= PNG_FREE_EXIF;
+    memcpy(new_exif, exif, (size_t)num_exif);
  
-    for (i = 0; i < (int) info_ptr->num_exif; i++)
-       info_ptr->exif[i] = eXIf_buf[i];
+    png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
  
+    info_ptr->num_exif = num_exif;
+    info_ptr->exif = new_exif;
+    info_ptr->free_me |= PNG_FREE_EXIF;
     info_ptr->valid |= PNG_INFO_eXIf;
  }
  #endif /* eXIf */
@@@ -237,15 -231,13 +231,13 @@@ png_set_hIST(png_const_structrp png_ptr
     if (info_ptr->hist == NULL)
     {
        png_warning(png_ptr, "Insufficient memory for hIST chunk data");
        return;
     }
  
-    info_ptr->free_me |= PNG_FREE_HIST;
     for (i = 0; i < info_ptr->num_palette; i++)
        info_ptr->hist[i] = hist[i];
  
+    info_ptr->free_me |= PNG_FREE_HIST;
     info_ptr->valid |= PNG_INFO_hIST;
  }
  #endif
@@@ -288,11 -280,6 +280,11 @@@ png_set_IHDR(png_const_structrp png_ptr
     info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
  
     info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
 +
 +#ifdef PNG_APNG_SUPPORTED
 +   /* for non-animated png. this may be overwritten from an acTL chunk later */
 +   info_ptr->num_frames = 1;
 +#endif
  }
  
  #ifdef PNG_oFFs_SUPPORTED
@@@ -372,6 -359,8 +364,8 @@@ png_set_pCAL(png_const_structrp png_ptr
  
     memcpy(info_ptr->pcal_purpose, purpose, length);
  
+    info_ptr->free_me |= PNG_FREE_PCAL;
     png_debug(3, "storing X0, X1, type, and nparams in info");
     info_ptr->pcal_X0 = X0;
     info_ptr->pcal_X1 = X1;
     if (info_ptr->pcal_units == NULL)
     {
        png_warning(png_ptr, "Insufficient memory for pCAL units");
        return;
     }
  
     if (info_ptr->pcal_params == NULL)
     {
        png_warning(png_ptr, "Insufficient memory for pCAL params");
        return;
     }
  
        if (info_ptr->pcal_params[i] == NULL)
        {
           png_warning(png_ptr, "Insufficient memory for pCAL parameter");
           return;
        }
  
     }
  
     info_ptr->valid |= PNG_INFO_pCAL;
-    info_ptr->free_me |= PNG_FREE_PCAL;
  }
  #endif
  
@@@ -483,18 -468,17 +473,17 @@@ png_set_sCAL_s(png_const_structrp png_p
  
     if (info_ptr->scal_s_height == NULL)
     {
-       png_free (png_ptr, info_ptr->scal_s_width);
+       png_free(png_ptr, info_ptr->scal_s_width);
        info_ptr->scal_s_width = NULL;
  
        png_warning(png_ptr, "Memory allocation failed while processing sCAL");
        return;
     }
  
     memcpy(info_ptr->scal_s_height, sheight, lengthh);
  
-    info_ptr->valid |= PNG_INFO_sCAL;
     info_ptr->free_me |= PNG_FREE_SCAL;
+    info_ptr->valid |= PNG_INFO_sCAL;
  }
  
  #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@@ -630,11 -614,10 +619,10 @@@ png_set_PLTE(png_structrp png_ptr, png_
     if (num_palette > 0)
        memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
            (sizeof (png_color)));
     info_ptr->palette = png_ptr->palette;
     info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
     info_ptr->free_me |= PNG_FREE_PLTE;
     info_ptr->valid |= PNG_INFO_PLTE;
  }
  
@@@ -1025,8 -1008,8 +1013,8 @@@ png_set_tRNS(png_structrp png_ptr, png_
                png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
            memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
  
-           info_ptr->valid |= PNG_INFO_tRNS;
            info_ptr->free_me |= PNG_FREE_TRNS;
+           info_ptr->valid |= PNG_INFO_tRNS;
         }
         png_ptr->trans_alpha = info_ptr->trans_alpha;
     }
  
     if (num_trans != 0)
     {
-       info_ptr->valid |= PNG_INFO_tRNS;
        info_ptr->free_me |= PNG_FREE_TRNS;
+       info_ptr->valid |= PNG_INFO_tRNS;
     }
  }
  #endif
@@@ -1094,11 -1077,11 +1082,11 @@@ png_set_sPLT(png_const_structrp png_ptr
     {
        /* Out of memory or too many chunks */
        png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
        return;
     }
  
     png_free(png_ptr, info_ptr->splt_palettes);
     info_ptr->splt_palettes = np;
     info_ptr->free_me |= PNG_FREE_SPLT;
  
  }
  #endif /* sPLT */
  
 +#ifdef 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_plays)
 +{
 +    png_debug1(1, "in %s storage function", "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_plays > PNG_UINT_31_MAX)
 +    {
 +        png_warning(png_ptr,
 +                    "Ignoring attempt to set acTL with num_plays "
 +                    "> 2^31-1");
 +        return (0);
 +    }
 +
 +    info_ptr->num_frames = num_frames;
 +    info_ptr->num_plays = num_plays;
 +
 +    info_ptr->valid |= PNG_INFO_acTL;
 +
 +    return (1);
 +}
 +
 +/* delay_num and delay_den can hold any 16-bit values including zero */
 +png_uint_32 PNGAPI
 +png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
 +    png_uint_32 width, png_uint_32 height,
 +    png_uint_32 x_offset, png_uint_32 y_offset,
 +    png_uint_16 delay_num, png_uint_16 delay_den,
 +    png_byte dispose_op, png_byte blend_op)
 +{
 +    png_debug1(1, "in %s storage function", "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);
 +    }
 +
 +    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
 +                             delay_num, delay_den, dispose_op, blend_op);
 +
 +    if (blend_op == PNG_BLEND_OP_OVER)
 +    {
 +        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
 +            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
 +        {
 +          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
 +                               "and wasteful for opaque images, ignored");
 +          blend_op = PNG_BLEND_OP_SOURCE;
 +        }
 +    }
 +
 +    info_ptr->next_frame_width = width;
 +    info_ptr->next_frame_height = height;
 +    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_dispose_op = dispose_op;
 +    info_ptr->next_frame_blend_op = blend_op;
 +
 +    info_ptr->valid |= PNG_INFO_fcTL;
 +
 +    return (1);
 +}
 +
 +void /* PRIVATE */
 +png_ensure_fcTL_is_valid(png_structp png_ptr,
 +    png_uint_32 width, png_uint_32 height,
 +    png_uint_32 x_offset, png_uint_32 y_offset,
 +    png_uint_16 delay_num, png_uint_16 delay_den,
 +    png_byte dispose_op, png_byte blend_op)
 +{
 +    if (width == 0 || width > PNG_UINT_31_MAX)
 +        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
 +    if (height == 0 || height > PNG_UINT_31_MAX)
 +        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
 +    if (x_offset > PNG_UINT_31_MAX)
 +        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
 +    if (y_offset > PNG_UINT_31_MAX)
 +        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
 +    if (width + x_offset > png_ptr->first_frame_width ||
 +        height + y_offset > png_ptr->first_frame_height)
 +        png_error(png_ptr, "dimensions of a frame are greater than"
 +                           "the ones in IHDR");
 +
 +    if (dispose_op != PNG_DISPOSE_OP_NONE &&
 +        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
 +        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
 +        png_error(png_ptr, "invalid dispose_op in fcTL");
 +
 +    if (blend_op != PNG_BLEND_OP_SOURCE &&
 +        blend_op != PNG_BLEND_OP_OVER)
 +        png_error(png_ptr, "invalid blend_op in fcTL");
 +
 +    PNG_UNUSED(delay_num)
 +    PNG_UNUSED(delay_den)
 +}
 +
 +png_uint_32 PNGAPI
 +png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
 +                              png_byte is_hidden)
 +{
 +    png_debug(1, "in png_first_frame_is_hidden()");
 +
 +    if (png_ptr == NULL)
 +        return 0;
 +
 +    if (is_hidden)
 +        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
 +    else
 +        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
 +
 +    PNG_UNUSED(info_ptr)
 +
 +    return 1;
 +}
 +#endif /* PNG_APNG_SUPPORTED */
 +
  #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  static png_byte
  check_location(png_const_structrp png_ptr, int location)
@@@ -1393,11 -1235,11 +1381,11 @@@ png_set_unknown_chunks(png_const_struct
     {
        png_chunk_report(png_ptr, "too many unknown chunks",
            PNG_CHUNK_WRITE_ERROR);
        return;
     }
  
     png_free(png_ptr, info_ptr->unknown_chunks);
     info_ptr->unknown_chunks = np; /* safe because it is initialized */
     info_ptr->free_me |= PNG_FREE_UNKN;
  
diff --combined pngtest.c
+++ b/pngtest.c
@@@ -875,10 -875,6 +875,10 @@@ test_one_file(const char *inname, cons
     volatile int num_passes;
     int pass;
     int bit_depth, color_type;
 +#ifdef PNG_APNG_SUPPORTED
 +   png_uint_32 num_frames;
 +   png_uint_32 num_plays;
 +#endif
  
     row_buf = NULL;
     error_parameters.file_name = inname;
        }
     }
  #endif
 +
 +#ifdef PNG_APNG_SUPPORTED
 +   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 +   {
 +      if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
 +      {
 +         png_byte is_hidden;
 +         pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
 +                    num_frames, num_plays);
 +         png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
 +         is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
 +         png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
 +      }
 +   }
 +#endif
 +
  #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
     {
        png_unknown_chunkp unknowns;
     t_misc += (t_stop - t_start);
     t_start = t_stop;
  #endif
 +#ifdef PNG_APNG_SUPPORTED
 +   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 +   {
 +      png_uint_32 frame;
 +      for (frame = 0; frame < num_frames; frame++)
 +      {
 +         png_uint_32 frame_width;
 +         png_uint_32 frame_height;
 +         png_uint_32 x_offset;
 +         png_uint_32 y_offset;
 +         png_uint_16 delay_num;
 +         png_uint_16 delay_den;
 +         png_byte dispose_op;
 +         png_byte blend_op;
 +         png_read_frame_head(read_ptr, read_info_ptr);
 +         if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
 +         {
 +            png_get_next_frame_fcTL(read_ptr, read_info_ptr,
 +                                    &frame_width, &frame_height,
 +                                    &x_offset, &y_offset,
 +                                    &delay_num, &delay_den,
 +                                    &dispose_op, &blend_op);
 +         }
 +         else
 +         {
 +            frame_width = width;
 +            frame_height = height;
 +            x_offset = 0;
 +            y_offset = 0;
 +            delay_num = 1;
 +            delay_den = 1;
 +            dispose_op = PNG_DISPOSE_OP_NONE;
 +            blend_op = PNG_BLEND_OP_SOURCE;
 +         }
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +         png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
 +                              frame_width, frame_height,
 +                              x_offset, y_offset,
 +                              delay_num, delay_den,
 +                              dispose_op, blend_op);
 +#endif
 +         for (pass = 0; pass < num_passes; pass++)
 +         {
 +#           ifdef calc_pass_height
 +               png_uint_32 pass_height;
 +
 +               if (num_passes == 7) /* interlaced */
 +               {
 +                  if (PNG_PASS_COLS(frame_width, pass) > 0)
 +                     pass_height = PNG_PASS_ROWS(frame_height, pass);
 +
 +                  else
 +                     pass_height = 0;
 +               }
 +
 +               else /* not interlaced */
 +                  pass_height = frame_height;
 +#           else
 +#              define pass_height frame_height
 +#           endif
 +
 +            pngtest_debug1("Writing row data for pass %d", pass);
 +            for (y = 0; y < pass_height; y++)
 +            {
 +#ifndef SINGLE_ROWBUF_ALLOC
 +               pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
 +
 +               row_buf = (png_bytep)png_malloc(read_ptr,
 +                  png_get_rowbytes(read_ptr, read_info_ptr));
 +
 +               pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
 +                  (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
 +
 +#endif /* !SINGLE_ROWBUF_ALLOC */
 +               png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
 +
 +#ifdef PNG_WRITE_SUPPORTED
 +#ifdef PNGTEST_TIMING
 +               t_stop = (float)clock();
 +               t_decode += (t_stop - t_start);
 +               t_start = t_stop;
 +#endif
 +               png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
 +#ifdef PNGTEST_TIMING
 +               t_stop = (float)clock();
 +               t_encode += (t_stop - t_start);
 +               t_start = t_stop;
 +#endif
 +#endif /* PNG_WRITE_SUPPORTED */
 +
 +#ifndef SINGLE_ROWBUF_ALLOC
 +               pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
 +               png_free(read_ptr, row_buf);
 +               row_buf = NULL;
 +#endif /* !SINGLE_ROWBUF_ALLOC */
 +            }
 +         }
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +         png_write_frame_tail(write_ptr, write_info_ptr);
 +#endif
 +      }
 +   }
 +   else
 +#endif
     for (pass = 0; pass < num_passes; pass++)
     {
  #     ifdef calc_pass_height
@@@ -2279,4 -2155,4 +2279,4 @@@ main(void
  #endif
  
  /* Generate a compiler error if there is an old png.h in the search path. */
- typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
+ typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;
diff --combined pngwrite.c
@@@ -1,7 -1,7 +1,7 @@@
  
  /* pngwrite.c - general routines to write a PNG file
   *
-  * Copyright (c) 2018-2022 Cosmin Truta
+  * Copyright (c) 2018-2023 Cosmin Truta
   * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
   * Copyright (c) 1996-1997 Andreas Dilger
   * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@@ -128,10 -128,6 +128,10 @@@ png_write_info_before_PLTE(png_structr
         * the application continues writing the PNG.  So check the 'invalid'
         * flag here too.
         */
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +      if (info_ptr->valid & PNG_INFO_acTL)
 +         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
 +#endif
  #ifdef PNG_GAMMA_SUPPORTED
  #  ifdef PNG_WRITE_gAMA_SUPPORTED
        if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
@@@ -243,7 -239,10 +243,10 @@@ png_write_info(png_structrp png_ptr, pn
  
  #ifdef PNG_WRITE_eXIf_SUPPORTED
     if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+    {
        png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+       png_ptr->mode |= PNG_WROTE_eXIf;
+    }
  #endif
  
  #ifdef PNG_WRITE_hIST_SUPPORTED
@@@ -374,11 -373,6 +377,11 @@@ png_write_end(png_structrp png_ptr, png
        png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
  #endif
  
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
 +      png_error(png_ptr, "Not enough frames written");
 +#endif
 +
     /* See if user wants us to write information chunks */
     if (info_ptr != NULL)
     {
  #endif
  
  #ifdef PNG_WRITE_eXIf_SUPPORTED
-    if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
-       png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+       if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
+           (png_ptr->mode & PNG_WROTE_eXIf) == 0)
+          png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
  #endif
  
  #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
@@@ -1039,38 -1034,10 +1043,38 @@@ png_set_filter(png_structrp png_ptr, in
           case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
  #endif /* WRITE_FILTER */
              /* FALLTHROUGH */
 +#ifdef __TIZEN__
 +            /* 'switch ~ case' is dead code.
 +             * If filters is #PNG_FILTER_VALUE_NONE, #PNG_FILTER_VALUE_SUB ...,
 +             * filter flag will be assigned to 'png_ptr->do_filter'. But
 +             * 'png_ptr->do_filter' is overwritten as 'filters' at below code.
 +             * Issue code(#1155) is 'png_ptr->do_filter = (png_byte)filters;'.
 +             * So the result of 'switch ~ case' has been lost at the line.
 +             * To keep the value of 'switch ~ case', we fixed it to apply
 +             * the result into 'filters'.
 +             * It will be updated into 'png_ptr->do_filter' at #1155 line.
 +             */
 +         case PNG_FILTER_VALUE_NONE:
 +            filters = PNG_FILTER_NONE; break;
 +#else
           case PNG_FILTER_VALUE_NONE:
              png_ptr->do_filter = PNG_FILTER_NONE; break;
 +#endif /* __TIZEN__ */
  
  #ifdef PNG_WRITE_FILTER_SUPPORTED
 +#ifdef __TIZEN__
 +         case PNG_FILTER_VALUE_SUB:
 +            filters = PNG_FILTER_SUB; break;
 +
 +         case PNG_FILTER_VALUE_UP:
 +            filters = PNG_FILTER_UP; break;
 +
 +         case PNG_FILTER_VALUE_AVG:
 +            filters = PNG_FILTER_AVG; break;
 +
 +         case PNG_FILTER_VALUE_PAETH:
 +            filters = PNG_FILTER_PAETH; break;
 +#else
           case PNG_FILTER_VALUE_SUB:
              png_ptr->do_filter = PNG_FILTER_SUB; break;
  
  
           case PNG_FILTER_VALUE_PAETH:
              png_ptr->do_filter = PNG_FILTER_PAETH; break;
 -
 +#endif /* __TIZEN__ */
           default:
              png_ptr->do_filter = (png_byte)filters; break;
  #else
@@@ -1508,43 -1475,6 +1512,43 @@@ png_write_png(png_structrp png_ptr, png
  }
  #endif
  
 +#ifdef 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 width, png_uint_32 height,
 +    png_uint_32 x_offset, png_uint_32 y_offset,
 +    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 +    png_byte blend_op)
 +{
 +    png_debug(1, "in png_write_frame_head");
 +
 +    /* there is a chance this has been set after png_write_info was called,
 +    * so it 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");
 +
 +    png_write_reset(png_ptr);
 +
 +    png_write_reinit(png_ptr, info_ptr, width, height);
 +
 +    if ( !(png_ptr->num_frames_written == 0 &&
 +           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
 +        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
 +                       delay_num, delay_den, dispose_op, blend_op);
 +
 +    PNG_UNUSED(row_pointers)
 +}
 +
 +void PNGAPI
 +png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
 +{
 +    png_debug(1, "in png_write_frame_tail");
 +
 +    png_ptr->num_frames_written++;
 +
 +    PNG_UNUSED(info_ptr)
 +}
 +#endif /* PNG_WRITE_APNG_SUPPORTED */
  
  #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
  /* Initialize the write structure - general purpose utility. */
diff --combined scripts/pnglibconf.dfa
@@@ -8,7 -8,7 +8,7 @@@ com pnglibconf.h - library build config
  com
  version
  com
- com Copyright (c) 2018-2022 Cosmin Truta
+ com Copyright (c) 2018-2023 Cosmin Truta
  com Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  com
  com This code is released under the libpng license.
@@@ -69,9 -69,9 +69,9 @@@ file pnglibconf.h scripts/pnglibconf.df
  #
  # 1) Create 'pngusr.h', enter the required private build information
  # detailed below and #define PNG_NO_<option> for each option you
- # don't want in that file in that file.  You can also turn on options
- # using PNG_<option>_SUPPORTED.  When you have finished rerun
- # configure and rebuild pnglibconf.h file with -DPNG_USER_CONFIG:
+ # don't want in that file.  You can also turn on options using
+ # PNG_<option>_SUPPORTED.  When you have finished, rerun configure
+ # and rebuild pnglibconf.h file with -DPNG_USER_CONFIG:
  #
  #  make clean
  #  CPPFLAGS='-DPNG_USER_CONFIG' ./configure
@@@ -328,7 -328,7 +328,7 @@@ option WRITE_INT_FUNCTIONS disable
  #     because it means that a failure to write an ancillary chunk can often be
  #     ignored.
  
 -option WARNINGS
 +option WARNINGS disabled
  option ERROR_TEXT
  option ERROR_NUMBERS disabled