texlive[74539] Build/source/libs: libpng 1.6.47

commits+kakuto at tug.org commits+kakuto at tug.org
Sat Mar 8 22:56:41 CET 2025


Revision: 74539
          https://tug.org/svn/texlive?view=revision&revision=74539
Author:   kakuto
Date:     2025-03-08 22:56:41 +0100 (Sat, 08 Mar 2025)
Log Message:
-----------
libpng 1.6.47

Modified Paths:
--------------
    trunk/Build/source/libs/README
    trunk/Build/source/libs/libpng/ChangeLog
    trunk/Build/source/libs/libpng/README
    trunk/Build/source/libs/libpng/TLpatches/ChangeLog
    trunk/Build/source/libs/libpng/TLpatches/TL-Changes
    trunk/Build/source/libs/libpng/configure
    trunk/Build/source/libs/libpng/libpng-src/ANNOUNCE
    trunk/Build/source/libs/libpng/libpng-src/CHANGES
    trunk/Build/source/libs/libpng/libpng-src/CMakeLists.txt
    trunk/Build/source/libs/libpng/libpng-src/README
    trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_cmake.sh
    trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_configure.sh
    trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_makefiles.sh
    trunk/Build/source/libs/libpng/libpng-src/ci/lib/ci.lib.sh
    trunk/Build/source/libs/libpng/libpng-src/configure.ac
    trunk/Build/source/libs/libpng/libpng-src/contrib/libtests/pngimage.c
    trunk/Build/source/libs/libpng/libpng-src/libpng-manual.txt
    trunk/Build/source/libs/libpng/libpng-src/libpng.3
    trunk/Build/source/libs/libpng/libpng-src/libpngpf.3
    trunk/Build/source/libs/libpng/libpng-src/png.5
    trunk/Build/source/libs/libpng/libpng-src/png.c
    trunk/Build/source/libs/libpng/libpng-src/png.h
    trunk/Build/source/libs/libpng/libpng-src/pngconf.h
    trunk/Build/source/libs/libpng/libpng-src/pngerror.c
    trunk/Build/source/libs/libpng/libpng-src/pngget.c
    trunk/Build/source/libs/libpng/libpng-src/pnginfo.h
    trunk/Build/source/libs/libpng/libpng-src/pnglibconf.h
    trunk/Build/source/libs/libpng/libpng-src/pngmem.c
    trunk/Build/source/libs/libpng/libpng-src/pngpread.c
    trunk/Build/source/libs/libpng/libpng-src/pngpriv.h
    trunk/Build/source/libs/libpng/libpng-src/pngread.c
    trunk/Build/source/libs/libpng/libpng-src/pngrtran.c
    trunk/Build/source/libs/libpng/libpng-src/pngrutil.c
    trunk/Build/source/libs/libpng/libpng-src/pngset.c
    trunk/Build/source/libs/libpng/libpng-src/pngstruct.h
    trunk/Build/source/libs/libpng/libpng-src/pngtest.c
    trunk/Build/source/libs/libpng/libpng-src/pngwrite.c
    trunk/Build/source/libs/libpng/libpng-src/pngwutil.c
    trunk/Build/source/libs/libpng/libpng-src/scripts/libpng-config-head.in
    trunk/Build/source/libs/libpng/libpng-src/scripts/libpng.pc.in
    trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.dfa
    trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.h.prebuilt
    trunk/Build/source/libs/libpng/version.ac

Added Paths:
-----------
    trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/fixed.dfa
    trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/float-fixed.dfa
    trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nocompile-limits.dfa
    trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nolimits.dfa

Modified: trunk/Build/source/libs/README
===================================================================
--- trunk/Build/source/libs/README	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/README	2025-03-08 21:56:41 UTC (rev 74539)
@@ -37,7 +37,7 @@
 libpaper 1.1.29 - checked 07jan24
   https://ftp.debian.org/debian/pool/main/libp/libpaper/
 
-libpng 1.6.46 - checked 25jan25
+libpng 1.6.47 - checked 09mar25
   https://sourceforge.net/projects/libpng/files/ - used by many
 
 lua 5.3.6 - checked 04oct20

Modified: trunk/Build/source/libs/libpng/ChangeLog
===================================================================
--- trunk/Build/source/libs/libpng/ChangeLog	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/ChangeLog	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,3 +1,8 @@
+2025-03-09 Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Import libpng-1.6.47.
+	* version.ac: Adjust.
+
 2025-01-25 Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Import libpng-1.6.46.

Modified: trunk/Build/source/libs/libpng/README
===================================================================
--- trunk/Build/source/libs/libpng/README	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/README	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,4 +1,4 @@
-	Building libpng-1.6.45 as part of the TL tree
+	Building libpng-1.6.47 as part of the TL tree
 	=============================================
 
 This directory libs/libpng/ uses a proxy Makefile.am to build the libpng library
@@ -14,4 +14,4 @@
 =============================
 
 2009-07-23	Peter Breitenlohner <peb at mppmu.mpg.de>
-2025-01-25	Akira Kakuto <kakuto at jcom.zaq.ne.jp>
+2025-03-09	Akira Kakuto <kakuto at jcom.zaq.ne.jp>

Modified: trunk/Build/source/libs/libpng/TLpatches/ChangeLog
===================================================================
--- trunk/Build/source/libs/libpng/TLpatches/ChangeLog	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/TLpatches/ChangeLog	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,3 +1,7 @@
+2025-03-09  Akira Kakuto <kakuto at jcom.zaq.ne.jp>
+
+	Import libpng-1.6.47.
+
 2025-01-25  Akira Kakuto <kakuto at jcom.zaq.ne.jp>
 
 	Import libpng-1.6.46.

Modified: trunk/Build/source/libs/libpng/TLpatches/TL-Changes
===================================================================
--- trunk/Build/source/libs/libpng/TLpatches/TL-Changes	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/TLpatches/TL-Changes	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,5 +1,5 @@
-Changes applied to the libpng-1.6.46/ tree as obtained from:
-	https://sourceforge.net/projects/libpng/files/libpng16/1.6.46/
+Changes applied to the libpng-1.6.47/ tree as obtained from:
+	https://sourceforge.net/projects/libpng/files/libpng16/1.6.47/
 
 Copied:
 	scripts/pnglibconf.h.prebuilt -> pnglibconf.h

Modified: trunk/Build/source/libs/libpng/configure
===================================================================
--- trunk/Build/source/libs/libpng/configure	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/configure	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for libpng (TeX Live) 1.6.46.
+# Generated by GNU Autoconf 2.72 for libpng (TeX Live) 1.6.47.
 #
 # Report bugs to <tex-k at tug.org>.
 #
@@ -604,8 +604,8 @@
 # Identity of this package.
 PACKAGE_NAME='libpng (TeX Live)'
 PACKAGE_TARNAME='libpng--tex-live-'
-PACKAGE_VERSION='1.6.46'
-PACKAGE_STRING='libpng (TeX Live) 1.6.46'
+PACKAGE_VERSION='1.6.47'
+PACKAGE_STRING='libpng (TeX Live) 1.6.47'
 PACKAGE_BUGREPORT='tex-k at tug.org'
 PACKAGE_URL=''
 
@@ -1342,7 +1342,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures libpng (TeX Live) 1.6.46 to adapt to many kinds of systems.
+'configure' configures libpng (TeX Live) 1.6.47 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1414,7 +1414,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libpng (TeX Live) 1.6.46:";;
+     short | recursive ) echo "Configuration of libpng (TeX Live) 1.6.47:";;
    esac
   cat <<\_ACEOF
 
@@ -1534,7 +1534,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libpng (TeX Live) configure 1.6.46
+libpng (TeX Live) configure 1.6.47
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -1861,7 +1861,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libpng (TeX Live) $as_me 1.6.46, which was
+It was created by libpng (TeX Live) $as_me 1.6.47, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4822,7 +4822,7 @@
 
 # Define the identity of the package.
  PACKAGE='libpng--tex-live-'
- VERSION='1.6.46'
+ VERSION='1.6.47'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -7996,7 +7996,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libpng (TeX Live) $as_me 1.6.46, which was
+This file was extended by libpng (TeX Live) $as_me 1.6.47, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8064,7 +8064,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-libpng (TeX Live) config.status 1.6.46
+libpng (TeX Live) config.status 1.6.47
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 

Modified: trunk/Build/source/libs/libpng/libpng-src/ANNOUNCE
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/ANNOUNCE	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/ANNOUNCE	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,5 +1,5 @@
-libpng 1.6.46 - January 23, 2025
-================================
+libpng 1.6.47 - February 18, 2025
+=================================
 
 This is a public release of libpng, intended for use in production code.
 
@@ -9,13 +9,13 @@
 
 Source files with LF line endings (for Unix/Linux):
 
- * libpng-1.6.46.tar.xz (LZMA-compressed, recommended)
- * libpng-1.6.46.tar.gz (deflate-compressed)
+ * libpng-1.6.47.tar.xz (LZMA-compressed, recommended)
+ * libpng-1.6.47.tar.gz (deflate-compressed)
 
 Source files with CRLF line endings (for Windows):
 
- * lpng1646.7z (LZMA-compressed, recommended)
- * lpng1646.zip (deflate-compressed)
+ * lpng1647.7z (LZMA-compressed, recommended)
+ * lpng1647.zip (deflate-compressed)
 
 Other information:
 
@@ -25,17 +25,19 @@
  * TRADEMARK.md
 
 
-Changes from version 1.6.45 to version 1.6.46
+Changes from version 1.6.46 to version 1.6.47
 ---------------------------------------------
 
- * Added support for the mDCV and cLLI chunks.
+ * Modified the behaviour of colorspace chunks in order to adhere
+   to the new precedence rules formulated in the latest draft of
+   the PNG Specification.
    (Contributed by John Bowler)
- * Fixed a build issue affecting C89 compilers.
-   This was a regression introduced in libpng-1.6.45.
-   (Contributed by John Bowler)
- * Added makefile.c89, specifically for testing C89 compilers.
- * Cleaned up contrib/pngminus: corrected an old typo, removed an old
-   workaround, and updated the CMake file.
+ * Fixed a latent bug in `png_write_iCCP`.
+   This would have been a read-beyond-end-of-malloc vulnerability,
+   introduced early in the libpng-1.6.0 development, yet (fortunately!)
+   it was inaccessible before the above-mentioned modification of the
+   colorspace precedence rules, due to pre-existing colorspace checks.
+   (Reported by Bob Friesenhahn; fixed by John Bowler)
 
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.

Modified: trunk/Build/source/libs/libpng/libpng-src/CHANGES
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/CHANGES	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/CHANGES	2025-03-08 21:56:41 UTC (rev 74539)
@@ -6239,6 +6239,18 @@
   Cleaned up contrib/pngminus: corrected an old typo, removed an old
     workaround, and updated the CMake file.
 
+Version 1.6.47 [February 18, 2025]
+  Modified the behaviour of colorspace chunks in order to adhere
+    to the new precedence rules formulated in the latest draft of
+    the PNG Specification.
+    (Contributed by John Bowler)
+  Fixed a latent bug in `png_write_iCCP`.
+    This would have been a read-beyond-end-of-malloc vulnerability,
+    introduced early in the libpng-1.6.0 development, yet (fortunately!)
+    it was inaccessible before the above-mentioned modification of the
+    colorspace precedence rules, due to pre-existing colorspace checks.
+    (Reported by Bob Friesenhahn; fixed by John Bowler)
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement

Modified: trunk/Build/source/libs/libpng/libpng-src/CMakeLists.txt
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/CMakeLists.txt	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/CMakeLists.txt	2025-03-08 21:56:41 UTC (rev 74539)
@@ -18,7 +18,7 @@
 
 set(PNGLIB_MAJOR 1)
 set(PNGLIB_MINOR 6)
-set(PNGLIB_REVISION 46)
+set(PNGLIB_REVISION 47)
 set(PNGLIB_SUBREVISION 0)
 #set(PNGLIB_SUBREVISION "git")
 set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_REVISION})

Modified: trunk/Build/source/libs/libpng/libpng-src/README
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/README	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/README	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,4 +1,4 @@
-README for libpng version 1.6.46
+README for libpng version 1.6.47
 ================================
 
 See the note about version numbers near the top of `png.h`.

Modified: trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_cmake.sh
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_cmake.sh	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_cmake.sh	2025-03-08 21:56:41 UTC (rev 74539)
@@ -64,6 +64,7 @@
     ci_info "environment option: \$CI_RANLIB: '$CI_RANLIB'"
     ci_info "environment option: \$CI_SANITIZERS: '$CI_SANITIZERS'"
     ci_info "environment option: \$CI_FORCE: '$CI_FORCE'"
+    ci_info "environment option: \$CI_NO_BUILD: '$CI_NO_BUILD'"
     ci_info "environment option: \$CI_NO_TEST: '$CI_NO_TEST'"
     ci_info "environment option: \$CI_NO_INSTALL: '$CI_NO_INSTALL'"
     ci_info "environment option: \$CI_NO_CLEAN: '$CI_NO_CLEAN'"
@@ -148,10 +149,12 @@
                          -S . \
                          -DCMAKE_INSTALL_PREFIX="$CI_INSTALL_DIR" \
                          "${all_cmake_vars[@]}"
-    # Spawn "cmake --build ...".
-    ci_spawn "$CI_CMAKE" --build "$CI_BUILD_DIR" \
-                         --config "$CI_CMAKE_BUILD_TYPE" \
-                         "${all_cmake_build_flags[@]}"
+    ci_expr $((CI_NO_BUILD)) || {
+        # Spawn "cmake --build ...".
+        ci_spawn "$CI_CMAKE" --build "$CI_BUILD_DIR" \
+                             --config "$CI_CMAKE_BUILD_TYPE" \
+                             "${all_cmake_build_flags[@]}"
+    }
     ci_expr $((CI_NO_TEST)) || {
         # Spawn "ctest" if testing is not disabled.
         ci_spawn pushd "$CI_BUILD_DIR"

Modified: trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_configure.sh
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_configure.sh	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_configure.sh	2025-03-08 21:56:41 UTC (rev 74539)
@@ -58,6 +58,7 @@
     ci_info "environment option: \$CI_LD_FLAGS: '$CI_LD_FLAGS'"
     ci_info "environment option: \$CI_SANITIZERS: '$CI_SANITIZERS'"
     ci_info "environment option: \$CI_FORCE: '$CI_FORCE'"
+    ci_info "environment option: \$CI_NO_BUILD: '$CI_NO_BUILD'"
     ci_info "environment option: \$CI_NO_TEST: '$CI_NO_TEST'"
     ci_info "environment option: \$CI_NO_INSTALL: '$CI_NO_INSTALL'"
     ci_info "environment option: \$CI_NO_CLEAN: '$CI_NO_CLEAN'"
@@ -131,8 +132,10 @@
     ci_spawn cd "$CI_BUILD_DIR"
     # Spawn "configure".
     ci_spawn "$CI_SRC_DIR/configure" --prefix="$CI_INSTALL_DIR" $CI_CONFIGURE_FLAGS
-    # Spawn "make".
-    ci_spawn "$CI_MAKE" $CI_MAKE_FLAGS
+    ci_expr $((CI_NO_BUILD)) || {
+        # Spawn "make".
+        ci_spawn "$CI_MAKE" $CI_MAKE_FLAGS
+    }
     ci_expr $((CI_NO_TEST)) || {
         # Spawn "make test" if testing is not disabled.
         ci_spawn "$CI_MAKE" $CI_MAKE_FLAGS test

Modified: trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_makefiles.sh
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_makefiles.sh	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/ci/ci_verify_makefiles.sh	2025-03-08 21:56:41 UTC (rev 74539)
@@ -51,6 +51,7 @@
     ci_info "environment option: \$CI_LIBS: '$CI_LIBS'"
     ci_info "environment option: \$CI_SANITIZERS: '$CI_SANITIZERS'"
     ci_info "environment option: \$CI_FORCE: '$CI_FORCE'"
+    ci_info "environment option: \$CI_NO_BUILD: '$CI_NO_BUILD'"
     ci_info "environment option: \$CI_NO_TEST: '$CI_NO_TEST'"
     ci_info "environment option: \$CI_NO_CLEAN: '$CI_NO_CLEAN'"
     ci_info "executable: \$CI_MAKE: $(command -V "$CI_MAKE")"
@@ -145,10 +146,12 @@
     for my_makefile in $CI_MAKEFILES
     do
         ci_info "using makefile: $my_makefile"
-        # Spawn "make".
-        ci_spawn "$CI_MAKE" -f "$my_makefile" \
-                            "${all_make_flags[@]}" \
-                            "${all_make_vars[@]}"
+        ci_expr $((CI_NO_BUILD)) || {
+            # Spawn "make".
+            ci_spawn "$CI_MAKE" -f "$my_makefile" \
+                                "${all_make_flags[@]}" \
+                                "${all_make_vars[@]}"
+        }
         ci_expr $((CI_NO_TEST)) || {
             # Spawn "make test" if testing is not disabled.
             ci_spawn "$CI_MAKE" -f "$my_makefile" \

Modified: trunk/Build/source/libs/libpng/libpng-src/ci/lib/ci.lib.sh
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/ci/lib/ci.lib.sh	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/ci/lib/ci.lib.sh	2025-03-08 21:56:41 UTC (rev 74539)
@@ -91,6 +91,9 @@
 [[ ${CI_FORCE:-0} == [01] ]] || {
     ci_err "bad boolean option: \$CI_FORCE: '$CI_FORCE'"
 }
+[[ ${CI_NO_BUILD:-0} == [01] ]] || {
+    ci_err "bad boolean option: \$CI_NO_BUILD: '$CI_NO_BUILD'"
+}
 [[ ${CI_NO_TEST:-0} == [01] ]] || {
     ci_err "bad boolean option: \$CI_NO_TEST: '$CI_NO_TEST'"
 }
@@ -100,3 +103,9 @@
 [[ ${CI_NO_CLEAN:-0} == [01] ]] || {
     ci_err "bad boolean option: \$CI_NO_CLEAN: '$CI_NO_CLEAN'"
 }
+if ci_expr $((CI_NO_BUILD))
+then
+    ci_expr $((CI_NO_TEST && CI_NO_INSTALL)) || {
+        ci_err "\$CI_NO_BUILD requires \$CI_NO_TEST and \$CI_NO_INSTALL"
+    }
+fi

Modified: trunk/Build/source/libs/libpng/libpng-src/configure.ac
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/configure.ac	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/configure.ac	2025-03-08 21:56:41 UTC (rev 74539)
@@ -25,7 +25,7 @@
 
 dnl Version number stuff here:
 
-AC_INIT([libpng],[1.6.46],[png-mng-implement at lists.sourceforge.net])
+AC_INIT([libpng],[1.6.47],[png-mng-implement at lists.sourceforge.net])
 AC_CONFIG_MACRO_DIR([scripts/autoconf])
 
 # libpng does not follow GNU file name conventions (hence 'foreign')
@@ -46,10 +46,10 @@
 dnl AM_PREREQ([1.11.2])
 dnl stop configure from automagically running automake
 
-PNGLIB_VERSION=1.6.46
+PNGLIB_VERSION=1.6.47
 PNGLIB_MAJOR=1
 PNGLIB_MINOR=6
-PNGLIB_RELEASE=46
+PNGLIB_RELEASE=47
 
 dnl End of version number stuff
 

Added: trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/fixed.dfa
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/fixed.dfa	                        (rev 0)
+++ trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/fixed.dfa	2025-03-08 21:56:41 UTC (rev 74539)
@@ -0,0 +1,15 @@
+# fixed.dfa
+#  Build time configuration of libpng
+#
+# Author: John Bowler
+# Copyright: (c) John Bowler, 2025
+# Usage rights:
+#  To the extent possible under law, the author has waived all copyright and
+#  related or neighboring rights to this work.  This work is published from:
+#  United States.
+#
+# Test the standard libpng configuration without floating point (the internal
+# fixed point implementations are used instead).
+#
+option FLOATING_ARITHMETIC off
+option FLOATING_POINT off

Added: trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/float-fixed.dfa
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/float-fixed.dfa	                        (rev 0)
+++ trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/float-fixed.dfa	2025-03-08 21:56:41 UTC (rev 74539)
@@ -0,0 +1,14 @@
+# fixed-float.dfa
+#  Build time configuration of libpng
+#
+# Author: John Bowler
+# Copyright: (c) John Bowler, 2025
+# Usage rights:
+#  To the extent possible under law, the author has waived all copyright and
+#  related or neighboring rights to this work.  This work is published from:
+#  United States.
+#
+# Test the standard libpng configuration with the fixed point internal
+# implementation in place of the default floating point
+#
+option FLOATING_ARITHMETIC off

Added: trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nocompile-limits.dfa
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nocompile-limits.dfa	                        (rev 0)
+++ trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nocompile-limits.dfa	2025-03-08 21:56:41 UTC (rev 74539)
@@ -0,0 +1,21 @@
+# nolimits.dfa
+#  Build time configuration of libpng
+#
+# Author: John Bowler
+# Copyright: (c) John Bowler, 2025
+#
+# Usage rights:
+#  To the extent possible under law, the author has waived all copyright and
+#  related or neighboring rights to this work.  This work is published from:
+#  United States.
+#
+# Build libpng without any limits and without run-time settable limits.  Turning
+# USER_LIMITS off reduces libpng code size by allowing compile-time elimination
+# of some checking code.
+#
+option USER_LIMITS off
+
+@# define PNG_USER_WIDTH_MAX PNG_UINT_31_MAX
+@# define PNG_USER_HEIGHT_MAX PNG_UINT_31_MAX
+@# define PNG_USER_CHUNK_CACHE_MAX 0
+@# define PNG_USER_CHUNK_MALLOC_MAX 0

Added: trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nolimits.dfa
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nolimits.dfa	                        (rev 0)
+++ trunk/Build/source/libs/libpng/libpng-src/contrib/conftest/nolimits.dfa	2025-03-08 21:56:41 UTC (rev 74539)
@@ -0,0 +1,19 @@
+# nolimits.dfa
+#  Build time configuration of libpng
+#
+# Author: John Bowler
+# Copyright: (c) John Bowler, 2025
+#
+# Usage rights:
+#  To the extent possible under law, the author has waived all copyright and
+#  related or neighboring rights to this work.  This work is published from:
+#  United States.
+#
+# Build libpng without any limits.  With these settigs run-time limits are still
+# possible.
+#
+@# define PNG_USER_WIDTH_MAX PNG_UINT_31_MAX
+@# define PNG_USER_HEIGHT_MAX PNG_UINT_31_MAX
+@# define PNG_USER_CHUNK_CACHE_MAX 0
+@# define PNG_USER_CHUNK_MALLOC_MAX 0
+

Modified: trunk/Build/source/libs/libpng/libpng-src/contrib/libtests/pngimage.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/contrib/libtests/pngimage.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/contrib/libtests/pngimage.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -542,6 +542,7 @@
 struct display
 {
    jmp_buf        error_return;      /* Where to go to on error */
+   error_level    error_code;        /* Set before longjmp */
 
    const char    *filename;          /* The name of the original file */
    const char    *operation;         /* Operation being performed */
@@ -762,7 +763,10 @@
 
    /* Errors cause this routine to exit to the fail code */
    if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
+   {
+      dp->error_code = level;
       longjmp(dp->error_return, level);
+    }
 }
 
 /* error handler callbacks for libpng */
@@ -1570,18 +1574,19 @@
 do_test(struct display *dp, const char *file)
    /* Exists solely to isolate the setjmp clobbers */
 {
-   int ret = setjmp(dp->error_return);
+   dp->error_code = VERBOSE; /* The "lowest" level */
 
-   if (ret == 0)
+   if (setjmp(dp->error_return) == 0)
    {
       test_one_file(dp, file);
       return 0;
    }
 
-   else if (ret < ERRORS) /* shouldn't longjmp on warnings */
-      display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
+   else if (dp->error_code < ERRORS) /* shouldn't longjmp on warnings */
+      display_log(dp, INTERNAL_ERROR, "unexpected return code %d",
+                  dp->error_code);
 
-   return ret;
+   return dp->error_code;
 }
 
 int
@@ -1681,7 +1686,11 @@
             int ret = do_test(&d, argv[i]);
 
             if (ret > QUIET) /* abort on user or internal error */
+            {
+               display_clean(&d);
+               display_destroy(&d);
                return 99;
+            }
          }
 
          /* Here on any return, including failures, except user/internal issues

Modified: trunk/Build/source/libs/libpng/libpng-src/libpng-manual.txt
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/libpng-manual.txt	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/libpng-manual.txt	2025-03-08 21:56:41 UTC (rev 74539)
@@ -9,7 +9,7 @@
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.46 - January 2025
+ libpng version 1.6.36, December 2018, through 1.6.47 - February 2025
  Updated and distributed by Cosmin Truta
  Copyright (c) 2018-2025 Cosmin Truta
 

Modified: trunk/Build/source/libs/libpng/libpng-src/libpng.3
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/libpng.3	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/libpng.3	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
-.TH LIBPNG 3 "January 23, 2025"
+.TH LIBPNG 3 "February 18, 2025"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.46
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.47
 
 .SH SYNOPSIS
 \fB#include <png.h>\fP
@@ -528,7 +528,7 @@
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.46 - January 2025
+ libpng version 1.6.36, December 2018, through 1.6.47 - February 2025
  Updated and distributed by Cosmin Truta
  Copyright (c) 2018-2025 Cosmin Truta
 

Modified: trunk/Build/source/libs/libpng/libpng-src/libpngpf.3
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/libpngpf.3	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/libpngpf.3	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
-.TH LIBPNGPF 3 "January 23, 2025"
+.TH LIBPNGPF 3 "February 18, 2025"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.46
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.47
 (private functions)
 
 .SH SYNOPSIS

Modified: trunk/Build/source/libs/libpng/libpng-src/png.5
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/png.5	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/png.5	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,4 +1,4 @@
-.TH PNG 5 "January 23, 2025"
+.TH PNG 5 "February 18, 2025"
 .SH NAME
 png \- Portable Network Graphics (PNG) format
 
@@ -20,10 +20,10 @@
 .SH "SEE ALSO"
 .BR "libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
 .LP
-PNG Specification (Third Edition) Candidate Recommendation Draft, July 2024:
+PNG Specification (Third Edition) Candidate Recommendation Draft, January 2025:
 .IP
 .br
-https://www.w3.org/TR/2024/CRD-png-3-20240718/
+https://www.w3.org/TR/2025/CRD-png-3-20250121/
 .LP
 PNG Specification (Second Edition), November 2003:
 .IP

Modified: trunk/Build/source/libs/libpng/libpng-src/png.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/png.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/png.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -13,8 +13,35 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_46 Your_png_h_is_not_version_1_6_46;
+typedef png_libpng_version_1_6_47 Your_png_h_is_not_version_1_6_47;
 
+/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
+ * corresponding macro definitions.  This causes a compile time failure if
+ * something is wrong but generates no code.
+ *
+ * (1) The first check is that the PNG_CHUNK(cHNK, index) 'index' values must
+ * increment from 0 to the last value.
+ */
+#define PNG_CHUNK(cHNK, index) != (index) || ((index)+1)
+
+#if 0 PNG_KNOWN_CHUNKS < 0
+#  error PNG_KNOWN_CHUNKS chunk definitions are not in order
+#endif
+
+#undef PNG_CHUNK
+
+/* (2) The chunk name macros, png_cHNK, must all be valid and defined.  Since
+ * this is a preprocessor test undefined pp-tokens come out as zero and will
+ * fail this test.
+ */
+#define PNG_CHUNK(cHNK, index) !PNG_CHUNK_NAME_VALID(png_ ## cHNK) ||
+
+#if PNG_KNOWN_CHUNKS 0
+#  error png_cHNK not defined for some known cHNK
+#endif
+
+#undef PNG_CHUNK
+
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
  * stream we can set num_bytes = 8 so that libpng will not attempt to read
@@ -241,21 +268,23 @@
     */
    memset(&create_struct, 0, (sizeof create_struct));
 
-   /* Added at libpng-1.2.6 */
 #  ifdef PNG_USER_LIMITS_SUPPORTED
       create_struct.user_width_max = PNG_USER_WIDTH_MAX;
       create_struct.user_height_max = PNG_USER_HEIGHT_MAX;
 
 #     ifdef PNG_USER_CHUNK_CACHE_MAX
-      /* Added at libpng-1.2.43 and 1.4.0 */
       create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
 #     endif
 
-#     ifdef PNG_USER_CHUNK_MALLOC_MAX
-      /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists
-       * in png_struct regardless.
-       */
+#     if PNG_USER_CHUNK_MALLOC_MAX > 0 /* default to compile-time limit */
       create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
+
+      /* No compile-time limit, so initialize to the system limit: */
+#     elif defined PNG_MAX_MALLOC_64K /* legacy system limit */
+      create_struct.user_chunk_malloc_max = 65536U;
+
+#     else /* modern system limit SIZE_MAX (C99) */
+      create_struct.user_chunk_malloc_max = PNG_SIZE_MAX;
 #     endif
 #  endif
 
@@ -597,13 +626,6 @@
    /* Free any eXIf entry */
    if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)
    {
-# ifdef PNG_READ_eXIf_SUPPORTED
-      if (info_ptr->eXIf_buf)
-      {
-         png_free(png_ptr, info_ptr->eXIf_buf);
-         info_ptr->eXIf_buf = NULL;
-      }
-# endif
       if (info_ptr->exif)
       {
          png_free(png_ptr, info_ptr->exif);
@@ -793,7 +815,7 @@
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.46" PNG_STRING_NEWLINE \
+      "libpng version 1.6.47" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
@@ -1038,169 +1060,6 @@
    }
 }
 
-/* png_convert_size: a PNGAPI but no longer in png.h, so deleted
- * at libpng 1.5.5!
- */
-
-/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
-#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
-static int
-png_colorspace_check_gamma(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, png_fixed_point gAMA, int from)
-   /* This is called to check a new gamma value against an existing one.  The
-    * routine returns false if the new gamma value should not be written.
-    *
-    * 'from' says where the new gamma value comes from:
-    *
-    *    0: the new gamma value is the libpng estimate for an ICC profile
-    *    1: the new gamma value comes from a gAMA chunk
-    *    2: the new gamma value comes from an sRGB chunk
-    */
-{
-   png_fixed_point gtest;
-
-   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
-       (png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) == 0  ||
-      png_gamma_significant(gtest) != 0))
-   {
-      /* Either this is an sRGB image, in which case the calculated gamma
-       * approximation should match, or this is an image with a profile and the
-       * value libpng calculates for the gamma of the profile does not match the
-       * value recorded in the file.  The former, sRGB, case is an error, the
-       * latter is just a warning.
-       */
-      if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)
-      {
-         png_chunk_report(png_ptr, "gamma value does not match sRGB",
-             PNG_CHUNK_ERROR);
-         /* Do not overwrite an sRGB value */
-         return from == 2;
-      }
-
-      else /* sRGB tag not involved */
-      {
-         png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
-             PNG_CHUNK_WARNING);
-         return from == 1;
-      }
-   }
-
-   return 1;
-}
-
-void /* PRIVATE */
-png_colorspace_set_gamma(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, png_fixed_point gAMA)
-{
-   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
-    * occur.  Since the fixed point representation is asymmetrical it is
-    * possible for 1/gamma to overflow the limit of 21474 and this means the
-    * gamma value must be at least 5/100000 and hence at most 20000.0.  For
-    * safety the limits here are a little narrower.  The values are 0.00016 to
-    * 6250.0, which are truly ridiculous gamma values (and will produce
-    * displays that are all black or all white.)
-    *
-    * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
-    * handling code, which only required the value to be >0.
-    */
-   png_const_charp errmsg;
-
-   if (gAMA < 16 || gAMA > 625000000)
-      errmsg = "gamma value out of range";
-
-#  ifdef PNG_READ_gAMA_SUPPORTED
-   /* Allow the application to set the gamma value more than once */
-   else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
-      (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
-      errmsg = "duplicate";
-#  endif
-
-   /* Do nothing if the colorspace is already invalid */
-   else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
-      return;
-
-   else
-   {
-      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
-          1/*from gAMA*/) != 0)
-      {
-         /* Store this gamma value. */
-         colorspace->gamma = gAMA;
-         colorspace->flags |=
-            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
-      }
-
-      /* At present if the check_gamma test fails the gamma of the colorspace is
-       * not updated however the colorspace is not invalidated.  This
-       * corresponds to the case where the existing gamma comes from an sRGB
-       * chunk or profile.  An error message has already been output.
-       */
-      return;
-   }
-
-   /* Error exit - errmsg has been set. */
-   colorspace->flags |= PNG_COLORSPACE_INVALID;
-   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
-}
-
-void /* PRIVATE */
-png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)
-{
-   if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
-   {
-      /* Everything is invalid */
-      info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|
-         PNG_INFO_iCCP);
-
-#     ifdef PNG_COLORSPACE_SUPPORTED
-      /* Clean up the iCCP profile now if it won't be used. */
-      png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);
-#     else
-      PNG_UNUSED(png_ptr)
-#     endif
-   }
-
-   else
-   {
-#     ifdef PNG_COLORSPACE_SUPPORTED
-      /* Leave the INFO_iCCP flag set if the pngset.c code has already set
-       * it; this allows a PNG to contain a profile which matches sRGB and
-       * yet still have that profile retrievable by the application.
-       */
-      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0)
-         info_ptr->valid |= PNG_INFO_sRGB;
-
-      else
-         info_ptr->valid &= ~PNG_INFO_sRGB;
-
-      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
-         info_ptr->valid |= PNG_INFO_cHRM;
-
-      else
-         info_ptr->valid &= ~PNG_INFO_cHRM;
-#     endif
-
-      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0)
-         info_ptr->valid |= PNG_INFO_gAMA;
-
-      else
-         info_ptr->valid &= ~PNG_INFO_gAMA;
-   }
-}
-
-#ifdef PNG_READ_SUPPORTED
-void /* PRIVATE */
-png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
-{
-   if (info_ptr == NULL) /* reduce code size; check here not in the caller */
-      return;
-
-   info_ptr->colorspace = png_ptr->colorspace;
-   png_colorspace_sync_info(png_ptr, info_ptr);
-}
-#endif
-#endif /* GAMMA */
-
 #ifdef PNG_COLORSPACE_SUPPORTED
 static png_int_32
 png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error)
@@ -1269,9 +1128,10 @@
  * non-zero on a parameter error.  The X, Y and Z values are required to be
  * positive and less than 1.0.
  */
-static int
+int /* PRIVATE */
 png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
 {
+   /* NOTE: returns 0 on success, 1 means error. */
    png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY;
 
    /* 'd' in each of the blocks below is just X+Y+Z for each component,
@@ -1334,9 +1194,10 @@
    return 0;
 }
 
-static int
+int /* PRIVATE */
 png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
 {
+   /* NOTE: returns 0 on success, 1 means error. */
    png_fixed_point red_inverse, green_inverse, blue_scale;
    png_fixed_point left, right, denominator;
 
@@ -1628,239 +1489,9 @@
 
    return 0; /*success*/
 }
+#endif /* COLORSPACE */
 
-static int
-png_XYZ_normalize(png_XYZ *XYZ)
-{
-   png_int_32 Y, Ytemp;
-
-   /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. */
-   Ytemp = XYZ->red_Y;
-   if (png_safe_add(&Ytemp, XYZ->green_Y, XYZ->blue_Y))
-      return 1;
-
-   Y = Ytemp;
-
-   if (Y != PNG_FP_1)
-   {
-      if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)
-         return 1;
-
-      if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)
-         return 1;
-
-      if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)
-         return 1;
-      if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)
-         return 1;
-   }
-
-   return 0;
-}
-
-static int
-png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta)
-{
-   /* Allow an error of +/-0.01 (absolute value) on each chromaticity */
-   if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||
-       PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||
-       PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||
-       PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||
-       PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||
-       PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||
-       PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||
-       PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta))
-      return 0;
-   return 1;
-}
-
-/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM
- * chunk chromaticities.  Earlier checks used to simply look for the overflow
- * condition (where the determinant of the matrix to solve for XYZ ends up zero
- * because the chromaticity values are not all distinct.)  Despite this it is
- * theoretically possible to produce chromaticities that are apparently valid
- * but that rapidly degrade to invalid, potentially crashing, sets because of
- * arithmetic inaccuracies when calculations are performed on them.  The new
- * check is to round-trip xy -> XYZ -> xy and then check that the result is
- * within a small percentage of the original.
- */
-static int
-png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy)
-{
-   int result;
-   png_xy xy_test;
-
-   /* As a side-effect this routine also returns the XYZ endpoints. */
-   result = png_XYZ_from_xy(XYZ, xy);
-   if (result != 0)
-      return result;
-
-   result = png_xy_from_XYZ(&xy_test, XYZ);
-   if (result != 0)
-      return result;
-
-   if (png_colorspace_endpoints_match(xy, &xy_test,
-       5/*actually, the math is pretty accurate*/) != 0)
-      return 0;
-
-   /* Too much slip */
-   return 1;
-}
-
-/* This is the check going the other way.  The XYZ is modified to normalize it
- * (another side-effect) and the xy chromaticities are returned.
- */
-static int
-png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ)
-{
-   int result;
-   png_XYZ XYZtemp;
-
-   result = png_XYZ_normalize(XYZ);
-   if (result != 0)
-      return result;
-
-   result = png_xy_from_XYZ(xy, XYZ);
-   if (result != 0)
-      return result;
-
-   XYZtemp = *XYZ;
-   return png_colorspace_check_xy(&XYZtemp, xy);
-}
-
-/* Used to check for an endpoint match against sRGB */
-static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
-{
-   /* color      x       y */
-   /* red   */ 64000, 33000,
-   /* green */ 30000, 60000,
-   /* blue  */ 15000,  6000,
-   /* white */ 31270, 32900
-};
-
-static int
-png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,
-    int preferred)
-{
-   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
-      return 0;
-
-   /* The consistency check is performed on the chromaticities; this factors out
-    * variations because of the normalization (or not) of the end point Y
-    * values.
-    */
-   if (preferred < 2 &&
-       (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
-   {
-      /* The end points must be reasonably close to any we already have.  The
-       * following allows an error of up to +/-.001
-       */
-      if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy,
-          100) == 0)
-      {
-         colorspace->flags |= PNG_COLORSPACE_INVALID;
-         png_benign_error(png_ptr, "inconsistent chromaticities");
-         return 0; /* failed */
-      }
-
-      /* Only overwrite with preferred values */
-      if (preferred == 0)
-         return 1; /* ok, but no change */
-   }
-
-   colorspace->end_points_xy = *xy;
-   colorspace->end_points_XYZ = *XYZ;
-   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;
-
-   /* The end points are normally quoted to two decimal digits, so allow +/-0.01
-    * on this test.
-    */
-   if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0)
-      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;
-
-   else
-      colorspace->flags &= PNG_COLORSPACE_CANCEL(
-         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
-
-   return 2; /* ok and changed */
-}
-
-int /* PRIVATE */
-png_colorspace_set_chromaticities(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, const png_xy *xy, int preferred)
-{
-   /* We must check the end points to ensure they are reasonable - in the past
-    * color management systems have crashed as a result of getting bogus
-    * colorant values, while this isn't the fault of libpng it is the
-    * responsibility of libpng because PNG carries the bomb and libpng is in a
-    * position to protect against it.
-    */
-   png_XYZ XYZ;
-
-   switch (png_colorspace_check_xy(&XYZ, xy))
-   {
-      case 0: /* success */
-         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,
-             preferred);
-
-      case 1:
-         /* We can't invert the chromaticities so we can't produce value XYZ
-          * values.  Likely as not a color management system will fail too.
-          */
-         colorspace->flags |= PNG_COLORSPACE_INVALID;
-         png_benign_error(png_ptr, "invalid chromaticities");
-         break;
-
-      default:
-         /* libpng is broken; this should be a warning but if it happens we
-          * want error reports so for the moment it is an error.
-          */
-         colorspace->flags |= PNG_COLORSPACE_INVALID;
-         png_error(png_ptr, "internal error checking chromaticities");
-   }
-
-   return 0; /* failed */
-}
-
-int /* PRIVATE */
-png_colorspace_set_endpoints(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)
-{
-   png_XYZ XYZ = *XYZ_in;
-   png_xy xy;
-
-   switch (png_colorspace_check_XYZ(&xy, &XYZ))
-   {
-      case 0:
-         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,
-             preferred);
-
-      case 1:
-         /* End points are invalid. */
-         colorspace->flags |= PNG_COLORSPACE_INVALID;
-         png_benign_error(png_ptr, "invalid end points");
-         break;
-
-      default:
-         colorspace->flags |= PNG_COLORSPACE_INVALID;
-         png_error(png_ptr, "internal error checking chromaticities");
-   }
-
-   return 0; /* failed */
-}
-
-#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED)
+#ifdef PNG_iCCP_SUPPORTED
 /* Error message generation */
 static char
 png_icc_tag_char(png_uint_32 byte)
@@ -1900,15 +1531,12 @@
 }
 
 static int
-png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_alloc_size_t value, png_const_charp reason)
+png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name,
+   png_alloc_size_t value, png_const_charp reason)
 {
    size_t pos;
    char message[196]; /* see below for calculation */
 
-   if (colorspace != NULL)
-      colorspace->flags |= PNG_COLORSPACE_INVALID;
-
    pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */
    pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */
    pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
@@ -1935,109 +1563,13 @@
    pos = png_safecat(message, (sizeof message), pos, reason);
    PNG_UNUSED(pos)
 
-   /* This is recoverable, but make it unconditionally an app_error on write to
-    * avoid writing invalid ICC profiles into PNG files (i.e., we handle them
-    * on read, with a warning, but on write unless the app turns off
-    * application errors the PNG won't be written.)
-    */
-   png_chunk_report(png_ptr, message,
-       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
+   png_chunk_benign_error(png_ptr, message);
 
    return 0;
 }
-#endif /* sRGB || iCCP */
+#endif /* iCCP */
 
-#ifdef PNG_sRGB_SUPPORTED
-int /* PRIVATE */
-png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    int intent)
-{
-   /* sRGB sets known gamma, end points and (from the chunk) intent. */
-   /* IMPORTANT: these are not necessarily the values found in an ICC profile
-    * because ICC profiles store values adapted to a D50 environment; it is
-    * expected that the ICC profile mediaWhitePointTag will be D50; see the
-    * checks and code elsewhere to understand this better.
-    *
-    * These XYZ values, which are accurate to 5dp, produce rgb to gray
-    * coefficients of (6968,23435,2366), which are reduced (because they add up
-    * to 32769 not 32768) to (6968,23434,2366).  These are the values that
-    * libpng has traditionally used (and are the best values given the 15bit
-    * algorithm used by the rgb to gray code.)
-    */
-   static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */
-   {
-      /* color      X      Y      Z */
-      /* red   */ 41239, 21264,  1933,
-      /* green */ 35758, 71517, 11919,
-      /* blue  */ 18048,  7219, 95053
-   };
-
-   /* Do nothing if the colorspace is already invalidated. */
-   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
-      return 0;
-
-   /* Check the intent, then check for existing settings.  It is valid for the
-    * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
-    * be consistent with the correct values.  If, however, this function is
-    * called below because an iCCP chunk matches sRGB then it is quite
-    * conceivable that an older app recorded incorrect gAMA and cHRM because of
-    * an incorrect calculation based on the values in the profile - this does
-    * *not* invalidate the profile (though it still produces an error, which can
-    * be ignored.)
-    */
-   if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
-      return png_icc_profile_error(png_ptr, colorspace, "sRGB",
-          (png_alloc_size_t)intent, "invalid sRGB rendering intent");
-
-   if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
-       colorspace->rendering_intent != intent)
-      return png_icc_profile_error(png_ptr, colorspace, "sRGB",
-         (png_alloc_size_t)intent, "inconsistent rendering intents");
-
-   if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
-   {
-      png_benign_error(png_ptr, "duplicate sRGB information ignored");
-      return 0;
-   }
-
-   /* If the standard sRGB cHRM chunk does not match the one from the PNG file
-    * warn but overwrite the value with the correct one.
-    */
-   if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&
-       !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
-       100))
-      png_chunk_report(png_ptr, "cHRM chunk does not match sRGB",
-         PNG_CHUNK_ERROR);
-
-   /* This check is just done for the error reporting - the routine always
-    * returns true when the 'from' argument corresponds to sRGB (2).
-    */
-   (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,
-       2/*from sRGB*/);
-
-   /* intent: bugs in GCC force 'int' to be used as the parameter type. */
-   colorspace->rendering_intent = (png_uint_16)intent;
-   colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
-
-   /* endpoints */
-   colorspace->end_points_xy = sRGB_xy;
-   colorspace->end_points_XYZ = sRGB_XYZ;
-   colorspace->flags |=
-      (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
-
-   /* gamma */
-   colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;
-   colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
-
-   /* Finally record that we have an sRGB profile */
-   colorspace->flags |=
-      (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);
-
-   return 1; /* set */
-}
-#endif /* sRGB */
-
-#ifdef PNG_iCCP_SUPPORTED
+#ifdef PNG_READ_iCCP_SUPPORTED
 /* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
  * is XYZ(0.9642,1.0,0.8249), which scales to:
  *
@@ -2047,21 +1579,19 @@
    { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };
 
 static int /* bool */
-icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_uint_32 profile_length)
+icc_check_length(png_const_structrp png_ptr, png_const_charp name,
+   png_uint_32 profile_length)
 {
    if (profile_length < 132)
-      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
-          "too short");
+      return png_icc_profile_error(png_ptr, name, profile_length, "too short");
    return 1;
 }
 
-#ifdef PNG_READ_iCCP_SUPPORTED
 int /* PRIVATE */
-png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_uint_32 profile_length)
+png_icc_check_length(png_const_structrp png_ptr, png_const_charp name,
+   png_uint_32 profile_length)
 {
-   if (!icc_check_length(png_ptr, colorspace, name, profile_length))
+   if (!icc_check_length(png_ptr, name, profile_length))
       return 0;
 
    /* This needs to be here because the 'normal' check is in
@@ -2070,30 +1600,17 @@
     * the caller supplies the profile buffer so libpng doesn't allocate it.  See
     * the call to icc_check_length below (the write case).
     */
-#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-      else if (png_ptr->user_chunk_malloc_max > 0 &&
-               png_ptr->user_chunk_malloc_max < profile_length)
-         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
-             "exceeds application limits");
-#  elif PNG_USER_CHUNK_MALLOC_MAX > 0
-      else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
-         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
-             "exceeds libpng limits");
-#  else /* !SET_USER_LIMITS */
-      /* This will get compiled out on all 32-bit and better systems. */
-      else if (PNG_SIZE_MAX < profile_length)
-         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
-             "exceeds system limits");
-#  endif /* !SET_USER_LIMITS */
+   if (profile_length > png_chunk_max(png_ptr))
+      return png_icc_profile_error(png_ptr, name, profile_length,
+            "profile too long");
 
    return 1;
 }
-#endif /* READ_iCCP */
 
 int /* PRIVATE */
-png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_uint_32 profile_length,
-    png_const_bytep profile/* first 132 bytes only */, int color_type)
+png_icc_check_header(png_const_structrp png_ptr, png_const_charp name,
+   png_uint_32 profile_length,
+   png_const_bytep profile/* first 132 bytes only */, int color_type)
 {
    png_uint_32 temp;
 
@@ -2104,18 +1621,18 @@
     */
    temp = png_get_uint_32(profile);
    if (temp != profile_length)
-      return png_icc_profile_error(png_ptr, colorspace, name, temp,
+      return png_icc_profile_error(png_ptr, name, temp,
           "length does not match profile");
 
    temp = (png_uint_32) (*(profile+8));
    if (temp > 3 && (profile_length & 3))
-      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
+      return png_icc_profile_error(png_ptr, name, profile_length,
           "invalid length");
 
    temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */
    if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */
       profile_length < 132+12*temp) /* truncated tag table */
-      return png_icc_profile_error(png_ptr, colorspace, name, temp,
+      return png_icc_profile_error(png_ptr, name, temp,
           "tag count too large");
 
    /* The 'intent' must be valid or we can't store it, ICC limits the intent to
@@ -2123,7 +1640,7 @@
     */
    temp = png_get_uint_32(profile+64);
    if (temp >= 0xffff) /* The ICC limit */
-      return png_icc_profile_error(png_ptr, colorspace, name, temp,
+      return png_icc_profile_error(png_ptr, name, temp,
           "invalid rendering intent");
 
    /* This is just a warning because the profile may be valid in future
@@ -2130,7 +1647,7 @@
     * versions.
     */
    if (temp >= PNG_sRGB_INTENT_LAST)
-      (void)png_icc_profile_error(png_ptr, NULL, name, temp,
+      (void)png_icc_profile_error(png_ptr, name, temp,
           "intent outside defined range");
 
    /* At this point the tag table can't be checked because it hasn't necessarily
@@ -2147,7 +1664,7 @@
     */
    temp = png_get_uint_32(profile+36); /* signature 'ascp' */
    if (temp != 0x61637370)
-      return png_icc_profile_error(png_ptr, colorspace, name, temp,
+      return png_icc_profile_error(png_ptr, name, temp,
           "invalid signature");
 
    /* Currently the PCS illuminant/adopted white point (the computational
@@ -2158,7 +1675,7 @@
     * following is just a warning.
     */
    if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)
-      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
+      (void)png_icc_profile_error(png_ptr, name, 0/*no tag value*/,
           "PCS illuminant is not D50");
 
    /* The PNG spec requires this:
@@ -2186,18 +1703,18 @@
    {
       case 0x52474220: /* 'RGB ' */
          if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
-            return png_icc_profile_error(png_ptr, colorspace, name, temp,
+            return png_icc_profile_error(png_ptr, name, temp,
                 "RGB color space not permitted on grayscale PNG");
          break;
 
       case 0x47524159: /* 'GRAY' */
          if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
-            return png_icc_profile_error(png_ptr, colorspace, name, temp,
+            return png_icc_profile_error(png_ptr, name, temp,
                 "Gray color space not permitted on RGB PNG");
          break;
 
       default:
-         return png_icc_profile_error(png_ptr, colorspace, name, temp,
+         return png_icc_profile_error(png_ptr, name, temp,
              "invalid ICC profile color space");
    }
 
@@ -2222,7 +1739,7 @@
 
       case 0x61627374: /* 'abst' */
          /* May not be embedded in an image */
-         return png_icc_profile_error(png_ptr, colorspace, name, temp,
+         return png_icc_profile_error(png_ptr, name, temp,
              "invalid embedded Abstract ICC profile");
 
       case 0x6c696e6b: /* 'link' */
@@ -2232,7 +1749,7 @@
           * therefore a DeviceLink profile should not be found embedded in a
           * PNG.
           */
-         return png_icc_profile_error(png_ptr, colorspace, name, temp,
+         return png_icc_profile_error(png_ptr, name, temp,
              "unexpected DeviceLink ICC profile class");
 
       case 0x6e6d636c: /* 'nmcl' */
@@ -2240,7 +1757,7 @@
           * contain an AToB0 tag that is open to misinterpretation.  Almost
           * certainly it will fail the tests below.
           */
-         (void)png_icc_profile_error(png_ptr, NULL, name, temp,
+         (void)png_icc_profile_error(png_ptr, name, temp,
              "unexpected NamedColor ICC profile class");
          break;
 
@@ -2250,7 +1767,7 @@
           * tag content to ensure they are backward compatible with one of the
           * understood profiles.
           */
-         (void)png_icc_profile_error(png_ptr, NULL, name, temp,
+         (void)png_icc_profile_error(png_ptr, name, temp,
              "unrecognized ICC profile class");
          break;
    }
@@ -2266,7 +1783,7 @@
          break;
 
       default:
-         return png_icc_profile_error(png_ptr, colorspace, name, temp,
+         return png_icc_profile_error(png_ptr, name, temp,
              "unexpected ICC PCS encoding");
    }
 
@@ -2274,9 +1791,9 @@
 }
 
 int /* PRIVATE */
-png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_uint_32 profile_length,
-    png_const_bytep profile /* header plus whole tag table */)
+png_icc_check_tag_table(png_const_structrp png_ptr, png_const_charp name,
+   png_uint_32 profile_length,
+   png_const_bytep profile /* header plus whole tag table */)
 {
    png_uint_32 tag_count = png_get_uint_32(profile+128);
    png_uint_32 itag;
@@ -2302,7 +1819,7 @@
        * profile.
        */
       if (tag_start > profile_length || tag_length > profile_length - tag_start)
-         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
+         return png_icc_profile_error(png_ptr, name, tag_id,
              "ICC profile tag outside profile");
 
       if ((tag_start & 3) != 0)
@@ -2311,7 +1828,7 @@
           * only a warning here because libpng does not care about the
           * alignment.
           */
-         (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
+         (void)png_icc_profile_error(png_ptr, name, tag_id,
              "ICC profile tag start not a multiple of 4");
       }
    }
@@ -2318,300 +1835,125 @@
 
    return 1; /* success, maybe with warnings */
 }
+#endif /* READ_iCCP */
 
-#ifdef PNG_sRGB_SUPPORTED
-#if PNG_sRGB_PROFILE_CHECKS >= 0
-/* Information about the known ICC sRGB profiles */
-static const struct
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+#if (defined PNG_READ_mDCV_SUPPORTED) || (defined PNG_READ_cHRM_SUPPORTED)
+static int
+have_chromaticities(png_const_structrp png_ptr)
 {
-   png_uint_32 adler, crc, length;
-   png_uint_32 md5[4];
-   png_byte    have_md5;
-   png_byte    is_broken;
-   png_uint_16 intent;
-
-#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
-#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\
-      { adler, crc, length, md5, broke, intent },
-
-} png_sRGB_checks[] =
-{
-   /* This data comes from contrib/tools/checksum-icc run on downloads of
-    * all four ICC sRGB profiles from www.color.org.
+   /* Handle new PNGv3 chunks and the precedence rules to determine whether
+    * png_struct::chromaticities must be processed.  Only required for RGB to
+    * gray.
+    *
+    * mDCV: this is the mastering colour space and it is independent of the
+    *       encoding so it needs to be used regardless of the encoded space.
+    *
+    * cICP: first in priority but not yet implemented - the chromaticities come
+    *       from the 'primaries'.
+    *
+    * iCCP: not supported by libpng (so ignored)
+    *
+    * sRGB: the defaults match sRGB
+    *
+    * cHRM: calculate the coefficients
     */
-   /* adler32, crc32, MD5[4], intent, date, length, file-name */
-   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
-       PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,
-       "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
+#  ifdef PNG_READ_mDCV_SUPPORTED
+      if (png_has_chunk(png_ptr, mDCV))
+         return 1;
+#     define check_chromaticities 1
+#  endif /*mDCV*/
 
-   /* ICC sRGB v2 perceptual no black-compensation: */
-   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
-       PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,
-       "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
+#  ifdef PNG_READ_sRGB_SUPPORTED
+      if (png_has_chunk(png_ptr, sRGB))
+         return 0;
+#  endif /*sRGB*/
 
-   PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,
-       PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,
-       "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
+#  ifdef PNG_READ_cHRM_SUPPORTED
+      if (png_has_chunk(png_ptr, cHRM))
+         return 1;
+#     define check_chromaticities 1
+#  endif /*cHRM*/
 
-   /* ICC sRGB v4 perceptual */
-   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
-       PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,
-       "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
+   return 0; /* sRGB defaults */
+}
+#endif /* READ_mDCV || READ_cHRM */
 
-   /* The following profiles have no known MD5 checksum. If there is a match
-    * on the (empty) MD5 the other fields are used to attempt a match and
-    * a warning is produced.  The first two of these profiles have a 'cprt' tag
-    * which suggests that they were also made by Hewlett Packard.
-    */
-   PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,
-       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,
-       "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
-
-   /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not
-    * match the D50 PCS illuminant in the header (it is in fact the D65 values,
-    * so the white point is recorded as the un-adapted value.)  The profiles
-    * below only differ in one byte - the intent - and are basically the same as
-    * the previous profile except for the mediaWhitePointTag error and a missing
-    * chromaticAdaptationTag.
-    */
-   PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,
-       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,
-       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")
-
-   PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,
-       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,
-       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")
-};
-
-static int
-png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
-    png_const_bytep profile, uLong adler)
+void /* PRIVATE */
+png_set_rgb_coefficients(png_structrp png_ptr)
 {
-   /* The quick check is to verify just the MD5 signature and trust the
-    * rest of the data.  Because the profile has already been verified for
-    * correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'
-    * field too, so if the profile has been edited with an intent not defined
-    * by sRGB (but maybe defined by a later ICC specification) the read of
-    * the profile will fail at that point.
+   /* Set the rgb_to_gray coefficients from the colorspace if available.  Note
+    * that '_set' means that png_rgb_to_gray was called **and** it successfully
+    * set up the coefficients.
     */
+   if (png_ptr->rgb_to_gray_coefficients_set == 0)
+   {
+#  if check_chromaticities
+      png_XYZ xyz;
 
-   png_uint_32 length = 0;
-   png_uint_32 intent = 0x10000; /* invalid */
-#if PNG_sRGB_PROFILE_CHECKS > 1
-   uLong crc = 0; /* the value for 0 length data */
-#endif
-   unsigned int i;
-
-#ifdef PNG_SET_OPTION_SUPPORTED
-   /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */
-   if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==
-               PNG_OPTION_ON)
-      return 0;
-#endif
-
-   for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)
-   {
-      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
-         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
-         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
-         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
+      if (have_chromaticities(png_ptr) &&
+          png_XYZ_from_xy(&xyz, &png_ptr->chromaticities) == 0)
       {
-         /* This may be one of the old HP profiles without an MD5, in that
-          * case we can only use the length and Adler32 (note that these
-          * are not used by default if there is an MD5!)
+         /* png_set_rgb_to_gray has not set the coefficients, get them from the
+          * Y * values of the colorspace colorants.
           */
-#        if PNG_sRGB_PROFILE_CHECKS == 0
-            if (png_sRGB_checks[i].have_md5 != 0)
-               return 1+png_sRGB_checks[i].is_broken;
-#        endif
+         png_fixed_point r = xyz.red_Y;
+         png_fixed_point g = xyz.green_Y;
+         png_fixed_point b = xyz.blue_Y;
+         png_fixed_point total = r+g+b;
 
-         /* Profile is unsigned or more checks have been configured in. */
-         if (length == 0)
+         if (total > 0 &&
+            r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
+            g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
+            b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
+            r+g+b <= 32769)
          {
-            length = png_get_uint_32(profile);
-            intent = png_get_uint_32(profile+64);
-         }
+            /* We allow 0 coefficients here.  r+g+b may be 32769 if two or
+             * all of the coefficients were rounded up.  Handle this by
+             * reducing the *largest* coefficient by 1; this matches the
+             * approach used for the default coefficients in pngrtran.c
+             */
+            int add = 0;
 
-         /* Length *and* intent must match */
-         if (length == (png_uint_32) png_sRGB_checks[i].length &&
-            intent == (png_uint_32) png_sRGB_checks[i].intent)
-         {
-            /* Now calculate the adler32 if not done already. */
-            if (adler == 0)
+            if (r+g+b > 32768)
+               add = -1;
+            else if (r+g+b < 32768)
+               add = 1;
+
+            if (add != 0)
             {
-               adler = adler32(0, NULL, 0);
-               adler = adler32(adler, profile, length);
+               if (g >= r && g >= b)
+                  g += add;
+               else if (r >= g && r >= b)
+                  r += add;
+               else
+                  b += add;
             }
 
-            if (adler == png_sRGB_checks[i].adler)
+            /* Check for an internal error. */
+            if (r+g+b != 32768)
+               png_error(png_ptr,
+                   "internal error handling cHRM coefficients");
+
+            else
             {
-               /* These basic checks suggest that the data has not been
-                * modified, but if the check level is more than 1 perform
-                * our own crc32 checksum on the data.
-                */
-#              if PNG_sRGB_PROFILE_CHECKS > 1
-                  if (crc == 0)
-                  {
-                     crc = crc32(0, NULL, 0);
-                     crc = crc32(crc, profile, length);
-                  }
-
-                  /* So this check must pass for the 'return' below to happen.
-                   */
-                  if (crc == png_sRGB_checks[i].crc)
-#              endif
-               {
-                  if (png_sRGB_checks[i].is_broken != 0)
-                  {
-                     /* These profiles are known to have bad data that may cause
-                      * problems if they are used, therefore attempt to
-                      * discourage their use, skip the 'have_md5' warning below,
-                      * which is made irrelevant by this error.
-                      */
-                     png_chunk_report(png_ptr, "known incorrect sRGB profile",
-                         PNG_CHUNK_ERROR);
-                  }
-
-                  /* Warn that this being done; this isn't even an error since
-                   * the profile is perfectly valid, but it would be nice if
-                   * people used the up-to-date ones.
-                   */
-                  else if (png_sRGB_checks[i].have_md5 == 0)
-                  {
-                     png_chunk_report(png_ptr,
-                         "out-of-date sRGB profile with no signature",
-                         PNG_CHUNK_WARNING);
-                  }
-
-                  return 1+png_sRGB_checks[i].is_broken;
-               }
+               png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;
+               png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
             }
-
-# if PNG_sRGB_PROFILE_CHECKS > 0
-         /* The signature matched, but the profile had been changed in some
-          * way.  This probably indicates a data error or uninformed hacking.
-          * Fall through to "no match".
-          */
-         png_chunk_report(png_ptr,
-             "Not recognizing known sRGB profile that has been edited",
-             PNG_CHUNK_WARNING);
-         break;
-# endif
          }
       }
-   }
-
-   return 0; /* no match */
-}
-
-void /* PRIVATE */
-png_icc_set_sRGB(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, png_const_bytep profile, uLong adler)
-{
-   /* Is this profile one of the known ICC sRGB profiles?  If it is, just set
-    * the sRGB information.
-    */
-   if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0)
-      (void)png_colorspace_set_sRGB(png_ptr, colorspace,
-         (int)/*already checked*/png_get_uint_32(profile+64));
-}
-#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */
-#endif /* sRGB */
-
-int /* PRIVATE */
-png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,
-    png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,
-    int color_type)
-{
-   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
-      return 0;
-
-   if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
-       png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
-           color_type) != 0 &&
-       png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
-           profile) != 0)
-   {
-#     if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
-         /* If no sRGB support, don't try storing sRGB information */
-         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
-#     endif
-      return 1;
-   }
-
-   /* Failure case */
-   return 0;
-}
-#endif /* iCCP */
-
-#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
-void /* PRIVATE */
-png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
-{
-   /* Set the rgb_to_gray coefficients from the colorspace. */
-   if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
-      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
-   {
-      /* png_set_background has not been called, get the coefficients from the Y
-       * values of the colorspace colorants.
-       */
-      png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;
-      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
-      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
-      png_fixed_point total = r+g+b;
-
-      if (total > 0 &&
-         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
-         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
-         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
-         r+g+b <= 32769)
+      else
+#  endif /* check_chromaticities */
       {
-         /* We allow 0 coefficients here.  r+g+b may be 32769 if two or
-          * all of the coefficients were rounded up.  Handle this by
-          * reducing the *largest* coefficient by 1; this matches the
-          * approach used for the default coefficients in pngrtran.c
-          */
-         int add = 0;
-
-         if (r+g+b > 32768)
-            add = -1;
-         else if (r+g+b < 32768)
-            add = 1;
-
-         if (add != 0)
-         {
-            if (g >= r && g >= b)
-               g += add;
-            else if (r >= g && r >= b)
-               r += add;
-            else
-               b += add;
-         }
-
-         /* Check for an internal error. */
-         if (r+g+b != 32768)
-            png_error(png_ptr,
-                "internal error handling cHRM coefficients");
-
-         else
-         {
-            png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;
-            png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
-         }
+         /* Use the historical REC 709 (etc) values: */
+         png_ptr->rgb_to_gray_red_coeff   = 6968;
+         png_ptr->rgb_to_gray_green_coeff = 23434;
+         /* png_ptr->rgb_to_gray_blue_coeff  = 2366; */
       }
-
-      /* This is a png_error at present even though it could be ignored -
-       * it should never happen, but it is important that if it does, the
-       * bug is fixed.
-       */
-      else
-         png_error(png_ptr, "internal error handling cHRM->XYZ");
    }
 }
 #endif /* READ_RGB_TO_GRAY */
 
-#endif /* COLORSPACE */
-
 void /* PRIVATE */
 png_check_IHDR(png_const_structrp png_ptr,
     png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -3413,7 +2755,7 @@
 #endif
 
 
-#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
     defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
 /* muldiv functions */
 /* This API takes signed arguments and rounds the result to the nearest
@@ -3421,7 +2763,7 @@
  * the nearest .00001).  Overflow and divide by zero are signalled in
  * the result, a boolean - true on success, false on overflow.
  */
-int
+int /* PRIVATE */
 png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
     png_int_32 divisor)
 {
@@ -3535,27 +2877,7 @@
 
    return 0;
 }
-#endif /* READ_GAMMA || INCH_CONVERSIONS */
 
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
-/* The following is for when the caller doesn't much care about the
- * result.
- */
-png_fixed_point
-png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times,
-    png_int_32 divisor)
-{
-   png_fixed_point result;
-
-   if (png_muldiv(&result, a, times, divisor) != 0)
-      return result;
-
-   png_warning(png_ptr, "fixed point overflow ignored");
-   return 0;
-}
-#endif
-
-#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */
 /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
 png_fixed_point
 png_reciprocal(png_fixed_point a)
@@ -3574,7 +2896,9 @@
 
    return 0; /* error/overflow */
 }
+#endif /* READ_GAMMA || COLORSPACE || INCH_CONVERSIONS || READ_pHYS */
 
+#ifdef PNG_READ_GAMMA_SUPPORTED
 /* This is the shared test on whether a gamma value is 'significant' - whether
  * it is worth doing gamma correction.
  */
@@ -3581,19 +2905,29 @@
 int /* PRIVATE */
 png_gamma_significant(png_fixed_point gamma_val)
 {
+   /* sRGB:       1/2.2 == 0.4545(45)
+    * AdobeRGB:   1/(2+51/256) ~= 0.45471 5dp
+    *
+    * So the correction from AdobeRGB to sRGB (output) is:
+    *
+    *    2.2/(2+51/256) == 1.00035524
+    *
+    * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/-
+    * 23).  Note that the Adobe choice seems to be something intended to give an
+    * exact number with 8 binary fractional digits - it is the closest to 2.2
+    * that is possible a base 2 .8p representation.
+    */
    return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
        gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
 }
-#endif
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
-#ifdef PNG_16BIT_SUPPORTED
+#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
 /* A local convenience routine. */
 static png_fixed_point
 png_product2(png_fixed_point a, png_fixed_point b)
 {
-   /* The required result is 1/a * 1/b; the following preserves accuracy. */
-#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+   /* The required result is a * b; the following preserves accuracy. */
+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Should now be unused */
    double r = a * 1E-5;
    r *= b;
    r = floor(r+.5);
@@ -3609,9 +2943,8 @@
 
    return 0; /* overflow */
 }
-#endif /* 16BIT */
+#endif /* FLOATING_ARITHMETIC */
 
-/* The inverse of the above. */
 png_fixed_point
 png_reciprocal2(png_fixed_point a, png_fixed_point b)
 {
@@ -4264,10 +3597,27 @@
  * tables, we don't make a full table if we are reducing to 8-bit in
  * the future.  Note also how the gamma_16 tables are segmented so that
  * we don't need to allocate > 64K chunks for a full 16-bit table.
+ *
+ * TODO: move this to pngrtran.c and make it static.  Better yet create
+ * pngcolor.c and put all the PNG_COLORSPACE stuff in there.
  */
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#  define GAMMA_TRANSFORMS 1 /* #ifdef CSE */
+#else
+#  define GAMMA_TRANSFORMS 0
+#endif
+
 void /* PRIVATE */
 png_build_gamma_table(png_structrp png_ptr, int bit_depth)
 {
+   png_fixed_point file_gamma, screen_gamma;
+   png_fixed_point correction;
+#  if GAMMA_TRANSFORMS
+      png_fixed_point file_to_linear, linear_to_screen;
+#  endif
+
    png_debug(1, "in png_build_gamma_table");
 
    /* Remove any existing table; this copes with multiple calls to
@@ -4282,27 +3632,44 @@
       png_destroy_gamma_table(png_ptr);
    }
 
+   /* The following fields are set, finally, in png_init_read_transformations.
+    * If file_gamma is 0 (unset) nothing can be done otherwise if screen_gamma
+    * is 0 (unset) there is no gamma correction but to/from linear is possible.
+    */
+   file_gamma = png_ptr->file_gamma;
+   screen_gamma = png_ptr->screen_gamma;
+#  if GAMMA_TRANSFORMS
+      file_to_linear = png_reciprocal(file_gamma);
+#  endif
+
+   if (screen_gamma > 0)
+   {
+#     if GAMMA_TRANSFORMS
+         linear_to_screen = png_reciprocal(screen_gamma);
+#     endif
+      correction = png_reciprocal2(screen_gamma, file_gamma);
+   }
+   else /* screen gamma unknown */
+   {
+#     if GAMMA_TRANSFORMS
+         linear_to_screen = file_gamma;
+#     endif
+      correction = PNG_FP_1;
+   }
+
    if (bit_depth <= 8)
    {
-      png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
-          png_ptr->screen_gamma > 0 ?
-          png_reciprocal2(png_ptr->colorspace.gamma,
-          png_ptr->screen_gamma) : PNG_FP_1);
+      png_build_8bit_table(png_ptr, &png_ptr->gamma_table, correction);
 
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
-   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
-   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#if GAMMA_TRANSFORMS
       if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
       {
-         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
-             png_reciprocal(png_ptr->colorspace.gamma));
+         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, file_to_linear);
 
          png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
-             png_ptr->screen_gamma > 0 ?
-             png_reciprocal(png_ptr->screen_gamma) :
-             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
+            linear_to_screen);
       }
-#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
+#endif /* GAMMA_TRANSFORMS */
    }
 #ifdef PNG_16BIT_SUPPORTED
    else
@@ -4368,22 +3735,17 @@
        * reduced to 8 bits.
        */
       if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)
-          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
-          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
-          png_ptr->screen_gamma) : PNG_FP_1);
-
+         png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
+            png_reciprocal(correction));
       else
-          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
-          png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
-          png_ptr->screen_gamma) : PNG_FP_1);
+         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
+            correction);
 
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
-   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
-   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#  if GAMMA_TRANSFORMS
       if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
       {
          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
-             png_reciprocal(png_ptr->colorspace.gamma));
+            file_to_linear);
 
          /* Notice that the '16 from 1' table should be full precision, however
           * the lookup on this table still uses gamma_shift, so it can't be.
@@ -4390,10 +3752,9 @@
           * TODO: fix this.
           */
          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
-             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
-             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
+            linear_to_screen);
       }
-#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
+#endif /* GAMMA_TRANSFORMS */
    }
 #endif /* 16BIT */
 }

Modified: trunk/Build/source/libs/libpng/libpng-src/png.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/png.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/png.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.46
+ * libpng version 1.6.47
  *
  * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -14,7 +14,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.46, January 2025:
+ *   libpng versions 1.6.36, December 2018, through 1.6.47, February 2025:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -238,7 +238,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.46                  16    10646  16.so.16.46[.0]
+ *    1.6.47                  16    10647  16.so.16.47[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -274,7 +274,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.46"
+#define PNG_LIBPNG_VER_STRING "1.6.47"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -285,7 +285,7 @@
 /* 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 46
+#define PNG_LIBPNG_VER_RELEASE 47
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -316,7 +316,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10646 /* 1.6.46 */
+#define PNG_LIBPNG_VER 10647 /* 1.6.47 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -426,7 +426,7 @@
 /* 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_46;
+typedef char* png_libpng_version_1_6_47;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *

Modified: trunk/Build/source/libs/libpng/libpng-src/pngconf.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngconf.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngconf.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
 /* pngconf.h - machine-configurable file for libpng
  *
- * libpng version 1.6.46
+ * libpng version 1.6.47
  *
  * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson

Modified: trunk/Build/source/libs/libpng/libpng-src/pngerror.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngerror.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngerror.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -935,23 +935,37 @@
 int /* PRIVATE */
 png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
 {
-   png_voidp saved_error_buf = image->opaque->error_buf;
+   const png_voidp saved_error_buf = image->opaque->error_buf;
    jmp_buf safe_jmpbuf;
-   int result;
 
    /* Safely execute function(arg), with png_error returning back here. */
    if (setjmp(safe_jmpbuf) == 0)
    {
+      int result;
+
       image->opaque->error_buf = safe_jmpbuf;
       result = function(arg);
       image->opaque->error_buf = saved_error_buf;
-      return result;
+
+      if (result)
+         return 1; /* success */
    }
 
-   /* On png_error, return via longjmp, pop the jmpbuf, and free the image. */
+   /* The function failed either because of a caught png_error and a regular
+    * return of false above or because of an uncaught png_error from the
+    * function itself.  Ensure that the error_buf is always set back to the
+    * value saved above:
+    */
    image->opaque->error_buf = saved_error_buf;
-   png_image_free(image);
-   return 0;
+
+   /* On the final false return, when about to return control to the caller, the
+    * image is freed (png_image_free does this check but it is duplicated here
+    * for clarity:
+    */
+   if (saved_error_buf == NULL)
+      png_image_free(image);
+
+   return 0; /* failure */
 }
 #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
 #endif /* READ || WRITE */

Modified: trunk/Build/source/libs/libpng/libpng-src/pngget.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngget.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngget.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -380,7 +380,13 @@
     * Notice that this can overflow - a warning is output and 0 is
     * returned.
     */
-   return png_muldiv_warn(png_ptr, microns, 500, 127);
+   png_fixed_point result;
+
+   if (png_muldiv(&result, microns, 500, 127) != 0)
+      return result;
+
+   png_warning(png_ptr, "fixed point overflow ignored");
+   return 0;
 }
 
 png_fixed_point PNGAPI
@@ -390,7 +396,7 @@
    return png_fixed_inches_from_microns(png_ptr,
        png_get_x_offset_microns(png_ptr, info_ptr));
 }
-#endif
+#endif /* FIXED_POINT */
 
 #ifdef PNG_FIXED_POINT_SUPPORTED
 png_fixed_point PNGAPI
@@ -518,44 +524,31 @@
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
 png_uint_32 PNGAPI
 png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
-    double *white_x, double *white_y, double *red_x, double *red_y,
-    double *green_x, double *green_y, double *blue_x, double *blue_y)
+    double *whitex, double *whitey, double *redx, double *redy,
+    double *greenx, double *greeny, double *bluex, double *bluey)
 {
    png_debug1(1, "in %s retrieval function", "cHRM");
 
-   /* Quiet API change: this code used to only return the end points if a cHRM
-    * chunk was present, but the end points can also come from iCCP or sRGB
-    * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and
-    * the png_set_ APIs merely check that set end points are mutually
-    * consistent.
-    */
+   /* PNGv3: this just returns the values store from the cHRM, if any. */
    if (png_ptr != NULL && info_ptr != NULL &&
-      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+       (info_ptr->valid & PNG_INFO_cHRM) != 0)
    {
-      if (white_x != NULL)
-         *white_x = png_float(png_ptr,
-             info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");
-      if (white_y != NULL)
-         *white_y = png_float(png_ptr,
-             info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y");
-      if (red_x != NULL)
-         *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx,
-             "cHRM red X");
-      if (red_y != NULL)
-         *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy,
-             "cHRM red Y");
-      if (green_x != NULL)
-         *green_x = png_float(png_ptr,
-             info_ptr->colorspace.end_points_xy.greenx, "cHRM green X");
-      if (green_y != NULL)
-         *green_y = png_float(png_ptr,
-             info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y");
-      if (blue_x != NULL)
-         *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex,
-             "cHRM blue X");
-      if (blue_y != NULL)
-         *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,
-             "cHRM blue Y");
+      if (whitex != NULL)
+         *whitex = png_float(png_ptr, info_ptr->cHRM.whitex, "cHRM wx");
+      if (whitey != NULL)
+         *whitey = png_float(png_ptr, info_ptr->cHRM.whitey, "cHRM wy");
+      if (redx   != NULL)
+         *redx   = png_float(png_ptr, info_ptr->cHRM.redx,   "cHRM rx");
+      if (redy   != NULL)
+         *redy   = png_float(png_ptr, info_ptr->cHRM.redy,   "cHRM ry");
+      if (greenx != NULL)
+         *greenx = png_float(png_ptr, info_ptr->cHRM.greenx, "cHRM gx");
+      if (greeny != NULL)
+         *greeny = png_float(png_ptr, info_ptr->cHRM.greeny, "cHRM gy");
+      if (bluex  != NULL)
+         *bluex  = png_float(png_ptr, info_ptr->cHRM.bluex,  "cHRM bx");
+      if (bluey  != NULL)
+         *bluey  = png_float(png_ptr, info_ptr->cHRM.bluey,  "cHRM by");
       return PNG_INFO_cHRM;
    }
 
@@ -568,38 +561,31 @@
     double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
     double *blue_Z)
 {
+   png_XYZ XYZ;
    png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
 
    if (png_ptr != NULL && info_ptr != NULL &&
-       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+       (info_ptr->valid & PNG_INFO_cHRM) != 0 &&
+       png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0)
    {
       if (red_X != NULL)
-         *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,
-             "cHRM red X");
+         *red_X = png_float(png_ptr, XYZ.red_X, "cHRM red X");
       if (red_Y != NULL)
-         *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y,
-             "cHRM red Y");
+         *red_Y = png_float(png_ptr, XYZ.red_Y, "cHRM red Y");
       if (red_Z != NULL)
-         *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z,
-             "cHRM red Z");
+         *red_Z = png_float(png_ptr, XYZ.red_Z, "cHRM red Z");
       if (green_X != NULL)
-         *green_X = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X");
+         *green_X = png_float(png_ptr, XYZ.green_X, "cHRM green X");
       if (green_Y != NULL)
-         *green_Y = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y");
+         *green_Y = png_float(png_ptr, XYZ.green_Y, "cHRM green Y");
       if (green_Z != NULL)
-         *green_Z = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z");
+         *green_Z = png_float(png_ptr, XYZ.green_Z, "cHRM green Z");
       if (blue_X != NULL)
-         *blue_X = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X");
+         *blue_X = png_float(png_ptr, XYZ.blue_X, "cHRM blue X");
       if (blue_Y != NULL)
-         *blue_Y = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y");
+         *blue_Y = png_float(png_ptr, XYZ.blue_Y, "cHRM blue Y");
       if (blue_Z != NULL)
-         *blue_Z = png_float(png_ptr,
-             info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");
+         *blue_Z = png_float(png_ptr, XYZ.blue_Z, "cHRM blue Z");
       return PNG_INFO_cHRM;
    }
 
@@ -616,29 +602,22 @@
     png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
     png_fixed_point *int_blue_Z)
 {
+   png_XYZ XYZ;
    png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
 
    if (png_ptr != NULL && info_ptr != NULL &&
-      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+       (info_ptr->valid & PNG_INFO_cHRM) != 0U &&
+       png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0)
    {
-      if (int_red_X != NULL)
-         *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;
-      if (int_red_Y != NULL)
-         *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y;
-      if (int_red_Z != NULL)
-         *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z;
-      if (int_green_X != NULL)
-         *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X;
-      if (int_green_Y != NULL)
-         *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y;
-      if (int_green_Z != NULL)
-         *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z;
-      if (int_blue_X != NULL)
-         *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X;
-      if (int_blue_Y != NULL)
-         *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;
-      if (int_blue_Z != NULL)
-         *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;
+      if (int_red_X != NULL) *int_red_X = XYZ.red_X;
+      if (int_red_Y != NULL) *int_red_Y = XYZ.red_Y;
+      if (int_red_Z != NULL) *int_red_Z = XYZ.red_Z;
+      if (int_green_X != NULL) *int_green_X = XYZ.green_X;
+      if (int_green_Y != NULL) *int_green_Y = XYZ.green_Y;
+      if (int_green_Z != NULL) *int_green_Z = XYZ.green_Z;
+      if (int_blue_X != NULL) *int_blue_X = XYZ.blue_X;
+      if (int_blue_Y != NULL) *int_blue_Y = XYZ.blue_Y;
+      if (int_blue_Z != NULL) *int_blue_Z = XYZ.blue_Z;
       return PNG_INFO_cHRM;
    }
 
@@ -647,31 +626,24 @@
 
 png_uint_32 PNGAPI
 png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
-    png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,
-    png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,
-    png_fixed_point *blue_x, png_fixed_point *blue_y)
+    png_fixed_point *whitex, png_fixed_point *whitey, png_fixed_point *redx,
+    png_fixed_point *redy, png_fixed_point *greenx, png_fixed_point *greeny,
+    png_fixed_point *bluex, png_fixed_point *bluey)
 {
    png_debug1(1, "in %s retrieval function", "cHRM");
 
+   /* PNGv3: this just returns the values store from the cHRM, if any. */
    if (png_ptr != NULL && info_ptr != NULL &&
-      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+       (info_ptr->valid & PNG_INFO_cHRM) != 0)
    {
-      if (white_x != NULL)
-         *white_x = info_ptr->colorspace.end_points_xy.whitex;
-      if (white_y != NULL)
-         *white_y = info_ptr->colorspace.end_points_xy.whitey;
-      if (red_x != NULL)
-         *red_x = info_ptr->colorspace.end_points_xy.redx;
-      if (red_y != NULL)
-         *red_y = info_ptr->colorspace.end_points_xy.redy;
-      if (green_x != NULL)
-         *green_x = info_ptr->colorspace.end_points_xy.greenx;
-      if (green_y != NULL)
-         *green_y = info_ptr->colorspace.end_points_xy.greeny;
-      if (blue_x != NULL)
-         *blue_x = info_ptr->colorspace.end_points_xy.bluex;
-      if (blue_y != NULL)
-         *blue_y = info_ptr->colorspace.end_points_xy.bluey;
+      if (whitex != NULL) *whitex = info_ptr->cHRM.whitex;
+      if (whitey != NULL) *whitey = info_ptr->cHRM.whitey;
+      if (redx   != NULL) *redx   = info_ptr->cHRM.redx;
+      if (redy   != NULL) *redy   = info_ptr->cHRM.redy;
+      if (greenx != NULL) *greenx = info_ptr->cHRM.greenx;
+      if (greeny != NULL) *greeny = info_ptr->cHRM.greeny;
+      if (bluex  != NULL) *bluex  = info_ptr->cHRM.bluex;
+      if (bluey  != NULL) *bluey  = info_ptr->cHRM.bluey;
       return PNG_INFO_cHRM;
    }
 
@@ -688,11 +660,11 @@
 {
    png_debug1(1, "in %s retrieval function", "gAMA");
 
+   /* PNGv3 compatibility: only report gAMA if it is really present. */
    if (png_ptr != NULL && info_ptr != NULL &&
-       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
-       file_gamma != NULL)
+       (info_ptr->valid & PNG_INFO_gAMA) != 0)
    {
-      *file_gamma = info_ptr->colorspace.gamma;
+      if (file_gamma != NULL) *file_gamma = info_ptr->gamma;
       return PNG_INFO_gAMA;
    }
 
@@ -707,12 +679,13 @@
 {
    png_debug1(1, "in %s retrieval function", "gAMA(float)");
 
+   /* PNGv3 compatibility: only report gAMA if it is really present. */
    if (png_ptr != NULL && info_ptr != NULL &&
-      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
-      file_gamma != NULL)
+       (info_ptr->valid & PNG_INFO_gAMA) != 0)
    {
-      *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,
-          "png_get_gAMA");
+      if (file_gamma != NULL)
+         *file_gamma = png_float(png_ptr, info_ptr->gamma, "gAMA");
+
       return PNG_INFO_gAMA;
    }
 
@@ -729,9 +702,10 @@
    png_debug1(1, "in %s retrieval function", "sRGB");
 
    if (png_ptr != NULL && info_ptr != NULL &&
-      (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL)
+      (info_ptr->valid & PNG_INFO_sRGB) != 0)
    {
-      *file_srgb_intent = info_ptr->colorspace.rendering_intent;
+      if (file_srgb_intent != NULL)
+         *file_srgb_intent = info_ptr->rendering_intent;
       return PNG_INFO_sRGB;
    }
 

Modified: trunk/Build/source/libs/libpng/libpng-src/pnginfo.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pnginfo.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pnginfo.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -86,20 +86,6 @@
     * and initialize the appropriate fields below.
     */
 
-#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
-   /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are
-    * defined.  When COLORSPACE is switched on all the colorspace-defining
-    * chunks should be enabled, when GAMMA is switched on all the gamma-defining
-    * chunks should be enabled.  If this is not done it becomes possible to read
-    * inconsistent PNG files and assign a probably incorrect interpretation to
-    * the information.  (In other words, by carefully choosing which chunks to
-    * recognize the system configuration can select an interpretation for PNG
-    * files containing ambiguous data and this will result in inconsistent
-    * behavior between different libpng builds!)
-    */
-   png_colorspace colorspace;
-#endif
-
 #ifdef PNG_cICP_SUPPORTED
    /* cICP chunk data */
    png_byte cicp_colour_primaries;
@@ -211,11 +197,8 @@
 #endif
 
 #ifdef PNG_eXIf_SUPPORTED
-   int num_exif;  /* Added at libpng-1.6.31 */
+   png_uint_32 num_exif;  /* Added at libpng-1.6.31 */
    png_bytep exif;
-# ifdef PNG_READ_eXIf_SUPPORTED
-   png_bytep eXIf_buf;  /* Added at libpng-1.6.32 */
-# endif
 #endif
 
 #ifdef PNG_hIST_SUPPORTED
@@ -288,5 +271,16 @@
    png_bytepp row_pointers;        /* the image bits */
 #endif
 
+#ifdef PNG_cHRM_SUPPORTED
+   png_xy cHRM;
+#endif
+
+#ifdef PNG_gAMA_SUPPORTED
+   png_fixed_point gamma;
+#endif
+
+#ifdef PNG_sRGB_SUPPORTED
+   int rendering_intent;
+#endif
 };
 #endif /* PNGINFO_H */

Modified: trunk/Build/source/libs/libpng/libpng-src/pnglibconf.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pnglibconf.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pnglibconf.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.6.46 */
+/* libpng version 1.6.47 */
 
 /* Copyright (c) 2018-2025 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */

Modified: trunk/Build/source/libs/libpng/libpng-src/pngmem.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngmem.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngmem.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -72,30 +72,29 @@
     * to implement a user memory handler.  This checks to be sure it isn't
     * called with big numbers.
     */
-#ifndef PNG_USER_MEM_SUPPORTED
-   PNG_UNUSED(png_ptr)
-#endif
+#  ifdef PNG_MAX_MALLOC_64K
+      /* This is support for legacy systems which had segmented addressing
+       * limiting the maximum allocation size to 65536.  It takes precedence
+       * over PNG_SIZE_MAX which is set to 65535 on true 16-bit systems.
+       *
+       * TODO: libpng-1.8: finally remove both cases.
+       */
+      if (size > 65536U) return NULL;
+#  endif
 
-   /* Some compilers complain that this is always true.  However, it
-    * can be false when integer overflow happens.
+   /* This is checked too because the system malloc call below takes a (size_t).
     */
-   if (size > 0 && size <= PNG_SIZE_MAX
-#     ifdef PNG_MAX_MALLOC_64K
-         && size <= 65536U
-#     endif
-      )
-   {
-#ifdef PNG_USER_MEM_SUPPORTED
+   if (size > PNG_SIZE_MAX) return NULL;
+
+#  ifdef PNG_USER_MEM_SUPPORTED
       if (png_ptr != NULL && png_ptr->malloc_fn != NULL)
          return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size);
+#  else
+      PNG_UNUSED(png_ptr)
+#  endif
 
-      else
-#endif
-         return malloc((size_t)size); /* checked for truncation above */
-   }
-
-   else
-      return NULL;
+   /* Use the system malloc */
+   return malloc((size_t)/*SAFE*/size); /* checked for truncation above */
 }
 
 #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\

Modified: trunk/Build/source/libs/libpng/libpng-src/pngpread.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngpread.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngpread.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -193,17 +193,8 @@
     */
    if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)
    {
-      png_byte chunk_length[4];
-      png_byte chunk_tag[4];
-
       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
-      png_push_fill_buffer(png_ptr, chunk_length, 4);
-      png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
-      png_reset_crc(png_ptr);
-      png_crc_read(png_ptr, chunk_tag, 4);
-      png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
-      png_check_chunk_name(png_ptr, png_ptr->chunk_name);
-      png_check_chunk_length(png_ptr, png_ptr->push_length);
+      png_ptr->push_length = png_read_chunk_header(png_ptr);
       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
    }
 
@@ -244,13 +235,13 @@
          png_error(png_ptr, "Invalid IHDR length");
 
       PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
    }
 
    else if (chunk_name == png_IEND)
    {
       PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
 
       png_ptr->process_mode = PNG_READ_DONE_MODE;
       png_push_have_end(png_ptr, info_ptr);
@@ -267,12 +258,6 @@
    }
 #endif
 
-   else if (chunk_name == png_PLTE)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
    else if (chunk_name == png_IDAT)
    {
       png_ptr->idat_size = png_ptr->push_length;
@@ -285,179 +270,10 @@
       return;
    }
 
-#ifdef PNG_READ_gAMA_SUPPORTED
-   else if (png_ptr->chunk_name == png_gAMA)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_sBIT_SUPPORTED
-   else if (png_ptr->chunk_name == png_sBIT)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_cHRM_SUPPORTED
-   else if (png_ptr->chunk_name == png_cHRM)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_cICP_SUPPORTED
-   else if (png_ptr->chunk_name == png_cICP)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_cLLI_SUPPORTED
-   else if (png_ptr->chunk_name == png_cLLI)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_cLLI(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_mDCV_SUPPORTED
-   else if (png_ptr->chunk_name == png_mDCV)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_mDCV(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_eXIf_SUPPORTED
-   else if (png_ptr->chunk_name == png_eXIf)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_eXIf(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_sRGB_SUPPORTED
-   else if (chunk_name == png_sRGB)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_iCCP_SUPPORTED
-   else if (png_ptr->chunk_name == png_iCCP)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_sPLT_SUPPORTED
-   else if (chunk_name == png_sPLT)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_tRNS_SUPPORTED
-   else if (chunk_name == png_tRNS)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_bKGD_SUPPORTED
-   else if (chunk_name == png_bKGD)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_hIST_SUPPORTED
-   else if (chunk_name == png_hIST)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_pHYs_SUPPORTED
-   else if (chunk_name == png_pHYs)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_oFFs_SUPPORTED
-   else if (chunk_name == png_oFFs)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
-   }
-#endif
-
-#ifdef PNG_READ_pCAL_SUPPORTED
-   else if (chunk_name == png_pCAL)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_sCAL_SUPPORTED
-   else if (chunk_name == png_sCAL)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_tIME_SUPPORTED
-   else if (chunk_name == png_tIME)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_tEXt_SUPPORTED
-   else if (chunk_name == png_tEXt)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_zTXt_SUPPORTED
-   else if (chunk_name == png_zTXt)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
-   }
-
-#endif
-#ifdef PNG_READ_iTXt_SUPPORTED
-   else if (chunk_name == png_iTXt)
-   {
-      PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
-   }
-#endif
-
    else
    {
       PNG_PUSH_SAVE_BUFFER_IF_FULL
-      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,
-          PNG_HANDLE_CHUNK_AS_DEFAULT);
+      png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
    }
 
    png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;

Modified: trunk/Build/source/libs/libpng/libpng-src/pngpriv.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngpriv.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngpriv.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -671,7 +671,7 @@
 #define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200U
 #define PNG_FLAG_CRC_CRITICAL_USE         0x0400U
 #define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800U
-#define PNG_FLAG_ASSUME_sRGB              0x1000U /* Added to libpng-1.5.4 */
+/*      PNG_FLAG_ASSUME_sRGB unused       0x1000U  * Added to libpng-1.5.4 */
 #define PNG_FLAG_OPTIMIZE_ALPHA           0x2000U /* Added to libpng-1.5.4 */
 #define PNG_FLAG_DETECT_UNINITIALIZED     0x4000U /* Added to libpng-1.5.4 */
 /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */
@@ -802,11 +802,31 @@
  *
  * PNG_32b correctly produces a value shifted by up to 24 bits, even on
  * architectures where (int) is only 16 bits.
+ *
+ * 1.6.47: PNG_32b was made into a preprocessor evaluable macro by replacing the
+ * static_cast with a promoting binary operation using a guaranteed 32-bit
+ * (minimum) unsigned value.
  */
-#define PNG_32b(b,s) ((png_uint_32)(b) << (s))
+#define PNG_32b(b,s) (((0xFFFFFFFFU)&(b)) << (s))
 #define PNG_U32(b1,b2,b3,b4) \
    (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))
 
+/* Chunk name validation.  When using these macros all the arguments should be
+ * constants, otherwise code bloat may well occur.  The macros are provided
+ * primarily for use in #if checks.
+ *
+ * PNG_32to8 produces a byte value with the right shift; used to extract the
+ * byte value from a chunk name.
+ */
+#define PNG_32to8(cn,s) (((cn) >> (s)) & 0xffU)
+#define PNG_CN_VALID_UPPER(b) ((b) >= 65 && (b) <= 90) /* upper-case ASCII */
+#define PNG_CN_VALID_ASCII(b) PNG_CN_VALID_UPPER((b) & ~32U)
+#define PNG_CHUNK_NAME_VALID(cn) (\
+   PNG_CN_VALID_ASCII(PNG_32to8(cn,24)) && /* critical, !ancillary */\
+   PNG_CN_VALID_ASCII(PNG_32to8(cn,16)) && /* public, !privately defined */\
+   PNG_CN_VALID_UPPER(PNG_32to8(cn, 8)) && /* VALID, !reserved */\
+   PNG_CN_VALID_ASCII(PNG_32to8(cn, 0))   /* data-dependent, !copy ok */)
+
 /* Constants for known chunk types.
  *
  * MAINTAINERS: If you need to add a chunk, define the name here.
@@ -834,11 +854,14 @@
 #define png_IEND PNG_U32( 73,  69,  78,  68)
 #define png_IHDR PNG_U32( 73,  72,  68,  82)
 #define png_PLTE PNG_U32( 80,  76,  84,  69)
+#define png_acTL PNG_U32( 97,  99,  84,  76) /* PNGv3: APNG */
 #define png_bKGD PNG_U32( 98,  75,  71,  68)
 #define png_cHRM PNG_U32( 99,  72,  82,  77)
 #define png_cICP PNG_U32( 99,  73,  67,  80) /* PNGv3 */
 #define png_cLLI PNG_U32( 99,  76,  76,  73) /* PNGv3 */
 #define png_eXIf PNG_U32(101,  88,  73, 102) /* registered July 2017 */
+#define png_fcTL PNG_U32(102,  99,  84,  76) /* PNGv3: APNG */
+#define png_fdAT PNG_U32(102, 100,  65,  84) /* PNGv3: APNG */
 #define png_fRAc PNG_U32(102,  82,  65,  99) /* registered, not defined */
 #define png_gAMA PNG_U32(103,  65,  77,  65)
 #define png_gIFg PNG_U32(103,  73,  70, 103)
@@ -888,11 +911,74 @@
 #define PNG_CHUNK_RESERVED(c)     (1 & ((c) >> 13))
 #define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >>  5))
 
+/* Known chunks.  All supported chunks must be listed here.  The macro PNG_CHUNK
+ * contains the four character ASCII name by which the chunk is identified.  The
+ * macro is implemented as required to build tables or switch statements which
+ * require entries for every known chunk.  The macro also contains an index
+ * value which should be in order (this is checked in png.c).
+ *
+ * Notice that "known" does not require "SUPPORTED"; tables should be built in
+ * such a way that chunks unsupported in a build require no more than the table
+ * entry (which should be small.)  In particular function pointers for
+ * unsupported chunks should be NULL.
+ *
+ * At present these index values are not exported (not part of the public API)
+ * so can be changed at will.  For convenience the names are in lexical sort
+ * order but with the critical chunks at the start in the order of occurence in
+ * a PNG.
+ *
+ * PNG_INFO_ values do not exist for every one of these chunk handles; for
+ * example PNG_INFO_{IDAT,IEND,tEXt,iTXt,zTXt} and possibly other chunks in the
+ * future.
+ */
+#define PNG_KNOWN_CHUNKS\
+   PNG_CHUNK(IHDR,  0)\
+   PNG_CHUNK(PLTE,  1)\
+   PNG_CHUNK(IDAT,  2)\
+   PNG_CHUNK(IEND,  3)\
+   PNG_CHUNK(acTL,  4)\
+   PNG_CHUNK(bKGD,  5)\
+   PNG_CHUNK(cHRM,  6)\
+   PNG_CHUNK(cICP,  7)\
+   PNG_CHUNK(cLLI,  8)\
+   PNG_CHUNK(eXIf,  9)\
+   PNG_CHUNK(fcTL, 10)\
+   PNG_CHUNK(fdAT, 11)\
+   PNG_CHUNK(gAMA, 12)\
+   PNG_CHUNK(hIST, 13)\
+   PNG_CHUNK(iCCP, 14)\
+   PNG_CHUNK(iTXt, 15)\
+   PNG_CHUNK(mDCV, 16)\
+   PNG_CHUNK(oFFs, 17)\
+   PNG_CHUNK(pCAL, 18)\
+   PNG_CHUNK(pHYs, 19)\
+   PNG_CHUNK(sBIT, 20)\
+   PNG_CHUNK(sCAL, 21)\
+   PNG_CHUNK(sPLT, 22)\
+   PNG_CHUNK(sRGB, 23)\
+   PNG_CHUNK(tEXt, 24)\
+   PNG_CHUNK(tIME, 25)\
+   PNG_CHUNK(tRNS, 26)\
+   PNG_CHUNK(zTXt, 27)
+
 /* Gamma values (new at libpng-1.5.4): */
 #define PNG_GAMMA_MAC_OLD 151724  /* Assume '1.8' is really 2.2/1.45! */
 #define PNG_GAMMA_MAC_INVERSE 65909
 #define PNG_GAMMA_sRGB_INVERSE 45455
 
+/* gamma sanity check.  libpng cannot implement gamma transforms outside a
+ * certain limit because of its use of 16-bit fixed point intermediate values.
+ * Gamma values that are too large or too small will zap the 16-bit values all
+ * to 0 or 65535 resulting in an obvious 'bad' image.
+ *
+ * In libpng 1.6.0 the limits were changed from 0.07..3 to 0.01..100 to
+ * accommodate the optimal 16-bit gamma of 36 and its reciprocal.
+ *
+ * These are png_fixed_point integral values:
+ */
+#define PNG_LIB_GAMMA_MIN 1000
+#define PNG_LIB_GAMMA_MAX 10000000
+
 /* Almost everything below is C specific; the #defines above can be used in
  * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.
  */
@@ -956,7 +1042,6 @@
  *
  * All of these functions must be declared with PNG_INTERNAL_FUNCTION.
  */
-
 /* Zlib support */
 #define PNG_UNEXPECTED_ZLIB_RETURN (-7)
 PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret),
@@ -996,6 +1081,25 @@
 PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,
    png_const_charp user_png_ver),PNG_EMPTY);
 
+#ifdef PNG_READ_SUPPORTED /* should only be used on read */
+/* Security: read limits on the largest allocations while reading a PNG.  This
+ * avoids very large allocations caused by PNG files with damaged or altered
+ * chunk 'length' fields.
+ */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* run-time limit */
+#  define png_chunk_max(png_ptr) ((png_ptr)->user_chunk_malloc_max)
+
+#elif PNG_USER_CHUNK_MALLOC_MAX > 0 /* compile-time limit */
+#  define png_chunk_max(png_ptr) ((void)png_ptr, PNG_USER_CHUNK_MALLOC_MAX)
+
+#elif (defined PNG_MAX_MALLOC_64K)  /* legacy system limit */
+#  define png_chunk_max(png_ptr) ((void)png_ptr, 65536U)
+
+#else                               /* modern system limit SIZE_MAX (C99) */
+#  define png_chunk_max(png_ptr) ((void)png_ptr, PNG_SIZE_MAX)
+#endif
+#endif /* READ */
+
 /* Internal base allocator - no messages, NULL on failure to allocate.  This
  * does, however, call the application provided allocator and that could call
  * png_error (although that would be a bug in the application implementation.)
@@ -1095,9 +1199,6 @@
 PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,
    png_uint_32 skip),PNG_EMPTY);
 
-/* Read the CRC from the file and compare it to the libpng calculated CRC */
-PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY);
-
 /* Calculate the CRC over a section of data.  Note that we are only
  * passing a maximum of 64K on systems that have this as a memory limit,
  * since this is the maximum buffer size we can specify.
@@ -1175,10 +1276,10 @@
 
 #ifdef PNG_WRITE_iCCP_SUPPORTED
 PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,
-   png_const_charp name, png_const_bytep profile), PNG_EMPTY);
-   /* The profile must have been previously validated for correctness, the
-    * length comes from the first four bytes.  Only the base, deflate,
-    * compression is supported.
+   png_const_charp name, png_const_bytep profile, png_uint_32 proflen),
+   PNG_EMPTY);
+   /* Writes a previously 'set' profile.  The profile argument is **not**
+    * compressed.
     */
 #endif
 
@@ -1487,128 +1588,24 @@
 /* The following decodes the appropriate chunks, and does error correction,
  * then calls the appropriate callback for the chunk if it is valid.
  */
+typedef enum
+{
+   /* Result of a call to png_handle_chunk made to handle the current chunk
+    * png_struct::chunk_name on read.  Always informational, either the stream
+    * is read for the next chunk or the routine will call png_error.
+    *
+    * NOTE: order is important internally.  handled_saved and above are regarded
+    * as handling the chunk.
+    */
+   handled_error = 0,  /* bad crc or known and bad format or too long */
+   handled_discarded,  /* not saved in the unknown chunk list */
+   handled_saved,      /* saved in the unknown chunk list */
+   handled_ok          /* known, supported and handled without error */
+} png_handle_result_code;
 
-/* Decode the IHDR chunk */
-PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-
-#ifdef PNG_READ_bKGD_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_cHRM_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_cICP_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_cICP,(png_structrp png_ptr,
-        png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_cLLI_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_cLLI,(png_structrp png_ptr,
-        png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_eXIf_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_gAMA_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_hIST_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_iCCP_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif /* READ_iCCP */
-
-#ifdef PNG_READ_iTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_mDCV_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_mDCV,(png_structrp png_ptr,
-        png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_oFFs_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_pCAL_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_pHYs_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_sBIT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_sCAL_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_sPLT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif /* READ_sPLT */
-
-#ifdef PNG_READ_sRGB_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_tEXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_tIME_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_tRNS_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-#ifdef PNG_READ_zTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-#endif
-
-PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr,
-    png_uint_32 chunk_name),PNG_EMPTY);
-
-PNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr,
-    png_uint_32 chunk_length),PNG_EMPTY);
-
-PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_unknown,
+    (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),
+    PNG_EMPTY);
    /* This is the function that gets called for unknown chunks.  The 'keep'
     * argument is either non-zero for a known chunk that has been set to be
     * handled as unknown or zero for an unknown chunk.  By default the function
@@ -1615,6 +1612,12 @@
     * just skips the chunk or errors out if it is critical.
     */
 
+PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_chunk,
+    (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
+   /* This handles the current chunk png_ptr->chunk_name with unread
+    * data[length] and returns one of the above result codes.
+    */
+
 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
     defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
 PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
@@ -1654,8 +1657,6 @@
     png_bytep buffer, size_t buffer_length),PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr),
     PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr,
-   png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr,
    png_inforp info_ptr),PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr,
@@ -1668,109 +1669,28 @@
     png_inforp info_ptr),PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr),
     PNG_EMPTY);
-#  ifdef PNG_READ_tEXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-#  endif
-#  ifdef PNG_READ_zTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-#  endif
-#  ifdef PNG_READ_iTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-#  endif
-
 #endif /* PROGRESSIVE_READ */
 
-/* Added at libpng version 1.6.0 */
-#ifdef PNG_GAMMA_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,
-    png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY);
-   /* Set the colorspace gamma with a value provided by the application or by
-    * the gAMA chunk on read.  The value will override anything set by an ICC
-    * profile.
-    */
-
-PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr,
-    png_inforp info_ptr), PNG_EMPTY);
-   /* Synchronize the info 'valid' flags with the colorspace */
-
-PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,
-    png_inforp info_ptr), PNG_EMPTY);
-   /* Copy the png_struct colorspace to the info_struct and call the above to
-    * synchronize the flags.  Checks for NULL info_ptr and does nothing.
-    */
-#endif
-
-/* Added at libpng version 1.4.0 */
-#ifdef PNG_COLORSPACE_SUPPORTED
-/* These internal functions are for maintaining the colorspace structure within
- * a png_info or png_struct (or, indeed, both).
- */
-PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities,
-   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy,
-    int preferred), PNG_EMPTY);
-
-PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints,
-   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ,
-    int preferred), PNG_EMPTY);
-
-#ifdef PNG_sRGB_SUPPORTED
-PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr,
-   png_colorspacerp colorspace, int intent), PNG_EMPTY);
-   /* This does set the colorspace gAMA and cHRM values too, but doesn't set the
-    * flags to write them, if it returns false there was a problem and an error
-    * message has already been output (but the colorspace may still need to be
-    * synced to record the invalid flag).
-    */
-#endif /* sRGB */
-
 #ifdef PNG_iCCP_SUPPORTED
-PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr,
-   png_colorspacerp colorspace, png_const_charp name,
-   png_uint_32 profile_length, png_const_bytep profile, int color_type),
-   PNG_EMPTY);
-   /* The 'name' is used for information only */
-
 /* Routines for checking parts of an ICC profile. */
 #ifdef PNG_READ_iCCP_SUPPORTED
 PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr,
-   png_colorspacerp colorspace, png_const_charp name,
-   png_uint_32 profile_length), PNG_EMPTY);
+   png_const_charp name, png_uint_32 profile_length), PNG_EMPTY);
 #endif /* READ_iCCP */
 PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr,
-   png_colorspacerp colorspace, png_const_charp name,
-   png_uint_32 profile_length,
+   png_const_charp name, png_uint_32 profile_length,
    png_const_bytep profile /* first 132 bytes only */, int color_type),
    PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,
-   png_colorspacerp colorspace, png_const_charp name,
-   png_uint_32 profile_length,
+   png_const_charp name, png_uint_32 profile_length,
    png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);
-#ifdef PNG_sRGB_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,(
-   png_const_structrp png_ptr, png_colorspacerp colorspace,
-   png_const_bytep profile, uLong adler), PNG_EMPTY);
-   /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may
-    * be zero to indicate that it is not available.  It is used, if provided,
-    * as a fast check on the profile when checking to see if it is sRGB.
-    */
-#endif
 #endif /* iCCP */
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients,
-   (png_structrp png_ptr), PNG_EMPTY);
-   /* Set the rgb_to_gray coefficients from the colorspace Y values */
+PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients, (png_structrp png_ptr),
+   PNG_EMPTY);
+   /* Set the rgb_to_gray coefficients from the cHRM Y values (if unset) */
 #endif /* READ_RGB_TO_GRAY */
-#endif /* COLORSPACE */
 
 /* Added at libpng version 1.4.0 */
 PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,
@@ -2032,8 +1952,10 @@
    size_t size),PNG_EMPTY);
 #endif /* pCAL || sCAL */
 
-#if defined(PNG_GAMMA_SUPPORTED) ||\
-    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
+#if defined(PNG_READ_GAMMA_SUPPORTED) ||\
+    defined(PNG_COLORSPACE_SUPPORTED) ||\
+    defined(PNG_INCH_CONVERSIONS_SUPPORTED) ||\
+    defined(PNG_READ_pHYs_SUPPORTED)
 /* Added at libpng version 1.5.0 */
 /* This is a utility to provide a*times/div (rounded) and indicate
  * if there is an overflow.  The result is a boolean - false (0)
@@ -2042,16 +1964,7 @@
  */
 PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a,
    png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY);
-#endif
 
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
-/* Same deal, but issue a warning on overflow and return 0. */
-PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn,
-   (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by,
-   png_int_32 divided_by),PNG_EMPTY);
-#endif
-
-#ifdef PNG_GAMMA_SUPPORTED
 /* Calculate a reciprocal - used for gamma values.  This returns
  * 0 if the argument is 0 in order to maintain an undefined value;
  * there are no warnings.
@@ -2058,6 +1971,7 @@
  */
 PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
    PNG_EMPTY);
+#endif
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
 /* The same but gives a reciprocal of the product of two fixed point
@@ -2066,14 +1980,22 @@
  */
 PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a,
    png_fixed_point b),PNG_EMPTY);
-#endif
 
 /* Return true if the gamma value is significantly different from 1.0 */
 PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),
    PNG_EMPTY);
-#endif
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
+/* PNGv3: 'resolve' the file gamma according to the new PNGv3 rules for colour
+ * space information.
+ *
+ * NOTE: this uses precisely those chunks that libpng supports.  For example it
+ * doesn't use iCCP and it can only use cICP for known and manageable
+ * transforms.  For this reason a gamma specified by png_set_gamma always takes
+ * precedence.
+ */
+PNG_INTERNAL_FUNCTION(png_fixed_point,png_resolve_file_gamma,
+   (png_const_structrp png_ptr),PNG_EMPTY);
+
 /* Internal fixed point gamma correction.  These APIs are called as
  * required to convert single values - they don't need to be fast,
  * they are not used when processing image pixel values.
@@ -2091,8 +2013,24 @@
    PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,
    int bit_depth),PNG_EMPTY);
+#endif /* READ_GAMMA */
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+/* Set the RGB coefficients if not already set by png_set_rgb_to_gray */
+PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients,(png_structrp png_ptr),
+   PNG_EMPTY);
 #endif
 
+#if defined(PNG_cHRM_SUPPORTED) || defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+PNG_INTERNAL_FUNCTION(int,png_XYZ_from_xy,(png_XYZ *XYZ, const png_xy *xy),
+   PNG_EMPTY);
+#endif /* cHRM || READ_RGB_TO_GRAY */
+
+#ifdef PNG_COLORSPACE_SUPPORTED
+PNG_INTERNAL_FUNCTION(int,png_xy_from_XYZ,(png_xy *xy, const png_XYZ *XYZ),
+   PNG_EMPTY);
+#endif
+
 /* SIMPLIFIED READ/WRITE SUPPORT */
 #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
    defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

Modified: trunk/Build/source/libs/libpng/libpng-src/pngread.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngread.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngread.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -131,14 +131,11 @@
          png_ptr->mode |= PNG_AFTER_IDAT;
       }
 
-      /* This should be a binary subdivision search or a hash for
-       * matching the chunk name rather than a linear search.
-       */
       if (chunk_name == png_IHDR)
-         png_handle_IHDR(png_ptr, info_ptr, length);
+         png_handle_chunk(png_ptr, info_ptr, length);
 
       else if (chunk_name == png_IEND)
-         png_handle_IEND(png_ptr, info_ptr, length);
+         png_handle_chunk(png_ptr, info_ptr, length);
 
 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
       else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
@@ -155,8 +152,6 @@
          }
       }
 #endif
-      else if (chunk_name == png_PLTE)
-         png_handle_PLTE(png_ptr, info_ptr, length);
 
       else if (chunk_name == png_IDAT)
       {
@@ -164,114 +159,8 @@
          break;
       }
 
-#ifdef PNG_READ_bKGD_SUPPORTED
-      else if (chunk_name == png_bKGD)
-         png_handle_bKGD(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cHRM_SUPPORTED
-      else if (chunk_name == png_cHRM)
-         png_handle_cHRM(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cICP_SUPPORTED
-      else if (chunk_name == png_cICP)
-         png_handle_cICP(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cLLI_SUPPORTED
-      else if (chunk_name == png_cLLI)
-         png_handle_cLLI(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_eXIf_SUPPORTED
-      else if (chunk_name == png_eXIf)
-         png_handle_eXIf(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_gAMA_SUPPORTED
-      else if (chunk_name == png_gAMA)
-         png_handle_gAMA(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_hIST_SUPPORTED
-      else if (chunk_name == png_hIST)
-         png_handle_hIST(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_mDCV_SUPPORTED
-      else if (chunk_name == png_mDCV)
-         png_handle_mDCV(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_oFFs_SUPPORTED
-      else if (chunk_name == png_oFFs)
-         png_handle_oFFs(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_pCAL_SUPPORTED
-      else if (chunk_name == png_pCAL)
-         png_handle_pCAL(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sCAL_SUPPORTED
-      else if (chunk_name == png_sCAL)
-         png_handle_sCAL(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_pHYs_SUPPORTED
-      else if (chunk_name == png_pHYs)
-         png_handle_pHYs(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sBIT_SUPPORTED
-      else if (chunk_name == png_sBIT)
-         png_handle_sBIT(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sRGB_SUPPORTED
-      else if (chunk_name == png_sRGB)
-         png_handle_sRGB(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_iCCP_SUPPORTED
-      else if (chunk_name == png_iCCP)
-         png_handle_iCCP(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sPLT_SUPPORTED
-      else if (chunk_name == png_sPLT)
-         png_handle_sPLT(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tEXt_SUPPORTED
-      else if (chunk_name == png_tEXt)
-         png_handle_tEXt(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tIME_SUPPORTED
-      else if (chunk_name == png_tIME)
-         png_handle_tIME(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tRNS_SUPPORTED
-      else if (chunk_name == png_tRNS)
-         png_handle_tRNS(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_zTXt_SUPPORTED
-      else if (chunk_name == png_zTXt)
-         png_handle_zTXt(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_iTXt_SUPPORTED
-      else if (chunk_name == png_iTXt)
-         png_handle_iTXt(png_ptr, info_ptr, length);
-#endif
-
       else
-         png_handle_unknown(png_ptr, info_ptr, length,
-             PNG_HANDLE_CHUNK_AS_DEFAULT);
+         png_handle_chunk(png_ptr, info_ptr, length);
    }
 }
 #endif /* SEQUENTIAL_READ */
@@ -816,10 +705,10 @@
          png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
 
       if (chunk_name == png_IEND)
-         png_handle_IEND(png_ptr, info_ptr, length);
+         png_handle_chunk(png_ptr, info_ptr, length);
 
       else if (chunk_name == png_IHDR)
-         png_handle_IHDR(png_ptr, info_ptr, length);
+         png_handle_chunk(png_ptr, info_ptr, length);
 
       else if (info_ptr == NULL)
          png_crc_finish(png_ptr, length);
@@ -853,117 +742,9 @@
 
          png_crc_finish(png_ptr, length);
       }
-      else if (chunk_name == png_PLTE)
-         png_handle_PLTE(png_ptr, info_ptr, length);
 
-#ifdef PNG_READ_bKGD_SUPPORTED
-      else if (chunk_name == png_bKGD)
-         png_handle_bKGD(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cHRM_SUPPORTED
-      else if (chunk_name == png_cHRM)
-         png_handle_cHRM(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cICP_SUPPORTED
-      else if (chunk_name == png_cICP)
-         png_handle_cICP(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_cLLI_SUPPORTED
-      else if (chunk_name == png_cLLI)
-         png_handle_cLLI(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_eXIf_SUPPORTED
-      else if (chunk_name == png_eXIf)
-         png_handle_eXIf(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_gAMA_SUPPORTED
-      else if (chunk_name == png_gAMA)
-         png_handle_gAMA(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_hIST_SUPPORTED
-      else if (chunk_name == png_hIST)
-         png_handle_hIST(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_mDCV_SUPPORTED
-      else if (chunk_name == png_mDCV)
-         png_handle_mDCV(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_oFFs_SUPPORTED
-      else if (chunk_name == png_oFFs)
-         png_handle_oFFs(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_pCAL_SUPPORTED
-      else if (chunk_name == png_pCAL)
-         png_handle_pCAL(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sCAL_SUPPORTED
-      else if (chunk_name == png_sCAL)
-         png_handle_sCAL(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_pHYs_SUPPORTED
-      else if (chunk_name == png_pHYs)
-         png_handle_pHYs(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sBIT_SUPPORTED
-      else if (chunk_name == png_sBIT)
-         png_handle_sBIT(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sRGB_SUPPORTED
-      else if (chunk_name == png_sRGB)
-         png_handle_sRGB(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_iCCP_SUPPORTED
-      else if (chunk_name == png_iCCP)
-         png_handle_iCCP(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_sPLT_SUPPORTED
-      else if (chunk_name == png_sPLT)
-         png_handle_sPLT(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tEXt_SUPPORTED
-      else if (chunk_name == png_tEXt)
-         png_handle_tEXt(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tIME_SUPPORTED
-      else if (chunk_name == png_tIME)
-         png_handle_tIME(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_tRNS_SUPPORTED
-      else if (chunk_name == png_tRNS)
-         png_handle_tRNS(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_zTXt_SUPPORTED
-      else if (chunk_name == png_zTXt)
-         png_handle_zTXt(png_ptr, info_ptr, length);
-#endif
-
-#ifdef PNG_READ_iTXt_SUPPORTED
-      else if (chunk_name == png_iTXt)
-         png_handle_iTXt(png_ptr, info_ptr, length);
-#endif
-
       else
-         png_handle_unknown(png_ptr, info_ptr, length,
-             PNG_HANDLE_CHUNK_AS_DEFAULT);
+         png_handle_chunk(png_ptr, info_ptr, length);
    } while ((png_ptr->mode & PNG_HAVE_IEND) == 0);
 }
 #endif /* SEQUENTIAL_READ */
@@ -1414,6 +1195,31 @@
    return format;
 }
 
+static int
+chromaticities_match_sRGB(const png_xy *xy)
+{
+#  define sRGB_TOLERANCE 1000
+   static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
+   {
+      /* color      x       y */
+      /* red   */ 64000, 33000,
+      /* green */ 30000, 60000,
+      /* blue  */ 15000,  6000,
+      /* white */ 31270, 32900
+   };
+
+   if (PNG_OUT_OF_RANGE(xy->whitex, sRGB_xy.whitex,sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->whitey, sRGB_xy.whitey,sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->redx,   sRGB_xy.redx,  sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->redy,   sRGB_xy.redy,  sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->greenx, sRGB_xy.greenx,sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->greeny, sRGB_xy.greeny,sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->bluex,  sRGB_xy.bluex, sRGB_TOLERANCE) ||
+       PNG_OUT_OF_RANGE(xy->bluey,  sRGB_xy.bluey, sRGB_TOLERANCE))
+      return 0;
+   return 1;
+}
+
 /* Is the given gamma significantly different from sRGB?  The test is the same
  * one used in pngrtran.c when deciding whether to do gamma correction.  The
  * arithmetic optimizes the division by using the fact that the inverse of the
@@ -1422,16 +1228,11 @@
 static int
 png_gamma_not_sRGB(png_fixed_point g)
 {
-   if (g < PNG_FP_1)
-   {
-      /* An uninitialized gamma is assumed to be sRGB for the simplified API. */
-      if (g == 0)
-         return 0;
+   /* 1.6.47: use the same sanity checks as used in pngrtran.c */
+   if (g < PNG_LIB_GAMMA_MIN || g > PNG_LIB_GAMMA_MAX)
+      return 0; /* Includes the uninitialized value 0 */
 
-      return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
-   }
-
-   return 1;
+   return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
 }
 
 /* Do the main body of a 'png_image_begin_read' function; read the PNG file
@@ -1439,6 +1240,33 @@
  * unlike the init routine above.
  */
 static int
+png_image_is_not_sRGB(png_const_structrp png_ptr)
+{
+   /* Does the colorspace **not** match sRGB?  The flag is only set if the
+    * answer can be determined reliably.
+    *
+    * png_struct::chromaticities always exists since the simplified API
+    * requires rgb-to-gray.  The mDCV, cICP and cHRM chunks may all set it to
+    * a non-sRGB value, so it needs to be checked but **only** if one of
+    * those chunks occured in the file.
+    */
+   /* Highest priority: check to be safe. */
+   if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV))
+      return !chromaticities_match_sRGB(&png_ptr->chromaticities);
+
+   /* If the image is marked as sRGB then it is... */
+   if (png_has_chunk(png_ptr, sRGB))
+      return 0;
+
+   /* Last stop: cHRM, must check: */
+   if (png_has_chunk(png_ptr, cHRM))
+      return !chromaticities_match_sRGB(&png_ptr->chromaticities);
+
+   /* Else default to sRGB */
+   return 0;
+}
+
+static int
 png_image_read_header(png_voidp argument)
 {
    png_imagep image = png_voidcast(png_imagep, argument);
@@ -1459,17 +1287,13 @@
 
       image->format = format;
 
-#ifdef PNG_COLORSPACE_SUPPORTED
-      /* Does the colorspace match sRGB?  If there is no color endpoint
-       * (colorant) information assume yes, otherwise require the
-       * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set.  If the
-       * colorspace has been determined to be invalid ignore it.
+      /* Greyscale images don't (typically) have colour space information and
+       * using it is pretty much impossible, so use sRGB for grayscale (it
+       * doesn't matter r==g==b so the transform is irrelevant.)
        */
-      if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags
-         & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|
-            PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))
+      if ((format & PNG_FORMAT_FLAG_COLOR) != 0 &&
+          png_image_is_not_sRGB(png_ptr))
          image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;
-#endif
    }
 
    /* We need the maximum number of entries regardless of the format the
@@ -1657,21 +1481,18 @@
     * potential vulnerability to security problems in the unused chunks.
     *
     * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored
-    * too.  This allows the simplified API to be compiled without iCCP support,
-    * however if the support is there the chunk is still checked to detect
-    * errors (which are unfortunately quite common.)
+    * too.  This allows the simplified API to be compiled without iCCP support.
     */
    {
          static const png_byte chunks_to_process[] = {
             98,  75,  71,  68, '\0',  /* bKGD */
             99,  72,  82,  77, '\0',  /* cHRM */
+            99,  73,  67,  80, '\0',  /* cICP */
            103,  65,  77,  65, '\0',  /* gAMA */
-#        ifdef PNG_READ_iCCP_SUPPORTED
-           105,  67,  67,  80, '\0',  /* iCCP */
-#        endif
+           109,  68,  67,  86, '\0',  /* mDCV */
            115,  66,  73,  84, '\0',  /* sBIT */
            115,  82,  71,  66, '\0',  /* sRGB */
-           };
+         };
 
        /* Ignore unknown chunks and all other chunks except for the
         * IHDR, PLTE, tRNS, IDAT, and IEND chunks.
@@ -1700,7 +1521,15 @@
 static void
 set_file_encoding(png_image_read_control *display)
 {
-   png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;
+   png_structrp png_ptr = display->image->opaque->png_ptr;
+   png_fixed_point g = png_resolve_file_gamma(png_ptr);
+
+   /* PNGv3: the result may be 0 however the 'default_gamma' should have been
+    * set before this is called so zero is an error:
+    */
+   if (g == 0)
+      png_error(png_ptr, "internal: default gamma not set");
+
    if (png_gamma_significant(g) != 0)
    {
       if (png_gamma_not_sRGB(g) != 0)
@@ -2188,25 +2017,19 @@
    /* Default the input file gamma if required - this is necessary because
     * libpng assumes that if no gamma information is present the data is in the
     * output format, but the simplified API deduces the gamma from the input
-    * format.
+    * format.  The 'default' gamma value is also set by png_set_alpha_mode, but
+    * this is happening before any such call, so:
+    *
+    * TODO: should be an internal API and all this code should be copied into a
+    * single common gamma+colorspace file.
     */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)
-   {
-      /* Do this directly, not using the png_colorspace functions, to ensure
-       * that it happens even if the colorspace is invalid (though probably if
-       * it is the setting will be ignored)  Note that the same thing can be
-       * achieved at the application interface with png_set_gAMA.
-       */
-      if (png_ptr->bit_depth == 16 &&
-         (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
-         png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;
+   if (png_ptr->bit_depth == 16 &&
+      (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
+      png_ptr->default_gamma = PNG_GAMMA_LINEAR;
 
-      else
-         png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;
+   else
+      png_ptr->default_gamma = PNG_GAMMA_sRGB_INVERSE;
 
-      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
-   }
-
    /* Decide what to do based on the PNG color type of the input data.  The
     * utility function png_create_colormap_entry deals with most aspects of the
     * output transformations; this code works out how to produce bytes of
@@ -2583,6 +2406,8 @@
 
             else
             {
+               const png_fixed_point gamma = png_resolve_file_gamma(png_ptr);
+
                /* Either the input or the output has no alpha channel, so there
                 * will be no non-opaque pixels in the color-map; it will just be
                 * grayscale.
@@ -2597,10 +2422,13 @@
                 * this case and doing it in the palette; this will result in
                 * duplicate palette entries, but that's better than the
                 * alternative of double gamma correction.
+                *
+                * NOTE: PNGv3: check the resolved result of all the potentially
+                * different colour space chunks.
                 */
                if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                   png_ptr->num_trans > 0) &&
-                  png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
+                  png_gamma_not_sRGB(gamma) != 0)
                {
                   cmap_entries = (unsigned int)make_gray_file_colormap(display);
                   data_encoding = P_FILE;
@@ -2632,8 +2460,8 @@
                      if (output_encoding == P_sRGB)
                         gray = png_sRGB_table[gray]; /* now P_LINEAR */
 
-                     gray = PNG_DIV257(png_gamma_16bit_correct(gray,
-                         png_ptr->colorspace.gamma)); /* now P_FILE */
+                     gray = PNG_DIV257(png_gamma_16bit_correct(gray, gamma));
+                        /* now P_FILE */
 
                      /* And make sure the corresponding palette entry contains
                       * exactly the required sRGB value.
@@ -3764,6 +3592,12 @@
       /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.
        */
       {
+         /* This is safe but should no longer be necessary as
+          * png_ptr->default_gamma should have been set after the
+          * info-before-IDAT was read in png_image_read_header.
+          *
+          * TODO: 1.8: remove this and see what happens.
+          */
          png_fixed_point input_gamma_default;
 
          if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 &&
@@ -3819,8 +3653,9 @@
           * yet; it's set below.  png_struct::gamma, however, is set to the
           * final value.
           */
-         if (png_muldiv(&gtest, output_gamma, png_ptr->colorspace.gamma,
-             PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)
+         if (png_muldiv(&gtest, output_gamma,
+                  png_resolve_file_gamma(png_ptr), PNG_FP_1) != 0 &&
+             png_gamma_significant(gtest) == 0)
             do_local_background = 0;
 
          else if (mode == PNG_ALPHA_STANDARD)

Modified: trunk/Build/source/libs/libpng/libpng-src/pngrtran.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngrtran.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngrtran.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -218,9 +218,59 @@
 #endif
 
 #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
+/* PNGv3 conformance: this private API exists to resolve the now mandatory error
+ * resolution when multiple conflicting sources of gamma or colour space
+ * information are available.
+ *
+ * Terminology (assuming power law, "gamma", encodings):
+ *    "screen" gamma: a power law imposed by the output device when digital
+ *    samples are converted to visible light output.  The EOTF - volage to
+ *    luminance on output.
+ *
+ *    "file" gamma: a power law used to encode luminance levels from the input
+ *    data (the scene or the mastering display system) into digital voltages.
+ *    The OETF - luminance to voltage on input.
+ *
+ *    gamma "correction": a power law matching the **inverse** of the overall
+ *    transfer function from input luminance levels to output levels.  The
+ *    **inverse** of the OOTF; the correction "corrects" for the OOTF by aiming
+ *    to make the overall OOTF (including the correction) linear.
+ *
+ * It is important to understand this terminology because the defined terms are
+ * scattered throughout the libpng code and it is very easy to end up with the
+ * inverse of the power law required.
+ *
+ * Variable and struct::member names:
+ *    file_gamma        OETF  how the PNG data was encoded
+ *
+ *    screen_gamma      EOTF  how the screen will decode digital levels
+ *
+ *    -- not used --    OOTF  the net effect OETF x EOTF
+ *    gamma_correction        the inverse of OOTF to make the result linear
+ *
+ * All versions of libpng require a call to "png_set_gamma" to establish the
+ * "screen" gamma, the power law representing the EOTF.  png_set_gamma may also
+ * set or default the "file" gamma; the OETF.  gamma_correction is calculated
+ * internally.
+ *
+ * The earliest libpng versions required file_gamma to be supplied to set_gamma.
+ * Later versions started allowing png_set_gamma and, later, png_set_alpha_mode,
+ * to cause defaulting from the file data.
+ *
+ * PNGv3 mandated a particular form for this defaulting, one that is compatible
+ * with what libpng did except that if libpng detected inconsistencies it marked
+ * all the chunks as "invalid".  PNGv3 effectively invalidates this prior code.
+ *
+ * Behaviour implemented below:
+ *    translate_gamma_flags(gamma, is_screen)
+ *       The libpng-1.6 API for the gamma parameters to libpng APIs
+ *       (png_set_gamma and png_set_alpha_mode at present).  This allows the
+ *       'gamma' value to be passed as a png_fixed_point number or as one of a
+ *       set of integral values for specific "well known" examples of transfer
+ *       functions.  This is compatible with PNGv3.
+ */
 static png_fixed_point
-translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
-    int is_screen)
+translate_gamma_flags(png_fixed_point output_gamma, int is_screen)
 {
    /* Check for flag values.  The main reason for having the old Mac value as a
     * flag is that it is pretty near impossible to work out what the correct
@@ -230,14 +280,6 @@
    if (output_gamma == PNG_DEFAULT_sRGB ||
       output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
    {
-      /* If there is no sRGB support this just sets the gamma to the standard
-       * sRGB value.  (This is a side effect of using this function!)
-       */
-#     ifdef PNG_READ_sRGB_SUPPORTED
-         png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
-#     else
-         PNG_UNUSED(png_ptr)
-#     endif
       if (is_screen != 0)
          output_gamma = PNG_GAMMA_sRGB;
       else
@@ -279,6 +321,33 @@
    return (png_fixed_point)output_gamma;
 }
 #  endif
+
+static int
+unsupported_gamma(png_structrp png_ptr, png_fixed_point gamma, int warn)
+{
+   /* Validate a gamma value to ensure it is in a reasonable range.  The value
+    * is expected to be 1 or greater, but this range test allows for some
+    * viewing correction values.  The intent is to weed out the API users
+    * who might use the inverse of the gamma value accidentally!
+    *
+    * 1.6.47: apply the test in png_set_gamma as well but only warn and return
+    * false if it fires.
+    *
+    * TODO: 1.8: make this an app_error in png_set_gamma as well.
+    */
+   if (gamma < PNG_LIB_GAMMA_MIN || gamma > PNG_LIB_GAMMA_MAX)
+   {
+#     define msg "gamma out of supported range"
+      if (warn)
+         png_app_warning(png_ptr, msg);
+      else
+         png_app_error(png_ptr, msg);
+      return 1;
+#     undef msg
+   }
+
+   return 0;
+}
 #endif /* READ_ALPHA_MODE || READ_GAMMA */
 
 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
@@ -286,8 +355,8 @@
 png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
     png_fixed_point output_gamma)
 {
+   png_fixed_point file_gamma;
    int compose = 0;
-   png_fixed_point file_gamma;
 
    png_debug(1, "in png_set_alpha_mode_fixed");
 
@@ -294,23 +363,21 @@
    if (png_rtran_ok(png_ptr, 0) == 0)
       return;
 
-   output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
+   output_gamma = translate_gamma_flags(output_gamma, 1/*screen*/);
+   if (unsupported_gamma(png_ptr, output_gamma, 0/*error*/))
+      return;
 
-   /* Validate the value to ensure it is in a reasonable range.  The value
-    * is expected to be 1 or greater, but this range test allows for some
-    * viewing correction values.  The intent is to weed out the API users
-    * who might use the inverse of the gamma value accidentally!
-    *
-    * In libpng 1.6.0, we changed from 0.07..3 to 0.01..100, to accommodate
-    * the optimal 16-bit gamma of 36 and its reciprocal.
-    */
-   if (output_gamma < 1000 || output_gamma > 10000000)
-      png_error(png_ptr, "output gamma out of expected range");
-
    /* The default file gamma is the inverse of the output gamma; the output
-    * gamma may be changed below so get the file value first:
+    * gamma may be changed below so get the file value first.  The default_gamma
+    * is set here and from the simplified API (which uses a different algorithm)
+    * so don't overwrite a set value:
     */
-   file_gamma = png_reciprocal(output_gamma);
+   file_gamma = png_ptr->default_gamma;
+   if (file_gamma == 0)
+   {
+      file_gamma = png_reciprocal(output_gamma);
+      png_ptr->default_gamma = file_gamma;
+   }
 
    /* There are really 8 possibilities here, composed of any combination
     * of:
@@ -361,17 +428,7 @@
          png_error(png_ptr, "invalid alpha mode");
    }
 
-   /* Only set the default gamma if the file gamma has not been set (this has
-    * the side effect that the gamma in a second call to png_set_alpha_mode will
-    * be ignored.)
-    */
-   if (png_ptr->colorspace.gamma == 0)
-   {
-      png_ptr->colorspace.gamma = file_gamma;
-      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
-   }
-
-   /* But always set the output gamma: */
+   /* Set the screen gamma values: */
    png_ptr->screen_gamma = output_gamma;
 
    /* Finally, if pre-multiplying, set the background fields to achieve the
@@ -381,7 +438,7 @@
    {
       /* And obtain alpha pre-multiplication by composing on black: */
       memset(&png_ptr->background, 0, (sizeof png_ptr->background));
-      png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */
+      png_ptr->background_gamma = file_gamma; /* just in case */
       png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
       png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
 
@@ -819,8 +876,8 @@
       return;
 
    /* New in libpng-1.5.4 - reserve particular negative values as flags. */
-   scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
-   file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
+   scrn_gamma = translate_gamma_flags(scrn_gamma, 1/*screen*/);
+   file_gamma = translate_gamma_flags(file_gamma, 0/*file*/);
 
    /* Checking the gamma values for being >0 was added in 1.5.4 along with the
     * premultiplied alpha support; this actually hides an undocumented feature
@@ -834,17 +891,19 @@
     * libpng-1.6.0.
     */
    if (file_gamma <= 0)
-      png_error(png_ptr, "invalid file gamma in png_set_gamma");
-
+      png_app_error(png_ptr, "invalid file gamma in png_set_gamma");
    if (scrn_gamma <= 0)
-      png_error(png_ptr, "invalid screen gamma in png_set_gamma");
+      png_app_error(png_ptr, "invalid screen gamma in png_set_gamma");
 
-   /* Set the gamma values unconditionally - this overrides the value in the PNG
-    * file if a gAMA chunk was present.  png_set_alpha_mode provides a
-    * different, easier, way to default the file gamma.
+   if (unsupported_gamma(png_ptr, file_gamma, 1/*warn*/) ||
+       unsupported_gamma(png_ptr, scrn_gamma, 1/*warn*/))
+      return;
+
+   /* 1.6.47: png_struct::file_gamma and png_struct::screen_gamma are now only
+    * written by this API.  This removes dependencies on the order of API calls
+    * and allows the complex gamma checks to be delayed until needed.
     */
-   png_ptr->colorspace.gamma = file_gamma;
-   png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
+   png_ptr->file_gamma = file_gamma;
    png_ptr->screen_gamma = scrn_gamma;
 }
 
@@ -1022,26 +1081,9 @@
          png_ptr->rgb_to_gray_coefficients_set = 1;
       }
 
-      else
-      {
-         if (red >= 0 && green >= 0)
-            png_app_warning(png_ptr,
-                "ignoring out of range rgb_to_gray coefficients");
-
-         /* Use the defaults, from the cHRM chunk if set, else the historical
-          * values which are close to the sRGB/HDTV/ITU-Rec 709 values.  See
-          * png_do_rgb_to_gray for more discussion of the values.  In this case
-          * the coefficients are not marked as 'set' and are not overwritten if
-          * something has already provided a default.
-          */
-         if (png_ptr->rgb_to_gray_red_coeff == 0 &&
-             png_ptr->rgb_to_gray_green_coeff == 0)
-         {
-            png_ptr->rgb_to_gray_red_coeff   = 6968;
-            png_ptr->rgb_to_gray_green_coeff = 23434;
-            /* png_ptr->rgb_to_gray_blue_coeff  = 2366; */
-         }
-      }
+      else if (red >= 0 && green >= 0)
+         png_app_warning(png_ptr,
+               "ignoring out of range rgb_to_gray coefficients");
    }
 }
 
@@ -1282,6 +1324,80 @@
 #endif /* READ_EXPAND && READ_BACKGROUND */
 }
 
+#ifdef PNG_READ_GAMMA_SUPPORTED
+png_fixed_point /* PRIVATE */
+png_resolve_file_gamma(png_const_structrp png_ptr)
+{
+   png_fixed_point file_gamma;
+
+   /* The file gamma is determined by these precedence rules, in this order
+    * (i.e. use the first value found):
+    *
+    *    png_set_gamma; png_struct::file_gammma if not zero, then:
+    *    png_struct::chunk_gamma if not 0 (determined the PNGv3 rules), then:
+    *    png_set_gamma; 1/png_struct::screen_gamma if not zero
+    *
+    *    0 (i.e. do no gamma handling)
+    */
+   file_gamma = png_ptr->file_gamma;
+   if (file_gamma != 0)
+      return file_gamma;
+
+   file_gamma = png_ptr->chunk_gamma;
+   if (file_gamma != 0)
+      return file_gamma;
+
+   file_gamma = png_ptr->default_gamma;
+   if (file_gamma != 0)
+      return file_gamma;
+
+   /* If png_reciprocal oveflows it returns 0 which indicates to the caller that
+    * there is no usable file gamma.  (The checks added to png_set_gamma and
+    * png_set_alpha_mode should prevent a screen_gamma which would overflow.)
+    */
+   if (png_ptr->screen_gamma != 0)
+      file_gamma = png_reciprocal(png_ptr->screen_gamma);
+
+   return file_gamma;
+}
+
+static int
+png_init_gamma_values(png_structrp png_ptr)
+{
+   /* The following temporary indicates if overall gamma correction is
+    * required.
+    */
+   int gamma_correction = 0;
+   png_fixed_point file_gamma, screen_gamma;
+
+   /* Resolve the file_gamma.  See above: if png_ptr::screen_gamma is set
+    * file_gamma will always be set here:
+    */
+   file_gamma = png_resolve_file_gamma(png_ptr);
+   screen_gamma = png_ptr->screen_gamma;
+
+   if (file_gamma > 0) /* file has been set */
+   {
+      if (screen_gamma > 0) /* screen set too */
+         gamma_correction = png_gamma_threshold(file_gamma, screen_gamma);
+
+      else
+         /* Assume the output matches the input; a long time default behavior
+          * of libpng, although the standard has nothing to say about this.
+          */
+         screen_gamma = png_reciprocal(file_gamma);
+   }
+
+   else /* both unset, prevent corrections: */
+      file_gamma = screen_gamma = PNG_FP_1;
+
+   png_ptr->file_gamma = file_gamma;
+   png_ptr->screen_gamma = screen_gamma;
+   return gamma_correction;
+
+}
+#endif /* READ_GAMMA */
+
 void /* PRIVATE */
 png_init_read_transformations(png_structrp png_ptr)
 {
@@ -1301,59 +1417,22 @@
     * the test needs to be performed later - here.  In addition prior to 1.5.4
     * the tests were repeated for the PALETTE color type here - this is no
     * longer necessary (and doesn't seem to have been necessary before.)
+    *
+    * PNGv3: the new mandatory precedence/priority rules for colour space chunks
+    * are handled here (by calling the above function).
+    *
+    * Turn the gamma transformation on or off as appropriate.  Notice that
+    * PNG_GAMMA just refers to the file->screen correction.  Alpha composition
+    * may independently cause gamma correction because it needs linear data
+    * (e.g. if the file has a gAMA chunk but the screen gamma hasn't been
+    * specified.)  In any case this flag may get turned off in the code
+    * immediately below if the transform can be handled outside the row loop.
     */
-   {
-      /* The following temporary indicates if overall gamma correction is
-       * required.
-       */
-      int gamma_correction = 0;
+   if (png_init_gamma_values(png_ptr) != 0)
+      png_ptr->transformations |= PNG_GAMMA;
 
-      if (png_ptr->colorspace.gamma != 0) /* has been set */
-      {
-         if (png_ptr->screen_gamma != 0) /* screen set too */
-            gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,
-                png_ptr->screen_gamma);
-
-         else
-            /* Assume the output matches the input; a long time default behavior
-             * of libpng, although the standard has nothing to say about this.
-             */
-            png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);
-      }
-
-      else if (png_ptr->screen_gamma != 0)
-         /* The converse - assume the file matches the screen, note that this
-          * perhaps undesirable default can (from 1.5.4) be changed by calling
-          * png_set_alpha_mode (even if the alpha handling mode isn't required
-          * or isn't changed from the default.)
-          */
-         png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);
-
-      else /* neither are set */
-         /* Just in case the following prevents any processing - file and screen
-          * are both assumed to be linear and there is no way to introduce a
-          * third gamma value other than png_set_background with 'UNIQUE', and,
-          * prior to 1.5.4
-          */
-         png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;
-
-      /* We have a gamma value now. */
-      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
-
-      /* Now turn the gamma transformation on or off as appropriate.  Notice
-       * that PNG_GAMMA just refers to the file->screen correction.  Alpha
-       * composition may independently cause gamma correction because it needs
-       * linear data (e.g. if the file has a gAMA chunk but the screen gamma
-       * hasn't been specified.)  In any case this flag may get turned off in
-       * the code immediately below if the transform can be handled outside the
-       * row loop.
-       */
-      if (gamma_correction != 0)
-         png_ptr->transformations |= PNG_GAMMA;
-
-      else
-         png_ptr->transformations &= ~PNG_GAMMA;
-   }
+   else
+      png_ptr->transformations &= ~PNG_GAMMA;
 #endif
 
    /* Certain transformations have the effect of preventing other
@@ -1425,7 +1504,7 @@
     * appropriately.
     */
    if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
-      png_colorspace_set_rgb_coefficients(png_ptr);
+      png_set_rgb_coefficients(png_ptr);
 #endif
 
 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
@@ -1568,10 +1647,10 @@
     */
    if ((png_ptr->transformations & PNG_GAMMA) != 0 ||
        ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 &&
-        (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
+        (png_gamma_significant(png_ptr->file_gamma) != 0 ||
          png_gamma_significant(png_ptr->screen_gamma) != 0)) ||
         ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
-         (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
+         (png_gamma_significant(png_ptr->file_gamma) != 0 ||
           png_gamma_significant(png_ptr->screen_gamma) != 0
 #  ifdef PNG_READ_BACKGROUND_SUPPORTED
          || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&
@@ -1627,8 +1706,8 @@
                      break;
 
                   case PNG_BACKGROUND_GAMMA_FILE:
-                     g = png_reciprocal(png_ptr->colorspace.gamma);
-                     gs = png_reciprocal2(png_ptr->colorspace.gamma,
+                     g = png_reciprocal(png_ptr->file_gamma);
+                     gs = png_reciprocal2(png_ptr->file_gamma,
                          png_ptr->screen_gamma);
                      break;
 
@@ -1736,8 +1815,8 @@
                   break;
 
                case PNG_BACKGROUND_GAMMA_FILE:
-                  g = png_reciprocal(png_ptr->colorspace.gamma);
-                  gs = png_reciprocal2(png_ptr->colorspace.gamma,
+                  g = png_reciprocal(png_ptr->file_gamma);
+                  gs = png_reciprocal2(png_ptr->file_gamma,
                       png_ptr->screen_gamma);
                   break;
 
@@ -1987,11 +2066,11 @@
     * been called before this from png_read_update_info->png_read_start_row
     * sometimes does the gamma transform and cancels the flag.
     *
-    * TODO: this looks wrong; the info_ptr should end up with a gamma equal to
-    * the screen_gamma value.  The following probably results in weirdness if
-    * the info_ptr is used by the app after the rows have been read.
+    * TODO: this is confusing.  It only changes the result of png_get_gAMA and,
+    * yes, it does return the value that the transformed data effectively has
+    * but does any app really understand this?
     */
-   info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
+   info_ptr->gamma = png_ptr->file_gamma;
 #endif
 
    if (info_ptr->bit_depth == 16)

Modified: trunk/Build/source/libs/libpng/libpng-src/pngrutil.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngrutil.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngrutil.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -17,6 +17,11 @@
 
 #ifdef PNG_READ_SUPPORTED
 
+/* The minimum 'zlib' stream is assumed to be just the 2 byte header, 5 bytes
+ * minimum 'deflate' stream, and the 4 byte checksum.
+ */
+#define LZ77Min  (2U+5U+4U)
+
 #ifdef PNG_READ_INTERLACING_SUPPORTED
 /* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
 
@@ -43,30 +48,6 @@
    return uval;
 }
 
-#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
-/* The following is a variation on the above for use with the fixed
- * point values used for gAMA and cHRM.  Instead of png_error it
- * issues a warning and returns (-1) - an invalid value because both
- * gAMA and cHRM use *unsigned* integers for fixed point values.
- */
-#define PNG_FIXED_ERROR (-1)
-
-static png_fixed_point /* PRIVATE */
-png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)
-{
-   png_uint_32 uval = png_get_uint_32(buf);
-
-   if (uval <= PNG_UINT_31_MAX)
-      return (png_fixed_point)uval; /* known to be in range */
-
-   /* The caller can turn off the warning by passing NULL. */
-   if (png_ptr != NULL)
-      png_warning(png_ptr, "PNG fixed point integer out of range");
-
-   return PNG_FIXED_ERROR;
-}
-#endif
-
 #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
 /* NOTE: the read macros will obscure these definitions, so that if
  * PNG_USE_READ_MACROS is set the library will not use them internally,
@@ -163,6 +144,38 @@
       png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
 }
 
+/* This function is called to verify that a chunk name is valid.
+ * Do this using the bit-whacking approach from contrib/tools/pngfix.c
+ *
+ * Copied from libpng 1.7.
+ */
+static int
+check_chunk_name(png_uint_32 name)
+{
+   png_uint_32 t;
+
+   /* Remove bit 5 from all but the reserved byte; this means
+    * every 8-bit unit must be in the range 65-90 to be valid.
+    * So bit 5 must be zero, bit 6 must be set and bit 7 zero.
+    */
+   name &= ~PNG_U32(32,32,0,32);
+   t = (name & ~0x1f1f1f1fU) ^ 0x40404040U;
+
+   /* Subtract 65 for each 8-bit quantity, this must not
+    * overflow and each byte must then be in the range 0-25.
+    */
+   name -= PNG_U32(65,65,65,65);
+   t |= name;
+
+   /* Subtract 26, handling the overflow which should set the
+    * top three bits of each byte.
+    */
+   name -= PNG_U32(25,25,25,26);
+   t |= ~name;
+
+   return (t & 0xe0e0e0e0U) == 0U;
+}
+
 /* Read the chunk header (length + type name).
  * Put the type name into png_ptr->chunk_name, and return the length.
  */
@@ -170,34 +183,37 @@
 png_read_chunk_header(png_structrp png_ptr)
 {
    png_byte buf[8];
-   png_uint_32 length;
+   png_uint_32 chunk_name, length;
 
 #ifdef PNG_IO_STATE_SUPPORTED
    png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
 #endif
 
-   /* Read the length and the chunk name.
-    * This must be performed in a single I/O call.
+   /* Read the length and the chunk name.  png_struct::chunk_name is immediately
+    * updated even if they are detectably wrong.  This aids error message
+    * handling by allowing png_chunk_error to be used.
     */
    png_read_data(png_ptr, buf, 8);
    length = png_get_uint_31(png_ptr, buf);
+   png_ptr->chunk_name = chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
 
-   /* Put the chunk name into png_ptr->chunk_name. */
-   png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
+   /* Reset the crc and run it over the chunk name. */
+   png_reset_crc(png_ptr);
+   png_calculate_crc(png_ptr, buf + 4, 4);
 
    png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu",
        (unsigned long)png_ptr->chunk_name, (unsigned long)length);
 
-   /* Reset the crc and run it over the chunk name. */
-   png_reset_crc(png_ptr);
-   png_calculate_crc(png_ptr, buf + 4, 4);
+   /* Sanity check the length (first by <= 0x80) and the chunk name.  An error
+    * here indicates a broken stream and libpng has no recovery from this.
+    */
+   if (buf[0] >= 0x80U)
+      png_chunk_error(png_ptr, "bad header (invalid length)");
 
    /* Check to see if chunk name is valid. */
-   png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+   if (!check_chunk_name(chunk_name))
+      png_chunk_error(png_ptr, "bad header (invalid type)");
 
-   /* Check for too-large chunk length */
-   png_check_chunk_length(png_ptr, length);
-
 #ifdef PNG_IO_STATE_SUPPORTED
    png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
 #endif
@@ -216,13 +232,85 @@
    png_calculate_crc(png_ptr, buf, length);
 }
 
+/* Compare the CRC stored in the PNG file with that calculated by libpng from
+ * the data it has read thus far.
+ */
+static int
+png_crc_error(png_structrp png_ptr, int handle_as_ancillary)
+{
+   png_byte crc_bytes[4];
+   png_uint_32 crc;
+   int need_crc = 1;
+
+   /* There are four flags two for ancillary and two for critical chunks.  The
+    * default setting of these flags is all zero.
+    *
+    * PNG_FLAG_CRC_ANCILLARY_USE
+    * PNG_FLAG_CRC_ANCILLARY_NOWARN
+    *  USE+NOWARN: no CRC calculation (implemented here), else;
+    *  NOWARN:     png_chunk_error on error (implemented in png_crc_finish)
+    *  else:       png_chunk_warning on error (implemented in png_crc_finish)
+    *              This is the default.
+    *
+    *    I.e. NOWARN without USE produces png_chunk_error.  The default setting
+    *    where neither are set does the same thing.
+    *
+    * PNG_FLAG_CRC_CRITICAL_USE
+    * PNG_FLAG_CRC_CRITICAL_IGNORE
+    *  IGNORE: no CRC calculation (implemented here), else;
+    *  USE:    png_chunk_warning on error (implemented in png_crc_finish)
+    *  else:   png_chunk_error on error (implemented in png_crc_finish)
+    *          This is the default.
+    *
+    * This arose because of original mis-implementation and has persisted for
+    * compatibility reasons.
+    *
+    * TODO: the flag names are internal so maybe this can be changed to
+    * something comprehensible.
+    */
+   if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+         need_crc = 0;
+   }
+
+   else /* critical */
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
+         need_crc = 0;
+   }
+
+#ifdef PNG_IO_STATE_SUPPORTED
+   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
+#endif
+
+   /* The chunk CRC must be serialized in a single I/O call. */
+   png_read_data(png_ptr, crc_bytes, 4);
+
+   if (need_crc != 0)
+   {
+      crc = png_get_uint_32(crc_bytes);
+      return crc != png_ptr->crc;
+   }
+
+   else
+      return 0;
+}
+
 /* Optionally skip data and then check the CRC.  Depending on whether we
  * are reading an ancillary or critical chunk, and how the program has set
  * things up, we may calculate the CRC on the data and print a message.
  * Returns '1' if there was a CRC error, '0' otherwise.
+ *
+ * There is one public version which is used in most places and another which
+ * takes the value for the 'critical' flag to check.  This allows PLTE and IEND
+ * handling code to ignore the CRC error and removes some confusing code
+ * duplication.
  */
-int /* PRIVATE */
-png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
+static int
+png_crc_finish_critical(png_structrp png_ptr, png_uint_32 skip,
+      int handle_as_ancillary)
 {
    /* The size of the local buffer for inflate is a good guess as to a
     * reasonable size to use for buffering reads from the application.
@@ -240,14 +328,24 @@
       png_crc_read(png_ptr, tmpbuf, len);
    }
 
-   if (png_crc_error(png_ptr) != 0)
+   /* If 'handle_as_ancillary' has been requested and this is a critical chunk
+    * but PNG_FLAG_CRC_CRITICAL_IGNORE was set then png_read_crc did not, in
+    * fact, calculate the CRC so the ANCILLARY settings should not be used
+    * instead.
+    */
+   if (handle_as_ancillary &&
+       (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
+      handle_as_ancillary = 0;
+
+   /* TODO: this might be more comprehensible if png_crc_error was inlined here.
+    */
+   if (png_crc_error(png_ptr, handle_as_ancillary) != 0)
    {
-      if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?
+      /* See above for the explanation of how the flags work. */
+      if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?
           (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 :
           (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0)
-      {
          png_chunk_warning(png_ptr, "CRC error");
-      }
 
       else
          png_chunk_error(png_ptr, "CRC error");
@@ -258,61 +356,29 @@
    return 0;
 }
 
-/* Compare the CRC stored in the PNG file with that calculated by libpng from
- * the data it has read thus far.
- */
 int /* PRIVATE */
-png_crc_error(png_structrp png_ptr)
+png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
 {
-   png_byte crc_bytes[4];
-   png_uint_32 crc;
-   int need_crc = 1;
-
-   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
-   {
-      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
-          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
-         need_crc = 0;
-   }
-
-   else /* critical */
-   {
-      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
-         need_crc = 0;
-   }
-
-#ifdef PNG_IO_STATE_SUPPORTED
-   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
-#endif
-
-   /* The chunk CRC must be serialized in a single I/O call. */
-   png_read_data(png_ptr, crc_bytes, 4);
-
-   if (need_crc != 0)
-   {
-      crc = png_get_uint_32(crc_bytes);
-      return crc != png_ptr->crc;
-   }
-
-   else
-      return 0;
+   return png_crc_finish_critical(png_ptr, skip, 0/*critical handling*/);
 }
 
 #if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\
     defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\
     defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\
-    defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED)
+    defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_eXIf_SUPPORTED) ||\
+    defined(PNG_SEQUENTIAL_READ_SUPPORTED)
 /* Manage the read buffer; this simply reallocates the buffer if it is not small
  * enough (or if it is not allocated).  The routine returns a pointer to the
  * buffer; if an error occurs and 'warn' is set the routine returns NULL, else
- * it will call png_error (via png_malloc) on failure.  (warn == 2 means
- * 'silent').
+ * it will call png_error on failure.
  */
 static png_bytep
-png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
+png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size)
 {
    png_bytep buffer = png_ptr->read_buffer;
 
+   if (new_size > png_chunk_max(png_ptr)) return NULL;
+
    if (buffer != NULL && new_size > png_ptr->read_buffer_size)
    {
       png_ptr->read_buffer = NULL;
@@ -327,24 +393,17 @@
 
       if (buffer != NULL)
       {
-         memset(buffer, 0, new_size); /* just in case */
+#        ifndef PNG_NO_MEMZERO /* for detecting UIM bugs **only** */
+            memset(buffer, 0, new_size); /* just in case */
+#        endif
          png_ptr->read_buffer = buffer;
          png_ptr->read_buffer_size = new_size;
       }
-
-      else if (warn < 2) /* else silent */
-      {
-         if (warn != 0)
-             png_chunk_warning(png_ptr, "insufficient memory to read chunk");
-
-         else
-             png_chunk_error(png_ptr, "insufficient memory to read chunk");
-      }
    }
 
    return buffer;
 }
-#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */
+#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|eXIf|SEQUENTIAL_READ */
 
 /* png_inflate_claim: claim the zstream for some nefarious purpose that involves
  * decompression.  Returns Z_OK on success, else a zlib error code.  It checks
@@ -631,17 +690,8 @@
     * maybe a '\0' terminator too.  We have to assume that 'prefix_size' is
     * limited only by the maximum chunk size.
     */
-   png_alloc_size_t limit = PNG_SIZE_MAX;
+   png_alloc_size_t limit = png_chunk_max(png_ptr);
 
-# ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (png_ptr->user_chunk_malloc_max > 0 &&
-       png_ptr->user_chunk_malloc_max < limit)
-      limit = png_ptr->user_chunk_malloc_max;
-# elif PNG_USER_CHUNK_MALLOC_MAX > 0
-   if (PNG_USER_CHUNK_MALLOC_MAX < limit)
-      limit = PNG_USER_CHUNK_MALLOC_MAX;
-# endif
-
    if (limit >= prefix_size + (terminate != 0))
    {
       int ret;
@@ -845,9 +895,9 @@
 }
 #endif /* READ_iCCP */
 
+/* CHUNK HANDLING */
 /* Read and check the IDHR chunk */
-
-void /* PRIVATE */
+static png_handle_result_code
 png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[13];
@@ -857,13 +907,8 @@
 
    png_debug(1, "in png_handle_IHDR");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)
-      png_chunk_error(png_ptr, "out of place");
+   /* Length and position are checked by the caller. */
 
-   /* Check the length */
-   if (length != 13)
-      png_chunk_error(png_ptr, "invalid");
-
    png_ptr->mode |= PNG_HAVE_IHDR;
 
    png_crc_read(png_ptr, buf, 13);
@@ -916,257 +961,196 @@
    png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
    png_debug1(3, "channels = %d", png_ptr->channels);
    png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);
+
+   /* Rely on png_set_IHDR to completely validate the data and call png_error if
+    * it's wrong.
+    */
    png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
        color_type, interlace_type, compression_type, filter_type);
+
+   return handled_ok;
+   PNG_UNUSED(length)
 }
 
 /* Read and check the palette */
-void /* PRIVATE */
+/* TODO: there are several obvious errors in this code when handling
+ * out-of-place chunks and there is much over-complexity caused by trying to
+ * patch up the problems.
+ */
+static png_handle_result_code
 png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
-   png_color palette[PNG_MAX_PALETTE_LENGTH];
-   int max_palette_length, num, i;
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
-   png_colorp pal_ptr;
-#endif
+   png_const_charp errmsg = NULL;
 
    png_debug(1, "in png_handle_PLTE");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   /* Moved to before the 'after IDAT' check below because otherwise duplicate
-    * PLTE chunks are potentially ignored (the spec says there shall not be more
-    * than one PLTE, the error is not treated as benign, so this check trumps
-    * the requirement that PLTE appears before IDAT.)
+   /* 1.6.47: consistency.  This used to be especially treated as a critical
+    * error even in an image which is not colour mapped, there isn't a good
+    * justification for treating some errors here one way and others another so
+    * everything uses the same logic.
     */
-   else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
-      png_chunk_error(png_ptr, "duplicate");
+   if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
+      errmsg = "duplicate";
 
    else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      /* This is benign because the non-benign error happened before, when an
-       * IDAT was encountered in a color-mapped image with no PLTE.
-       */
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
+      errmsg = "out of place";
 
-   png_ptr->mode |= PNG_HAVE_PLTE;
+   else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
+      errmsg = "ignored in grayscale PNG";
 
-   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");
-      return;
-   }
+   else if (length > 3*PNG_MAX_PALETTE_LENGTH || (length % 3) != 0)
+      errmsg = "invalid";
 
-#ifndef PNG_READ_OPT_PLTE_SUPPORTED
-   if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
-   {
-      png_crc_finish(png_ptr, length);
-      return;
-   }
-#endif
+   /* This drops PLTE in favour of tRNS or bKGD because both of those chunks
+    * can have an effect on the rendering of the image whereas PLTE only matters
+    * in the case of an 8-bit display with a decoder which controls the palette.
+    *
+    * The alternative here is to ignore the error and store the palette anyway;
+    * destroying the tRNS will definately cause problems.
+    *
+    * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because
+    * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and
+    * hIST all check for a preceding PLTE in these cases.
+    */
+   else if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE &&
+            (png_has_chunk(png_ptr, tRNS) || png_has_chunk(png_ptr, bKGD)))
+      errmsg = "out of place";
 
-   if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
+   else
    {
-      png_crc_finish(png_ptr, length);
+      /* If the palette has 256 or fewer entries but is too large for the bit
+       * depth we don't issue an error to preserve the behavior of previous
+       * libpng versions. We silently truncate the unused extra palette entries
+       * here.
+       */
+      const unsigned max_palette_length =
+         (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+            1U << png_ptr->bit_depth : PNG_MAX_PALETTE_LENGTH;
 
-      if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
-         png_chunk_benign_error(png_ptr, "invalid");
+      /* The cast is safe because 'length' is less than
+       * 3*PNG_MAX_PALETTE_LENGTH
+       */
+      const unsigned num = (length > 3U*max_palette_length) ?
+         max_palette_length : (unsigned)length / 3U;
 
-      else
-         png_chunk_error(png_ptr, "invalid");
+      unsigned i, j;
+      png_byte buf[3*PNG_MAX_PALETTE_LENGTH];
+      png_color palette[PNG_MAX_PALETTE_LENGTH];
 
-      return;
-   }
+      /* Read the chunk into the buffer then read to the end of the chunk. */
+      png_crc_read(png_ptr, buf, num*3U);
+      png_crc_finish_critical(png_ptr, length - 3U*num,
+            /* Handle as ancillary if PLTE is optional: */
+            png_ptr->color_type != PNG_COLOR_TYPE_PALETTE);
 
-   /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
-   num = (int)length / 3;
+      for (i = 0U, j = 0U; i < num; i++)
+      {
+         palette[i].red = buf[j++];
+         palette[i].green = buf[j++];
+         palette[i].blue = buf[j++];
+      }
 
-   /* If the palette has 256 or fewer entries but is too large for the bit
-    * depth, we don't issue an error, to preserve the behavior of previous
-    * libpng versions. We silently truncate the unused extra palette entries
-    * here.
-    */
-   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-      max_palette_length = (1 << png_ptr->bit_depth);
-   else
-      max_palette_length = PNG_MAX_PALETTE_LENGTH;
+      /* A valid PLTE chunk has been read */
+      png_ptr->mode |= PNG_HAVE_PLTE;
 
-   if (num > max_palette_length)
-      num = max_palette_length;
-
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
-   for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
-   {
-      png_byte buf[3];
-
-      png_crc_read(png_ptr, buf, 3);
-      pal_ptr->red = buf[0];
-      pal_ptr->green = buf[1];
-      pal_ptr->blue = buf[2];
+      /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to
+       * its own copy of the palette.  This has the side effect that when
+       * png_start_row is called (this happens after any call to
+       * png_read_update_info) the info_ptr palette gets changed.  This is
+       * extremely unexpected and confusing.
+       *
+       * REVIEW: there have been consistent bugs in the past about gamma and
+       * similar transforms to colour mapped images being useless because the
+       * modified palette cannot be accessed because of the above.
+       *
+       * CONSIDER: Fix this by not sharing the palette in this way.  But does
+       * this completely fix the problem?
+       */
+      png_set_PLTE(png_ptr, info_ptr, palette, num);
+      return handled_ok;
    }
-#else
-   for (i = 0; i < num; i++)
-   {
-      png_byte buf[3];
 
-      png_crc_read(png_ptr, buf, 3);
-      /* Don't depend upon png_color being any order */
-      palette[i].red = buf[0];
-      palette[i].green = buf[1];
-      palette[i].blue = buf[2];
-   }
-#endif
-
-   /* If we actually need the PLTE chunk (ie for a paletted image), we do
-    * whatever the normal CRC configuration tells us.  However, if we
-    * have an RGB image, the PLTE can be considered ancillary, so
-    * we will act as though it is.
-    */
-#ifndef PNG_READ_OPT_PLTE_SUPPORTED
+   /* Here on error: errmsg is non NULL. */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-#endif
    {
-      png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3));
+      png_crc_finish(png_ptr, length);
+      png_chunk_error(png_ptr, errmsg);
    }
 
-#ifndef PNG_READ_OPT_PLTE_SUPPORTED
-   else if (png_crc_error(png_ptr) != 0)  /* Only if we have a CRC error */
+   else /* not critical to this image */
    {
-      /* If we don't want to use the data from an ancillary chunk,
-       * we have two options: an error abort, or a warning and we
-       * ignore the data in this chunk (which should be OK, since
-       * it's considered ancillary for a RGB or RGBA image).
-       *
-       * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the
-       * chunk type to determine whether to check the ancillary or the critical
-       * flags.
-       */
-      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0)
-      {
-         if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0)
-            return;
-
-         else
-            png_chunk_error(png_ptr, "CRC error");
-      }
-
-      /* Otherwise, we (optionally) emit a warning and use the chunk. */
-      else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)
-         png_chunk_warning(png_ptr, "CRC error");
+      png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/);
+      png_chunk_benign_error(png_ptr, errmsg);
    }
-#endif
 
-   /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its
-    * own copy of the palette.  This has the side effect that when png_start_row
-    * is called (this happens after any call to png_read_update_info) the
-    * info_ptr palette gets changed.  This is extremely unexpected and
-    * confusing.
-    *
-    * Fix this by not sharing the palette in this way.
+   /* Because PNG_UNUSED(errmsg) does not work if all the uses are compiled out
+    * (this does happen).
     */
-   png_set_PLTE(png_ptr, info_ptr, palette, num);
+   return errmsg != NULL ? handled_error : handled_error;
+}
 
-   /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before
-    * IDAT.  Prior to 1.6.0 this was not checked; instead the code merely
-    * checked the apparent validity of a tRNS chunk inserted before PLTE on a
-    * palette PNG.  1.6.0 attempts to rigorously follow the standard and
-    * therefore does a benign error if the erroneous condition is detected *and*
-    * cancels the tRNS if the benign error returns.  The alternative is to
-    * amend the standard since it would be rather hypocritical of the standards
-    * maintainers to ignore it.
-    */
-#ifdef PNG_READ_tRNS_SUPPORTED
-   if (png_ptr->num_trans > 0 ||
-       (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))
-   {
-      /* Cancel this because otherwise it would be used if the transforms
-       * require it.  Don't cancel the 'valid' flag because this would prevent
-       * detection of duplicate chunks.
-       */
-      png_ptr->num_trans = 0;
+/* On read the IDAT chunk is always handled specially, even if marked for
+ * unknown handling (this is allowed), so:
+ */
+#define png_handle_IDAT NULL
 
-      if (info_ptr != NULL)
-         info_ptr->num_trans = 0;
-
-      png_chunk_benign_error(png_ptr, "tRNS must be after");
-   }
-#endif
-
-#ifdef PNG_READ_hIST_SUPPORTED
-   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
-      png_chunk_benign_error(png_ptr, "hIST must be after");
-#endif
-
-#ifdef PNG_READ_bKGD_SUPPORTED
-   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
-      png_chunk_benign_error(png_ptr, "bKGD must be after");
-#endif
-}
-
-void /* PRIVATE */
+static png_handle_result_code
 png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_debug(1, "in png_handle_IEND");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 ||
-       (png_ptr->mode & PNG_HAVE_IDAT) == 0)
-      png_chunk_error(png_ptr, "out of place");
-
    png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
 
-   png_crc_finish(png_ptr, length);
-
    if (length != 0)
       png_chunk_benign_error(png_ptr, "invalid");
 
+   png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/);
+
+   return handled_ok;
    PNG_UNUSED(info_ptr)
 }
 
 #ifdef PNG_READ_gAMA_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code
 png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
-   png_fixed_point igamma;
+   png_uint_32 ugamma;
    png_byte buf[4];
 
    png_debug(1, "in png_handle_gAMA");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
+   png_crc_read(png_ptr, buf, 4);
 
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
+   if (png_crc_finish(png_ptr, 0) != 0)
+      return handled_error;
 
-   if (length != 4)
+   ugamma = png_get_uint_32(buf);
+
+   if (ugamma > PNG_UINT_31_MAX)
    {
-      png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "invalid");
-      return;
+      return handled_error;
    }
 
-   png_crc_read(png_ptr, buf, 4);
+   png_set_gAMA_fixed(png_ptr, info_ptr, (png_fixed_point)/*SAFE*/ugamma);
 
-   if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+#ifdef PNG_READ_GAMMA_SUPPORTED
+      /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA.  gAMA is
+       * at the end of the chain so simply check for an unset value.
+       */
+      if (png_ptr->chunk_gamma == 0)
+         png_ptr->chunk_gamma = (png_fixed_point)/*SAFE*/ugamma;
+#endif /*READ_GAMMA*/
 
-   igamma = png_get_fixed_point(NULL, buf);
-
-   png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);
-   png_colorspace_sync(png_ptr, info_ptr);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_gAMA NULL
 #endif
 
 #ifdef PNG_READ_sBIT_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    unsigned int truelen, i;
@@ -1175,23 +1159,6 @@
 
    png_debug(1, "in png_handle_sBIT");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
       truelen = 3;
@@ -1204,11 +1171,11 @@
       sample_depth = png_ptr->bit_depth;
    }
 
-   if (length != truelen || length > 4)
+   if (length != truelen)
    {
-      png_chunk_benign_error(png_ptr, "invalid");
       png_crc_finish(png_ptr, length);
-      return;
+      png_chunk_benign_error(png_ptr, "bad length");
+      return handled_error;
    }
 
    buf[0] = buf[1] = buf[2] = buf[3] = sample_depth;
@@ -1215,7 +1182,7 @@
    png_crc_read(png_ptr, buf, truelen);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    for (i=0; i<truelen; ++i)
    {
@@ -1222,7 +1189,7 @@
       if (buf[i] == 0 || buf[i] > sample_depth)
       {
          png_chunk_benign_error(png_ptr, "invalid");
-         return;
+         return handled_error;
       }
    }
 
@@ -1234,7 +1201,7 @@
       png_ptr->sig_bit.alpha = buf[3];
    }
 
-   else
+   else /* grayscale */
    {
       png_ptr->sig_bit.gray = buf[0];
       png_ptr->sig_bit.red = buf[0];
@@ -1244,83 +1211,87 @@
    }
 
    png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+   return handled_ok;
 }
+#else
+#  define png_handle_sBIT NULL
 #endif
 
 #ifdef PNG_READ_cHRM_SUPPORTED
-void /* PRIVATE */
+static png_int_32
+png_get_int_32_checked(png_const_bytep buf, int *error)
+{
+   png_uint_32 uval = png_get_uint_32(buf);
+   if ((uval & 0x80000000) == 0) /* non-negative */
+      return (png_int_32)uval;
+
+   uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */
+   if ((uval & 0x80000000) == 0) /* no overflow */
+      return -(png_int_32)uval;
+
+   /* This version of png_get_int_32 has a way of returning the error to the
+    * caller, so:
+    */
+   *error = 1;
+   return 0; /* Safe */
+}
+
+static png_handle_result_code /* PRIVATE */
 png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
+   int error = 0;
+   png_xy xy;
    png_byte buf[32];
-   png_xy xy;
 
    png_debug(1, "in png_handle_cHRM");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   if (length != 32)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 32);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
-   xy.whitex = png_get_fixed_point(NULL, buf);
-   xy.whitey = png_get_fixed_point(NULL, buf + 4);
-   xy.redx   = png_get_fixed_point(NULL, buf + 8);
-   xy.redy   = png_get_fixed_point(NULL, buf + 12);
-   xy.greenx = png_get_fixed_point(NULL, buf + 16);
-   xy.greeny = png_get_fixed_point(NULL, buf + 20);
-   xy.bluex  = png_get_fixed_point(NULL, buf + 24);
-   xy.bluey  = png_get_fixed_point(NULL, buf + 28);
+   xy.whitex = png_get_int_32_checked(buf +  0, &error);
+   xy.whitey = png_get_int_32_checked(buf +  4, &error);
+   xy.redx   = png_get_int_32_checked(buf +  8, &error);
+   xy.redy   = png_get_int_32_checked(buf + 12, &error);
+   xy.greenx = png_get_int_32_checked(buf + 16, &error);
+   xy.greeny = png_get_int_32_checked(buf + 20, &error);
+   xy.bluex  = png_get_int_32_checked(buf + 24, &error);
+   xy.bluey  = png_get_int_32_checked(buf + 28, &error);
 
-   if (xy.whitex == PNG_FIXED_ERROR ||
-       xy.whitey == PNG_FIXED_ERROR ||
-       xy.redx   == PNG_FIXED_ERROR ||
-       xy.redy   == PNG_FIXED_ERROR ||
-       xy.greenx == PNG_FIXED_ERROR ||
-       xy.greeny == PNG_FIXED_ERROR ||
-       xy.bluex  == PNG_FIXED_ERROR ||
-       xy.bluey  == PNG_FIXED_ERROR)
+   if (error)
    {
-      png_chunk_benign_error(png_ptr, "invalid values");
-      return;
+      png_chunk_benign_error(png_ptr, "invalid");
+      return handled_error;
    }
 
-   /* If a colorspace error has already been output skip this chunk */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
-      return;
+   /* png_set_cHRM may complain about some of the values but this doesn't matter
+    * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous)
+    * values.  Ridiculousity will be checked if the values are used later.
+    */
+   png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
+         xy.greenx, xy.greeny, xy.bluex, xy.bluey);
 
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0)
-   {
-      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
-      png_colorspace_sync(png_ptr, info_ptr);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
+   /* We only use 'chromaticities' for RGB to gray */
+#  ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+      /* There is no need to check sRGB here, cICP is NYI and iCCP is not
+       * supported so just check mDCV.
+       */
+      if (!png_has_chunk(png_ptr, mDCV))
+      {
+         png_ptr->chromaticities = xy;
+      }
+#  endif /* READ_RGB_TO_GRAY */
 
-   png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
-   (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy,
-       1/*prefer cHRM values*/);
-   png_colorspace_sync(png_ptr, info_ptr);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_cHRM NULL
 #endif
 
 #ifdef PNG_READ_sRGB_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte intent;
@@ -1327,50 +1298,45 @@
 
    png_debug(1, "in png_handle_sRGB");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
+   png_crc_read(png_ptr, &intent, 1);
 
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
+   if (png_crc_finish(png_ptr, 0) != 0)
+      return handled_error;
 
-   if (length != 1)
+   /* This checks the range of the "rendering intent" because it is specified in
+    * the PNG spec itself; the "reserved" values will result in the chunk not
+    * being accepted, just as they do with the various "reserved" values in
+    * IHDR.
+    */
+   if (intent > 3/*PNGv3 spec*/)
    {
-      png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "invalid");
-      return;
+      return handled_error;
    }
 
-   png_crc_read(png_ptr, &intent, 1);
+   png_set_sRGB(png_ptr, info_ptr, intent);
+   /* NOTE: png_struct::chromaticities is not set here because the RGB to gray
+    * coefficients are known without a need for the chromaticities.
+    */
 
-   if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+#ifdef PNG_READ_GAMMA_SUPPORTED
+      /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA.  iCCP is
+       * not supported by libpng so the only requirement is to check for cICP
+       * setting the gamma (this is NYI, but this check is safe.)
+       */
+      if (!png_has_chunk(png_ptr, cICP) || png_ptr->chunk_gamma == 0)
+         png_ptr->chunk_gamma = PNG_GAMMA_sRGB_INVERSE;
+#endif /*READ_GAMMA*/
 
-   /* If a colorspace error has already been output skip this chunk */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
-      return;
-
-   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
-    * this.
-    */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)
-   {
-      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
-      png_colorspace_sync(png_ptr, info_ptr);
-      png_chunk_benign_error(png_ptr, "too many profiles");
-      return;
-   }
-
-   (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
-   png_colorspace_sync(png_ptr, info_ptr);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_sRGB NULL
 #endif /* READ_sRGB */
 
 #ifdef PNG_READ_iCCP_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle profiles that are > 64K under DOS */
 {
@@ -1379,45 +1345,11 @@
 
    png_debug(1, "in png_handle_iCCP");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   /* Consistent with all the above colorspace handling an obviously *invalid*
-    * chunk is just ignored, so does not invalidate the color space.  An
-    * alternative is to set the 'invalid' flags at the start of this routine
-    * and only clear them in they were not set before and all the tests pass.
+   /* PNGv3: allow PNG files with both sRGB and iCCP because the PNG spec only
+    * ever said that there "should" be only one, not "shall" and the PNGv3
+    * colour chunk precedence rules give a handling for this case anyway.
     */
-
-   /* The keyword must be at least one character and there is a
-    * terminator (0) byte and the compression method byte, and the
-    * 'zlib' datastream is at least 11 bytes.
-    */
-   if (length < 14)
    {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "too short");
-      return;
-   }
-
-   /* If a colorspace error has already been output skip this chunk */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      return;
-   }
-
-   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
-    * this.
-    */
-   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)
-   {
       uInt read_length, keyword_length;
       char keyword[81];
 
@@ -1426,19 +1358,16 @@
        */
       read_length = 81; /* maximum */
       if (read_length > length)
-         read_length = (uInt)length;
+         read_length = (uInt)/*SAFE*/length;
 
       png_crc_read(png_ptr, (png_bytep)keyword, read_length);
       length -= read_length;
 
-      /* The minimum 'zlib' stream is assumed to be just the 2 byte header,
-       * 5 bytes minimum 'deflate' stream, and the 4 byte checksum.
-       */
-      if (length < 11)
+      if (length < LZ77Min)
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "too short");
-         return;
+         return handled_error;
       }
 
       keyword_length = 0;
@@ -1475,15 +1404,14 @@
                    */
                   png_uint_32 profile_length = png_get_uint_32(profile_header);
 
-                  if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
-                      keyword, profile_length) != 0)
+                  if (png_icc_check_length(png_ptr, keyword, profile_length) !=
+                      0)
                   {
                      /* The length is apparently ok, so we can check the 132
                       * byte header.
                       */
-                     if (png_icc_check_header(png_ptr, &png_ptr->colorspace,
-                         keyword, profile_length, profile_header,
-                         png_ptr->color_type) != 0)
+                     if (png_icc_check_header(png_ptr, keyword, profile_length,
+                              profile_header, png_ptr->color_type) != 0)
                      {
                         /* Now read the tag table; a variable size buffer is
                          * needed at this point, allocate one for the whole
@@ -1493,7 +1421,7 @@
                         png_uint_32 tag_count =
                            png_get_uint_32(profile_header + 128);
                         png_bytep profile = png_read_buffer(png_ptr,
-                            profile_length, 2/*silent*/);
+                              profile_length);
 
                         if (profile != NULL)
                         {
@@ -1512,8 +1440,7 @@
                            if (size == 0)
                            {
                               if (png_icc_check_tag_table(png_ptr,
-                                  &png_ptr->colorspace, keyword, profile_length,
-                                  profile) != 0)
+                                       keyword, profile_length, profile) != 0)
                               {
                                  /* The profile has been validated for basic
                                   * security issues, so read the whole thing in.
@@ -1545,13 +1472,6 @@
                                     png_crc_finish(png_ptr, length);
                                     finished = 1;
 
-# if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
-                                    /* Check for a match against sRGB */
-                                    png_icc_set_sRGB(png_ptr,
-                                        &png_ptr->colorspace, profile,
-                                        png_ptr->zstream.adler);
-# endif
-
                                     /* Steal the profile for info_ptr. */
                                     if (info_ptr != NULL)
                                     {
@@ -1574,11 +1494,7 @@
                                        }
 
                                        else
-                                       {
-                                          png_ptr->colorspace.flags |=
-                                             PNG_COLORSPACE_INVALID;
                                           errmsg = "out of memory";
-                                       }
                                     }
 
                                     /* else the profile remains in the read
@@ -1586,13 +1502,10 @@
                                      * chunks.
                                      */
 
-                                    if (info_ptr != NULL)
-                                       png_colorspace_sync(png_ptr, info_ptr);
-
                                     if (errmsg == NULL)
                                     {
                                        png_ptr->zowner = 0;
-                                       return;
+                                       return handled_ok;
                                     }
                                  }
                                  if (errmsg == NULL)
@@ -1633,22 +1546,21 @@
          errmsg = "bad keyword";
    }
 
-   else
-      errmsg = "too many profiles";
-
    /* Failure: the reason is in 'errmsg' */
    if (finished == 0)
       png_crc_finish(png_ptr, length);
 
-   png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
-   png_colorspace_sync(png_ptr, info_ptr);
    if (errmsg != NULL) /* else already output */
       png_chunk_benign_error(png_ptr, errmsg);
+
+   return handled_error;
 }
+#else
+#  define png_handle_iCCP NULL
 #endif /* READ_iCCP */
 
 #ifdef PNG_READ_sPLT_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle chunks that are > 64K under DOS */
 {
@@ -1669,7 +1581,7 @@
       if (png_ptr->user_chunk_cache_max == 1)
       {
          png_crc_finish(png_ptr, length);
-         return;
+         return handled_error;
       }
 
       if (--png_ptr->user_chunk_cache_max == 1)
@@ -1676,36 +1588,17 @@
       {
          png_warning(png_ptr, "No space in chunk cache for sPLT");
          png_crc_finish(png_ptr, length);
-         return;
+         return handled_error;
       }
    }
 #endif
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-#ifdef PNG_MAX_MALLOC_64K
-   if (length > 65535U)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "too large to fit in memory");
-      return;
-   }
-#endif
-
-   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+   buffer = png_read_buffer(png_ptr, length+1);
    if (buffer == NULL)
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
 
@@ -1716,7 +1609,7 @@
    png_crc_read(png_ptr, buffer, length);
 
    if (png_crc_finish(png_ptr, skip) != 0)
-      return;
+      return handled_error;
 
    buffer[length] = 0;
 
@@ -1729,7 +1622,7 @@
    if (length < 2U || entry_start > buffer + (length - 2U))
    {
       png_warning(png_ptr, "malformed sPLT chunk");
-      return;
+      return handled_error;
    }
 
    new_palette.depth = *entry_start++;
@@ -1743,7 +1636,7 @@
    if ((data_length % (unsigned int)entry_size) != 0)
    {
       png_warning(png_ptr, "sPLT chunk has bad length");
-      return;
+      return handled_error;
    }
 
    dl = (png_uint_32)(data_length / (unsigned int)entry_size);
@@ -1752,7 +1645,7 @@
    if (dl > max_dl)
    {
       png_warning(png_ptr, "sPLT chunk too long");
-      return;
+      return handled_error;
    }
 
    new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size);
@@ -1763,10 +1656,9 @@
    if (new_palette.entries == NULL)
    {
       png_warning(png_ptr, "sPLT chunk requires too much memory");
-      return;
+      return handled_error;
    }
 
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
    for (i = 0; i < new_palette.nentries; i++)
    {
       pp = new_palette.entries + i;
@@ -1789,32 +1681,7 @@
 
       pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
    }
-#else
-   pp = new_palette.entries;
 
-   for (i = 0; i < new_palette.nentries; i++)
-   {
-
-      if (new_palette.depth == 8)
-      {
-         pp[i].red   = *entry_start++;
-         pp[i].green = *entry_start++;
-         pp[i].blue  = *entry_start++;
-         pp[i].alpha = *entry_start++;
-      }
-
-      else
-      {
-         pp[i].red   = png_get_uint_16(entry_start); entry_start += 2;
-         pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
-         pp[i].blue  = png_get_uint_16(entry_start); entry_start += 2;
-         pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
-      }
-
-      pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;
-   }
-#endif
-
    /* Discard all chunk data except the name and stash that */
    new_palette.name = (png_charp)buffer;
 
@@ -1821,11 +1688,14 @@
    png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
 
    png_free(png_ptr, new_palette.entries);
+   return handled_ok;
 }
+#else
+#  define png_handle_sPLT NULL
 #endif /* READ_sPLT */
 
 #ifdef PNG_READ_tRNS_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
@@ -1832,23 +1702,6 @@
 
    png_debug(1, "in png_handle_tRNS");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
    if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
    {
       png_byte buf[2];
@@ -1857,7 +1710,7 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "invalid");
-         return;
+         return handled_error;
       }
 
       png_crc_read(png_ptr, buf, 2);
@@ -1873,7 +1726,7 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "invalid");
-         return;
+         return handled_error;
       }
 
       png_crc_read(png_ptr, buf, length);
@@ -1887,10 +1740,9 @@
    {
       if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
       {
-         /* TODO: is this actually an error in the ISO spec? */
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "out of place");
-         return;
+         return handled_error;
       }
 
       if (length > (unsigned int) png_ptr->num_palette ||
@@ -1899,7 +1751,7 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "invalid");
-         return;
+         return handled_error;
       }
 
       png_crc_read(png_ptr, readbuf, length);
@@ -1910,13 +1762,13 @@
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "invalid with alpha channel");
-      return;
+      return handled_error;
    }
 
    if (png_crc_finish(png_ptr, 0) != 0)
    {
       png_ptr->num_trans = 0;
-      return;
+      return handled_error;
    }
 
    /* TODO: this is a horrible side effect in the palette case because the
@@ -1925,11 +1777,14 @@
     */
    png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
        &(png_ptr->trans_color));
+   return handled_ok;
 }
+#else
+#  define png_handle_tRNS NULL
 #endif
 
 #ifdef PNG_READ_bKGD_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    unsigned int truelen;
@@ -1938,28 +1793,18 @@
 
    png_debug(1, "in png_handle_bKGD");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
-       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
-       (png_ptr->mode & PNG_HAVE_PLTE) == 0))
+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
+      if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
+      {
+         png_crc_finish(png_ptr, length);
+         png_chunk_benign_error(png_ptr, "out of place");
+         return handled_error;
+      }
 
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
+      truelen = 1;
    }
 
-   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-      truelen = 1;
-
    else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
       truelen = 6;
 
@@ -1970,13 +1815,13 @@
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "invalid");
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buf, truelen);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* We convert the index value into RGB components so that we can allow
     * arbitrary RGB values for background when we have transparency, and
@@ -1992,7 +1837,7 @@
          if (buf[0] >= info_ptr->num_palette)
          {
             png_chunk_benign_error(png_ptr, "invalid index");
-            return;
+            return handled_error;
          }
 
          background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
@@ -2013,7 +1858,7 @@
          if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth))
          {
             png_chunk_benign_error(png_ptr, "invalid gray level");
-            return;
+            return handled_error;
          }
       }
 
@@ -2031,7 +1876,7 @@
          if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0)
          {
             png_chunk_benign_error(png_ptr, "invalid color");
-            return;
+            return handled_error;
          }
       }
 
@@ -2043,11 +1888,14 @@
    }
 
    png_set_bKGD(png_ptr, info_ptr, &background);
+   return handled_ok;
 }
+#else
+#  define png_handle_bKGD NULL
 #endif
 
 #ifdef PNG_READ_cICP_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[4];
@@ -2054,41 +1902,39 @@
 
    png_debug(1, "in png_handle_cICP");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
+   png_crc_read(png_ptr, buf, 4);
 
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
+   if (png_crc_finish(png_ptr, 0) != 0)
+      return handled_error;
 
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cICP) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
+   png_set_cICP(png_ptr, info_ptr, buf[0], buf[1],  buf[2], buf[3]);
 
-   else if (length != 4)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
+   /* We only use 'chromaticities' for RGB to gray */
+#  ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+      if (!png_has_chunk(png_ptr, mDCV))
+      {
+         /* TODO: png_ptr->chromaticities = chromaticities; */
+      }
+#  endif /* READ_RGB_TO_GRAY */
 
-   png_crc_read(png_ptr, buf, 4);
+#ifdef PNG_READ_GAMMA_SUPPORTED
+      /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA.  cICP is
+       * at the head so simply set the gamma if it can be determined.  If not
+       * chunk_gamma remains unchanged; sRGB and gAMA handling check it for
+       * being zero.
+       */
+      /* TODO: set png_struct::chunk_gamma when possible */
+#endif /*READ_GAMMA*/
 
-   if (png_crc_finish(png_ptr, 0) != 0)
-      return;
-
-   png_set_cICP(png_ptr, info_ptr, buf[0], buf[1],  buf[2], buf[3]);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_cICP NULL
 #endif
 
 #ifdef PNG_READ_cLLI_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_cLLI(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[8];
@@ -2095,77 +1941,34 @@
 
    png_debug(1, "in png_handle_cLLI");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cLLI) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   else if (length != 8)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 8);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* The error checking happens here, this puts it in just one place: */
    png_set_cLLI_fixed(png_ptr, info_ptr, png_get_uint_32(buf),
          png_get_uint_32(buf+4));
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_cLLI NULL
 #endif
 
 #ifdef PNG_READ_mDCV_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_mDCV(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
+   png_xy chromaticities;
    png_byte buf[24];
 
    png_debug(1, "in png_handle_mDCV");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_mDCV) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   else if (length != 24)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 24);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* The error checking happens here, this puts it in just one place.  The
     * odd /50000 scaling factor makes it more difficult but the (x.y) values are
@@ -2178,86 +1981,81 @@
     * stored in four bytes.  This is very, very confusing.  These APIs remove
     * the confusion by copying the existing, well established, API.
     */
+   chromaticities.redx   = png_get_uint_16(buf+ 0U) << 1; /* red x */
+   chromaticities.redy   = png_get_uint_16(buf+ 2U) << 1; /* red y */
+   chromaticities.greenx = png_get_uint_16(buf+ 4U) << 1; /* green x */
+   chromaticities.greeny = png_get_uint_16(buf+ 6U) << 1; /* green y */
+   chromaticities.bluex  = png_get_uint_16(buf+ 8U) << 1; /* blue x */
+   chromaticities.bluey  = png_get_uint_16(buf+10U) << 1; /* blue y */
+   chromaticities.whitex = png_get_uint_16(buf+12U) << 1; /* white x */
+   chromaticities.whitey = png_get_uint_16(buf+14U) << 1; /* white y */
+
    png_set_mDCV_fixed(png_ptr, info_ptr,
-         png_get_uint_16(buf+12U) << 1U, /* white x */
-         png_get_uint_16(buf+14U) << 1U, /* white y */
-         png_get_uint_16(buf+ 0U) << 1U, /* red x */
-         png_get_uint_16(buf+ 2U) << 1U, /* red y */
-         png_get_uint_16(buf+ 4U) << 1U, /* green x */
-         png_get_uint_16(buf+ 6U) << 1U, /* green y */
-         png_get_uint_16(buf+ 8U) << 1U, /* blue x */
-         png_get_uint_16(buf+10U) << 1U, /* blue y */
+         chromaticities.whitex, chromaticities.whitey,
+         chromaticities.redx, chromaticities.redy,
+         chromaticities.greenx, chromaticities.greeny,
+         chromaticities.bluex, chromaticities.bluey,
          png_get_uint_32(buf+16U), /* peak luminance */
          png_get_uint_32(buf+20U));/* minimum perceivable luminance */
+
+   /* We only use 'chromaticities' for RGB to gray */
+#  ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+      png_ptr->chromaticities = chromaticities;
+#  endif /* READ_RGB_TO_GRAY */
+
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_mDCV NULL
 #endif
 
 #ifdef PNG_READ_eXIf_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
-   unsigned int i;
+   png_bytep buffer = NULL;
 
    png_debug(1, "in png_handle_eXIf");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
+   buffer = png_read_buffer(png_ptr, length);
 
-   if (length < 2)
+   if (buffer == NULL)
    {
       png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "too short");
-      return;
+      png_chunk_benign_error(png_ptr, "out of memory");
+      return handled_error;
    }
 
-   else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
+   png_crc_read(png_ptr, buffer, length);
 
-   info_ptr->free_me |= PNG_FREE_EXIF;
+   if (png_crc_finish(png_ptr, 0) != 0)
+      return handled_error;
 
-   info_ptr->eXIf_buf = png_voidcast(png_bytep,
-             png_malloc_warn(png_ptr, length));
-
-   if (info_ptr->eXIf_buf == NULL)
+   /* PNGv3: the code used to check the byte order mark at the start for MM or
+    * II, however PNGv3 states that the the first 4 bytes should be checked.
+    * The caller ensures that there are four bytes available.
+    */
    {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of memory");
-      return;
-   }
+      png_uint_32 header = png_get_uint_32(buffer);
 
-   for (i = 0; i < length; i++)
-   {
-      png_byte buf[1];
-      png_crc_read(png_ptr, buf, 1);
-      info_ptr->eXIf_buf[i] = buf[0];
-      if (i == 1)
+      /* These numbers are copied from the PNGv3 spec: */
+      if (header != 0x49492A00 && header != 0x4D4D002A)
       {
-         if ((buf[0] != 'M' && buf[0] != 'I') ||
-             (info_ptr->eXIf_buf[0] != buf[0]))
-         {
-            png_crc_finish(png_ptr, length - 2);
-            png_chunk_benign_error(png_ptr, "incorrect byte-order specifier");
-            png_free(png_ptr, info_ptr->eXIf_buf);
-            info_ptr->eXIf_buf = NULL;
-            return;
-         }
+         png_chunk_benign_error(png_ptr, "invalid");
+         return handled_error;
       }
    }
 
-   if (png_crc_finish(png_ptr, 0) == 0)
-      png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);
-
-   png_free(png_ptr, info_ptr->eXIf_buf);
-   info_ptr->eXIf_buf = NULL;
+   png_set_eXIf_1(png_ptr, info_ptr, length, buffer);
+   return handled_ok;
 }
+#else
+#  define png_handle_eXIf NULL
 #endif
 
 #ifdef PNG_READ_hIST_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    unsigned int num, i;
@@ -2265,26 +2063,14 @@
 
    png_debug(1, "in png_handle_hIST");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
+   /* This cast is safe because the chunk definition limits the length to a
+    * maximum of 1024 bytes.
+    *
+    * TODO: maybe use png_uint_32 anyway, not unsigned int, to reduce the
+    * casts.
+    */
+   num = (unsigned int)length / 2 ;
 
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
-       (png_ptr->mode & PNG_HAVE_PLTE) == 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   num = length / 2 ;
-
    if (length != num * 2 ||
        num != (unsigned int)png_ptr->num_palette ||
        num > (unsigned int)PNG_MAX_PALETTE_LENGTH)
@@ -2291,7 +2077,7 @@
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "invalid");
-      return;
+      return handled_error;
    }
 
    for (i = 0; i < num; i++)
@@ -2303,14 +2089,17 @@
    }
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    png_set_hIST(png_ptr, info_ptr, readbuf);
+   return handled_ok;
 }
+#else
+#  define png_handle_hIST NULL
 #endif
 
 #ifdef PNG_READ_pHYs_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[9];
@@ -2319,44 +2108,24 @@
 
    png_debug(1, "in png_handle_pHYs");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   if (length != 9)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 9);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    res_x = png_get_uint_32(buf);
    res_y = png_get_uint_32(buf + 4);
    unit_type = buf[8];
    png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_pHYs NULL
 #endif
 
 #ifdef PNG_READ_oFFs_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[9];
@@ -2365,45 +2134,25 @@
 
    png_debug(1, "in png_handle_oFFs");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   if (length != 9)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 9);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    offset_x = png_get_int_32(buf);
    offset_y = png_get_int_32(buf + 4);
    unit_type = buf[8];
    png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_oFFs NULL
 #endif
 
 #ifdef PNG_READ_pCAL_SUPPORTED
 /* Read the pCAL chunk (described in the PNG Extensions document) */
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_int_32 X0, X1;
@@ -2413,40 +2162,22 @@
    int i;
 
    png_debug(1, "in png_handle_pCAL");
-
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
    png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
        length + 1);
 
-   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+   buffer = png_read_buffer(png_ptr, length+1);
 
    if (buffer == NULL)
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buffer, length);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    buffer[length] = 0; /* Null terminate the last string */
 
@@ -2462,7 +2193,7 @@
    if (endptr - buf <= 12)
    {
       png_chunk_benign_error(png_ptr, "invalid");
-      return;
+      return handled_error;
    }
 
    png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
@@ -2482,7 +2213,7 @@
        (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
    {
       png_chunk_benign_error(png_ptr, "invalid parameter count");
-      return;
+      return handled_error;
    }
 
    else if (type >= PNG_EQUATION_LAST)
@@ -2501,7 +2232,7 @@
    if (params == NULL)
    {
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
    /* Get pointers to the start of each parameter string. */
@@ -2519,7 +2250,7 @@
       {
          png_free(png_ptr, params);
          png_chunk_benign_error(png_ptr, "invalid data");
-         return;
+         return handled_error;
       }
    }
 
@@ -2526,13 +2257,22 @@
    png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,
        (png_charp)units, params);
 
+   /* TODO: BUG: png_set_pCAL calls png_chunk_report which, in this case, calls
+    * png_benign_error and that can error out.
+    *
+    * png_read_buffer needs to be allocated with space for both nparams and the
+    * parameter strings.  Not hard to do.
+    */
    png_free(png_ptr, params);
+   return handled_ok;
 }
+#else
+#  define png_handle_pCAL NULL
 #endif
 
 #ifdef PNG_READ_sCAL_SUPPORTED
 /* Read the sCAL chunk */
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_bytep buffer;
@@ -2540,42 +2280,16 @@
    int state;
 
    png_debug(1, "in png_handle_sCAL");
-
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "out of place");
-      return;
-   }
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
-   /* Need unit type, width, \0, height: minimum 4 bytes */
-   else if (length < 4)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
        length + 1);
 
-   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+   buffer = png_read_buffer(png_ptr, length+1);
 
    if (buffer == NULL)
    {
+      png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      png_crc_finish(png_ptr, length);
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buffer, length);
@@ -2582,13 +2296,13 @@
    buffer[length] = 0; /* Null terminate the last string */
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* Validate the unit. */
    if (buffer[0] != 1 && buffer[0] != 2)
    {
       png_chunk_benign_error(png_ptr, "invalid unit");
-      return;
+      return handled_error;
    }
 
    /* Validate the ASCII numbers, need two ASCII numbers separated by
@@ -2617,15 +2331,22 @@
          png_chunk_benign_error(png_ptr, "non-positive height");
 
       else
+      {
          /* This is the (only) success case. */
          png_set_sCAL_s(png_ptr, info_ptr, buffer[0],
              (png_charp)buffer+1, (png_charp)buffer+heighti);
+         return handled_ok;
+      }
    }
+
+   return handled_error;
 }
+#else
+#  define png_handle_sCAL NULL
 #endif
 
 #ifdef PNG_READ_tIME_SUPPORTED
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_byte buf[7];
@@ -2633,30 +2354,17 @@
 
    png_debug(1, "in png_handle_tIME");
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
-   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "duplicate");
-      return;
-   }
-
+   /* TODO: what is this doing here?  It should be happened in pngread.c and
+    * pngpread.c, although it could be moved to png_handle_chunk below and
+    * thereby avoid some code duplication.
+    */
    if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
-   if (length != 7)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "invalid");
-      return;
-   }
-
    png_crc_read(png_ptr, buf, 7);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    mod_time.second = buf[6];
    mod_time.minute = buf[5];
@@ -2666,12 +2374,16 @@
    mod_time.year = png_get_uint_16(buf);
 
    png_set_tIME(png_ptr, info_ptr, &mod_time);
+   return handled_ok;
+   PNG_UNUSED(length)
 }
+#else
+#  define png_handle_tIME NULL
 #endif
 
 #ifdef PNG_READ_tEXt_SUPPORTED
 /* Note: this does not properly handle chunks that are > 64K under DOS */
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_text  text_info;
@@ -2688,7 +2400,7 @@
       if (png_ptr->user_chunk_cache_max == 1)
       {
          png_crc_finish(png_ptr, length);
-         return;
+         return handled_error;
       }
 
       if (--png_ptr->user_chunk_cache_max == 1)
@@ -2695,38 +2407,28 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "no space in chunk cache");
-         return;
+         return handled_error;
       }
    }
 #endif
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
+   /* TODO: this doesn't work and shouldn't be necessary. */
    if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
-#ifdef PNG_MAX_MALLOC_64K
-   if (length > 65535U)
-   {
-      png_crc_finish(png_ptr, length);
-      png_chunk_benign_error(png_ptr, "too large to fit in memory");
-      return;
-   }
-#endif
+   buffer = png_read_buffer(png_ptr, length+1);
 
-   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
-
    if (buffer == NULL)
    {
+      png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buffer, length);
 
    if (png_crc_finish(png_ptr, skip) != 0)
-      return;
+      return handled_error;
 
    key = (png_charp)buffer;
    key[length] = 0;
@@ -2745,14 +2447,19 @@
    text_info.text = text;
    text_info.text_length = strlen(text);
 
-   if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0)
-      png_warning(png_ptr, "Insufficient memory to process text chunk");
+   if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) == 0)
+      return handled_ok;
+
+   png_chunk_benign_error(png_ptr, "out of memory");
+   return handled_error;
 }
+#else
+#  define png_handle_tEXt NULL
 #endif
 
 #ifdef PNG_READ_zTXt_SUPPORTED
 /* Note: this does not correctly handle chunks that are > 64K under DOS */
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_const_charp errmsg = NULL;
@@ -2767,7 +2474,7 @@
       if (png_ptr->user_chunk_cache_max == 1)
       {
          png_crc_finish(png_ptr, length);
-         return;
+         return handled_error;
       }
 
       if (--png_ptr->user_chunk_cache_max == 1)
@@ -2774,33 +2481,32 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "no space in chunk cache");
-         return;
+         return handled_error;
       }
    }
 #endif
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
+   /* TODO: should not be necessary. */
    if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
    /* Note, "length" is sufficient here; we won't be adding
-    * a null terminator later.
+    * a null terminator later.  The limit check in png_handle_chunk should be
+    * sufficient.
     */
-   buffer = png_read_buffer(png_ptr, length, 2/*silent*/);
+   buffer = png_read_buffer(png_ptr, length);
 
    if (buffer == NULL)
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buffer, length);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* TODO: also check that the keyword contents match the spec! */
    for (keyword_length = 0;
@@ -2853,8 +2559,10 @@
             text.lang = NULL;
             text.lang_key = NULL;
 
-            if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
-               errmsg = "insufficient memory";
+            if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0)
+               return handled_ok;
+
+            errmsg = "out of memory";
          }
       }
 
@@ -2862,14 +2570,16 @@
          errmsg = png_ptr->zstream.msg;
    }
 
-   if (errmsg != NULL)
-      png_chunk_benign_error(png_ptr, errmsg);
+   png_chunk_benign_error(png_ptr, errmsg);
+   return handled_error;
 }
+#else
+#  define png_handle_zTXt NULL
 #endif
 
 #ifdef PNG_READ_iTXt_SUPPORTED
 /* Note: this does not correctly handle chunks that are > 64K under DOS */
-void /* PRIVATE */
+static png_handle_result_code /* PRIVATE */
 png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_const_charp errmsg = NULL;
@@ -2884,7 +2594,7 @@
       if (png_ptr->user_chunk_cache_max == 1)
       {
          png_crc_finish(png_ptr, length);
-         return;
+         return handled_error;
       }
 
       if (--png_ptr->user_chunk_cache_max == 1)
@@ -2891,30 +2601,28 @@
       {
          png_crc_finish(png_ptr, length);
          png_chunk_benign_error(png_ptr, "no space in chunk cache");
-         return;
+         return handled_error;
       }
    }
 #endif
 
-   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
-      png_chunk_error(png_ptr, "missing IHDR");
-
+   /* TODO: should not be necessary. */
    if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
-   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
+   buffer = png_read_buffer(png_ptr, length+1);
 
    if (buffer == NULL)
    {
       png_crc_finish(png_ptr, length);
       png_chunk_benign_error(png_ptr, "out of memory");
-      return;
+      return handled_error;
    }
 
    png_crc_read(png_ptr, buffer, length);
 
    if (png_crc_finish(png_ptr, 0) != 0)
-      return;
+      return handled_error;
 
    /* First the keyword. */
    for (prefix_length=0;
@@ -3004,8 +2712,10 @@
          text.text_length = 0;
          text.itxt_length = uncompressed_length;
 
-         if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
-            errmsg = "insufficient memory";
+         if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0)
+            return handled_ok;
+
+         errmsg = "out of memory";
       }
    }
 
@@ -3014,7 +2724,10 @@
 
    if (errmsg != NULL)
       png_chunk_benign_error(png_ptr, errmsg);
+   return handled_error;
 }
+#else
+#  define png_handle_iTXt NULL
 #endif
 
 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
@@ -3022,7 +2735,7 @@
 static int
 png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
 {
-   png_alloc_size_t limit = PNG_SIZE_MAX;
+   const png_alloc_size_t limit = png_chunk_max(png_ptr);
 
    if (png_ptr->unknown_chunk.data != NULL)
    {
@@ -3030,16 +2743,6 @@
       png_ptr->unknown_chunk.data = NULL;
    }
 
-#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (png_ptr->user_chunk_malloc_max > 0 &&
-       png_ptr->user_chunk_malloc_max < limit)
-      limit = png_ptr->user_chunk_malloc_max;
-
-#  elif PNG_USER_CHUNK_MALLOC_MAX > 0
-   if (PNG_USER_CHUNK_MALLOC_MAX < limit)
-      limit = PNG_USER_CHUNK_MALLOC_MAX;
-#  endif
-
    if (length <= limit)
    {
       PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
@@ -3078,11 +2781,11 @@
 #endif /* READ_UNKNOWN_CHUNKS */
 
 /* Handle an unknown, or known but disabled, chunk */
-void /* PRIVATE */
+png_handle_result_code /*PRIVATE*/
 png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
     png_uint_32 length, int keep)
 {
-   int handled = 0; /* the chunk was handled */
+   png_handle_result_code handled = handled_discarded; /* the default */
 
    png_debug(1, "in png_handle_unknown");
 
@@ -3129,7 +2832,7 @@
           *           error at this point unless it is to be saved.
           * positive: The chunk was handled, libpng will ignore/discard it.
           */
-         if (ret < 0)
+         if (ret < 0) /* handled_error */
             png_chunk_error(png_ptr, "error in user chunk");
 
          else if (ret == 0)
@@ -3163,7 +2866,7 @@
 
          else /* chunk was handled */
          {
-            handled = 1;
+            handled = handled_ok;
             /* Critical chunks can be safely discarded at this point. */
             keep = PNG_HANDLE_CHUNK_NEVER;
          }
@@ -3248,7 +2951,7 @@
              */
             png_set_unknown_chunks(png_ptr, info_ptr,
                 &png_ptr->unknown_chunk, 1);
-            handled = 1;
+            handled = handled_saved;
 #  ifdef PNG_USER_LIMITS_SUPPORTED
             break;
       }
@@ -3274,79 +2977,267 @@
 #endif /* !READ_UNKNOWN_CHUNKS */
 
    /* Check for unhandled critical chunks */
-   if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
+   if (handled < handled_saved && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
       png_chunk_error(png_ptr, "unhandled critical chunk");
+
+   return handled;
 }
 
-/* This function is called to verify that a chunk name is valid.
- * This function can't have the "critical chunk check" incorporated
- * into it, since in the future we will need to be able to call user
- * functions to handle unknown critical chunks after we check that
- * the chunk name itself is valid.
+/* APNG handling: the minimal implementation of APNG handling in libpng 1.6
+ * requires that those significant applications which already handle APNG not
+ * get hosed.  To do this ensure the code here will have to ensure than APNG
+ * data by default (at least in 1.6) gets stored in the unknown chunk list.
+ * Maybe this can be relaxed in a few years but at present it's just the only
+ * safe way.
+ *
+ * ATM just cause unknown handling for all three chunks:
  */
+#define png_handle_acTL NULL
+#define png_handle_fcTL NULL
+#define png_handle_fdAT NULL
 
-/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:
+/*
+ * 1.6.47: This is the new table driven interface to all the chunk handling.
  *
- * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+ * The table describes the PNG standard rules for **reading** known chunks -
+ * every chunk which has an entry in PNG_KNOWN_CHUNKS.  The table contains an
+ * entry for each PNG_INDEX_cHNK describing the rules.
+ *
+ * In this initial version the only information in the entry is the
+ * png_handle_cHNK function for the chunk in question.  When chunk support is
+ * compiled out the entry will be NULL.
  */
+static const struct
+{
+   png_handle_result_code (*handler)(
+         png_structrp, png_inforp, png_uint_32 length);
+      /* A chunk-specific 'handler', NULL if the chunk is not supported in this
+       * build.
+       */
 
-void /* PRIVATE */
-png_check_chunk_name(png_const_structrp png_ptr, png_uint_32 chunk_name)
+   /* Crushing these values helps on modern 32-bit architectures because the
+    * pointer and the following bit fields both end up requiring 32 bits.
+    * Typically this will halve the table size.  On 64-bit architectures the
+    * table entries will typically be 8 bytes.
+    */
+   png_uint_32 max_length :12; /* Length min, max in bytes */
+   png_uint_32 min_length :8;
+      /* Length errors on critical chunks have special handling to preserve the
+       * existing behaviour in libpng 1.6.  Anciallary chunks are checked below
+       * and produce a 'benign' error.
+       */
+   png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */
+   png_uint_32 pos_after  :4; /* PNG_HAVE_ values chunk must follow */
+      /* NOTE: PLTE, tRNS and bKGD require special handling which depends on
+       * the colour type of the base image.
+       */
+   png_uint_32 multiple   :1; /* Multiple occurences permitted */
+      /* This is enabled for PLTE because PLTE may, in practice, be optional */
+}
+read_chunks[PNG_INDEX_unknown] =
 {
-   int i;
-   png_uint_32 cn=chunk_name;
+   /* Definitions as above but done indirectly by #define so that
+    * PNG_KNOWN_CHUNKS can be used safely to build the table in order.
+    *
+    * Each CDcHNK definition lists the values for the parameters **after**
+    * the first, 'handler', function.  'handler' is NULL when the chunk has no
+    * compiled in support.
+    */
+#  define NoCheck 0x801U      /* Do not check the maximum length */
+#  define Limit   0x802U      /* Limit to png_chunk_max bytes */
+#  define LKMin   3U+LZ77Min  /* Minimum length of keyword+LZ77 */
 
-   png_debug(1, "in png_check_chunk_name");
+#define hIHDR PNG_HAVE_IHDR
+#define hPLTE PNG_HAVE_PLTE
+#define hIDAT PNG_HAVE_IDAT
+   /* For the two chunks, tRNS and bKGD which can occur in PNGs without a PLTE
+    * but must occur after the PLTE use this and put the check in the handler
+    * routine for colour mapped images were PLTE is required.  Also put a check
+    * in PLTE for other image types to drop the PLTE if tRNS or bKGD have been
+    * seen.
+    */
+#define hCOL  (PNG_HAVE_PLTE|PNG_HAVE_IDAT)
+   /* Used for the decoding chunks which must be before PLTE. */
+#define aIDAT PNG_AFTER_IDAT
 
-   for (i=1; i<=4; ++i)
+   /* Chunks from W3C PNG v3: */
+   /*       cHNK  max_len,   min, before, after, multiple */
+#  define CDIHDR      13U,   13U,  hIHDR,     0,        0
+#  define CDPLTE  NoCheck,    0U,      0, hIHDR,        1
+      /* PLTE errors are only critical for colour-map images, consequently the
+       * hander does all the checks.
+       */
+#  define CDIDAT  NoCheck,    0U,  aIDAT, hIHDR,        1
+#  define CDIEND  NoCheck,    0U,      0, aIDAT,        0
+      /* Historically data was allowed in IEND */
+#  define CDtRNS     256U,    0U,  hIDAT, hIHDR,        0
+#  define CDcHRM      32U,   32U,   hCOL, hIHDR,        0
+#  define CDgAMA       4U,    4U,   hCOL, hIHDR,        0
+#  define CDiCCP  NoCheck, LKMin,   hCOL, hIHDR,        0
+#  define CDsBIT       4U,    1U,   hCOL, hIHDR,        0
+#  define CDsRGB       1U,    1U,   hCOL, hIHDR,        0
+#  define CDcICP       4U,    4U,   hCOL, hIHDR,        0
+#  define CDmDCV      24U,   24U,   hCOL, hIHDR,        0
+#  define CDeXIf    Limit,    4U,      0, hIHDR,        0
+#  define CDcLLI       8U,    8U,   hCOL, hIHDR,        0
+#  define CDtEXt  NoCheck,    2U,      0, hIHDR,        1
+      /* Allocates 'length+1'; checked in the handler */
+#  define CDzTXt    Limit, LKMin,      0, hIHDR,        1
+#  define CDiTXt  NoCheck,    6U,      0, hIHDR,        1
+      /* Allocates 'length+1'; checked in the handler */
+#  define CDbKGD       6U,    1U,  hIDAT, hIHDR,        0
+#  define CDhIST    1024U,    0U,  hPLTE, hIHDR,        0
+#  define CDpHYs       9U,    9U,  hIDAT, hIHDR,        0
+#  define CDsPLT  NoCheck,    3U,  hIDAT, hIHDR,        1
+      /* Allocates 'length+1'; checked in the handler */
+#  define CDtIME       7U,    7U,      0, hIHDR,        0
+#  define CDacTL       8U,    8U,  hIDAT, hIHDR,        0
+#  define CDfcTL      25U,   26U,      0, hIHDR,        1
+#  define CDfdAT    Limit,    4U,  hIDAT, hIHDR,        1
+   /* Supported chunks from PNG extensions 1.5.0, NYI so limit */
+#  define CDoFFs       9U,    9U,  hIDAT, hIHDR,        0
+#  define CDpCAL  NoCheck,   14U,  hIDAT, hIHDR,        0
+      /* Allocates 'length+1'; checked in the handler */
+#  define CDsCAL    Limit,    4U,  hIDAT, hIHDR,        0
+      /* Allocates 'length+1'; checked in the handler */
+
+#  define PNG_CHUNK(cHNK, index) { png_handle_ ## cHNK, CD ## cHNK },
+   PNG_KNOWN_CHUNKS
+#  undef PNG_CHUNK
+};
+
+
+static png_index
+png_chunk_index_from_name(png_uint_32 chunk_name)
+{
+   /* For chunk png_cHNK return PNG_INDEX_cHNK.  Return PNG_INDEX_unknown if
+    * chunk_name is not known.  Notice that in a particular build "known" does
+    * not necessarily mean "supported", although the inverse applies.
+    */
+   switch (chunk_name)
    {
-      int c = cn & 0xff;
+#     define PNG_CHUNK(cHNK, index)\
+         case png_ ## cHNK: return PNG_INDEX_ ## cHNK; /* == index */
 
-      if (c < 65 || c > 122 || (c > 90 && c < 97))
-         png_chunk_error(png_ptr, "invalid chunk type");
+      PNG_KNOWN_CHUNKS
 
-      cn >>= 8;
+#     undef PNG_CHUNK
+
+      default: return PNG_INDEX_unknown;
    }
 }
 
-void /* PRIVATE */
-png_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length)
+png_handle_result_code /*PRIVATE*/
+png_handle_chunk(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
-   png_alloc_size_t limit = PNG_UINT_31_MAX;
+   /* CSE: these things don't change, these autos are just to save typing and
+    * make the code more clear.
+    */
+   const png_uint_32 chunk_name = png_ptr->chunk_name;
+   const png_index chunk_index = png_chunk_index_from_name(chunk_name);
 
-# ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (png_ptr->user_chunk_malloc_max > 0 &&
-       png_ptr->user_chunk_malloc_max < limit)
-      limit = png_ptr->user_chunk_malloc_max;
-# elif PNG_USER_CHUNK_MALLOC_MAX > 0
-   if (PNG_USER_CHUNK_MALLOC_MAX < limit)
-      limit = PNG_USER_CHUNK_MALLOC_MAX;
-# endif
-   if (png_ptr->chunk_name == png_IDAT)
+   png_handle_result_code handled = handled_error;
+   png_const_charp errmsg = NULL;
+
+   /* Is this a known chunk?  If not there are no checks performed here;
+    * png_handle_unknown does the correct checks.  This means that the values
+    * for known but unsupported chunks in the above table are not used here
+    * however the chunks_seen fields in png_struct are still set.
+    */
+   if (chunk_index == PNG_INDEX_unknown ||
+       read_chunks[chunk_index].handler == NULL)
    {
-      png_alloc_size_t idat_limit = PNG_UINT_31_MAX;
-      size_t row_factor =
-         (size_t)png_ptr->width
-         * (size_t)png_ptr->channels
-         * (png_ptr->bit_depth > 8? 2: 1)
-         + 1
-         + (png_ptr->interlaced? 6: 0);
-      if (png_ptr->height > PNG_UINT_32_MAX/row_factor)
-         idat_limit = PNG_UINT_31_MAX;
-      else
-         idat_limit = png_ptr->height * row_factor;
-      row_factor = row_factor > 32566? 32566 : row_factor;
-      idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */
-      idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX;
-      limit = limit < idat_limit? idat_limit : limit;
+      handled = png_handle_unknown(
+            png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT);
    }
 
-   if (length > limit)
+   /* First check the position.   The first check is historical; the stream must
+    * start with IHDR and anything else causes libpng to give up immediately.
+    */
+   else if (chunk_index != PNG_INDEX_IHDR &&
+            (png_ptr->mode & PNG_HAVE_IHDR) == 0)
+      png_chunk_error(png_ptr, "missing IHDR"); /* NORETURN */
+
+   /* Before all the pos_before chunks, after all the pos_after chunks. */
+   else if (((png_ptr->mode & read_chunks[chunk_index].pos_before) != 0) ||
+            ((png_ptr->mode & read_chunks[chunk_index].pos_after) !=
+             read_chunks[chunk_index].pos_after))
    {
-      png_debug2(0," length = %lu, limit = %lu",
-         (unsigned long)length,(unsigned long)limit);
-      png_benign_error(png_ptr, "chunk data is too large");
+      errmsg = "out of place";
    }
+
+   /* Now check for duplicates: duplicated critical chunks also produce a
+    * full error.
+    */
+   else if (read_chunks[chunk_index].multiple == 0 &&
+            png_file_has_chunk(png_ptr, chunk_index))
+   {
+      errmsg = "duplicate";
+   }
+
+   else if (length < read_chunks[chunk_index].min_length)
+      errmsg = "too short";
+   else
+   {
+      /* NOTE: apart from IHDR the critical chunks (PLTE, IDAT and IEND) are set
+       * up above not to do any length checks.
+       *
+       * The png_chunk_max check ensures that the variable length chunks are
+       * always checked at this point for being within the system allocation
+       * limits.
+       */
+      unsigned max_length = read_chunks[chunk_index].max_length;
+
+      switch (max_length)
+      {
+         case Limit:
+            /* png_read_chunk_header has already png_error'ed chunks with a
+             * length exceeding the 31-bit PNG limit, so just check the memory
+             * limit:
+             */
+            if (length <= png_chunk_max(png_ptr))
+               goto MeetsLimit;
+
+            errmsg = "length exceeds libpng limit";
+            break;
+
+         default:
+            if (length <= max_length)
+               goto MeetsLimit;
+
+            errmsg = "too long";
+            break;
+
+         case NoCheck:
+         MeetsLimit:
+            handled = read_chunks[chunk_index].handler(
+                  png_ptr, info_ptr, length);
+            break;
+      }
+   }
+
+   /* If there was an error or the chunk was simply skipped it is not counted as
+    * 'seen'.
+    */
+   if (errmsg != NULL)
+   {
+      if (PNG_CHUNK_CRITICAL(chunk_name)) /* stop immediately */
+         png_chunk_error(png_ptr, errmsg);
+      else /* ancillary chunk */
+      {
+         /* The chunk data is skipped: */
+         png_crc_finish(png_ptr, length);
+         png_chunk_benign_error(png_ptr, errmsg);
+      }
+   }
+
+   else if (handled >= handled_saved)
+   {
+      if (chunk_index != PNG_INDEX_unknown)
+         png_file_add_chunk(png_ptr, chunk_index);
+   }
+
+   return handled;
 }
 
 /* Combines the row recently read in with the existing pixels in the row.  This
@@ -4336,6 +4227,9 @@
 
          avail_in = png_ptr->IDAT_read_size;
 
+         if (avail_in > png_chunk_max(png_ptr))
+            avail_in = (uInt)/*SAFE*/png_chunk_max(png_ptr);
+
          if (avail_in > png_ptr->idat_size)
             avail_in = (uInt)png_ptr->idat_size;
 
@@ -4343,9 +4237,14 @@
           * to minimize memory usage by causing lots of re-allocs, but
           * realistically doing IDAT_read_size re-allocs is not likely to be a
           * big problem.
+          *
+          * An error here corresponds to the system being out of memory.
           */
-         buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);
+         buffer = png_read_buffer(png_ptr, avail_in);
 
+         if (buffer == NULL)
+            png_chunk_error(png_ptr, "out of memory");
+
          png_crc_read(png_ptr, buffer, avail_in);
          png_ptr->idat_size -= avail_in;
 

Modified: trunk/Build/source/libs/libpng/libpng-src/pngset.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngset.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngset.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -41,27 +41,21 @@
     png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
     png_fixed_point blue_x, png_fixed_point blue_y)
 {
-   png_xy xy;
-
    png_debug1(1, "in %s storage function", "cHRM fixed");
 
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   xy.redx = red_x;
-   xy.redy = red_y;
-   xy.greenx = green_x;
-   xy.greeny = green_y;
-   xy.bluex = blue_x;
-   xy.bluey = blue_y;
-   xy.whitex = white_x;
-   xy.whitey = white_y;
+   info_ptr->cHRM.redx = red_x;
+   info_ptr->cHRM.redy = red_y;
+   info_ptr->cHRM.greenx = green_x;
+   info_ptr->cHRM.greeny = green_y;
+   info_ptr->cHRM.bluex = blue_x;
+   info_ptr->cHRM.bluey = blue_y;
+   info_ptr->cHRM.whitex = white_x;
+   info_ptr->cHRM.whitey = white_y;
 
-   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
-       2/* override with app values*/) != 0)
-      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
-
-   png_colorspace_sync_info(png_ptr, info_ptr);
+   info_ptr->valid |= PNG_INFO_cHRM;
 }
 
 void PNGFAPI
@@ -73,6 +67,7 @@
     png_fixed_point int_blue_Z)
 {
    png_XYZ XYZ;
+   png_xy xy;
 
    png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
 
@@ -89,11 +84,14 @@
    XYZ.blue_Y = int_blue_Y;
    XYZ.blue_Z = int_blue_Z;
 
-   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace,
-       &XYZ, 2) != 0)
-      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
+   if (png_xy_from_XYZ(&xy, &XYZ) == 0)
+   {
+      info_ptr->cHRM = xy;
+      info_ptr->valid |= PNG_INFO_cHRM;
+   }
 
-   png_colorspace_sync_info(png_ptr, info_ptr);
+   else
+      png_app_error(png_ptr, "invalid cHRM XYZ");
 }
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -205,8 +203,7 @@
 
 #ifdef PNG_mDCV_SUPPORTED
 static png_uint_16
-png_ITU_fixed_16(png_const_structrp png_ptr, png_fixed_point v,
-   png_const_charp text)
+png_ITU_fixed_16(int *error, png_fixed_point v)
 {
    /* Return a safe uint16_t value scaled according to the ITU H273 rules for
     * 16-bit display chromaticities.  Functions like the corresponding
@@ -216,12 +213,11 @@
     */
    v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
    if (v > 65535 || v < 0)
-      png_fixed_error(png_ptr, text);
+   {
+      *error = 1;
+      return 0;
+   }
 
-#  ifndef PNG_ERROR_TEXT_SUPPORTED
-   PNG_UNUSED(text)
-#  endif
-
    return (png_uint_16)/*SAFE*/v;
 }
 
@@ -235,6 +231,7 @@
     png_uint_32 minDL)
 {
    png_uint_16 rx, ry, gx, gy, bx, by, wx, wy;
+   int error;
 
    png_debug1(1, "in %s storage function", "mDCV");
 
@@ -242,15 +239,24 @@
       return;
 
    /* Check the input values to ensure they are in the expected range: */
-   rx = png_ITU_fixed_16(png_ptr, red_x, "png_set_mDCV(red(x))");
-   ry = png_ITU_fixed_16(png_ptr, red_y, "png_set_mDCV(red(y))");
-   gx = png_ITU_fixed_16(png_ptr, green_x, "png_set_mDCV(green(x))");
-   gy = png_ITU_fixed_16(png_ptr, green_y, "png_set_mDCV(green(y))");
-   bx = png_ITU_fixed_16(png_ptr, blue_x, "png_set_mDCV(blue(x))");
-   by = png_ITU_fixed_16(png_ptr, blue_y, "png_set_mDCV(blue(y))");
-   wx = png_ITU_fixed_16(png_ptr, white_x, "png_set_mDCV(white(x))");
-   wy = png_ITU_fixed_16(png_ptr, white_y, "png_set_mDCV(white(y))");
+   error = 0;
+   rx = png_ITU_fixed_16(&error, red_x);
+   ry = png_ITU_fixed_16(&error, red_y);
+   gx = png_ITU_fixed_16(&error, green_x);
+   gy = png_ITU_fixed_16(&error, green_y);
+   bx = png_ITU_fixed_16(&error, blue_x);
+   by = png_ITU_fixed_16(&error, blue_y);
+   wx = png_ITU_fixed_16(&error, white_x);
+   wy = png_ITU_fixed_16(&error, white_y);
 
+   if (error)
+   {
+      png_chunk_report(png_ptr,
+         "mDCV chromaticities outside representable range",
+         PNG_CHUNK_WRITE_ERROR);
+      return;
+   }
+
    /* Check the light level range: */
    if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU)
    {
@@ -362,8 +368,8 @@
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
-   png_colorspace_sync_info(png_ptr, info_ptr);
+   info_ptr->gamma = file_gamma;
+   info_ptr->valid |= PNG_INFO_gAMA;
 }
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -822,8 +828,8 @@
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
-   png_colorspace_sync_info(png_ptr, info_ptr);
+   info_ptr->rendering_intent = srgb_intent;
+   info_ptr->valid |= PNG_INFO_sRGB;
 }
 
 void PNGAPI
@@ -835,15 +841,20 @@
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,
-       srgb_intent) != 0)
-   {
-      /* This causes the gAMA and cHRM to be written too */
-      info_ptr->colorspace.flags |=
-         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
-   }
+   png_set_sRGB(png_ptr, info_ptr, srgb_intent);
 
-   png_colorspace_sync_info(png_ptr, info_ptr);
+#  ifdef PNG_gAMA_SUPPORTED
+      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
+#  endif /* gAMA */
+
+#  ifdef PNG_cHRM_SUPPORTED
+      png_set_cHRM_fixed(png_ptr, info_ptr,
+         /* color      x       y */
+         /* white */ 31270, 32900,
+         /* red   */ 64000, 33000,
+         /* green */ 30000, 60000,
+         /* blue  */ 15000,  6000);
+#  endif /* cHRM */
 }
 #endif /* sRGB */
 
@@ -866,27 +877,6 @@
    if (compression_type != PNG_COMPRESSION_TYPE_BASE)
       png_app_error(png_ptr, "Invalid iCCP compression method");
 
-   /* Set the colorspace first because this validates the profile; do not
-    * override previously set app cHRM or gAMA here (because likely as not the
-    * application knows better than libpng what the correct values are.)  Pass
-    * the info_ptr color_type field to png_colorspace_set_ICC because in the
-    * write case it has not yet been stored in png_ptr.
-    */
-   {
-      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
-          proflen, profile, info_ptr->color_type);
-
-      png_colorspace_sync_info(png_ptr, info_ptr);
-
-      /* Don't do any of the copying if the profile was bad, or inconsistent. */
-      if (result == 0)
-         return;
-
-      /* But do write the gAMA and cHRM chunks from the profile. */
-      info_ptr->colorspace.flags |=
-         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
-   }
-
    length = strlen(name)+1;
    new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
 
@@ -1841,8 +1831,24 @@
 {
    png_debug(1, "in png_set_chunk_malloc_max");
 
+   /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in
+    * png.c.  This API supports '0' for unlimited, make sure the correct
+    * (unlimited) value is set here to avoid a need to check for 0 everywhere
+    * the parameter is used.
+    */
    if (png_ptr != NULL)
-      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
+   {
+      if (user_chunk_malloc_max == 0U) /* unlimited */
+      {
+#        ifdef PNG_MAX_MALLOC_64K
+            png_ptr->user_chunk_malloc_max = 65536U;
+#        else
+            png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX;
+#        endif
+      }
+      else
+         png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
+   }
 }
 #endif /* ?SET_USER_LIMITS */
 

Modified: trunk/Build/source/libs/libpng/libpng-src/pngstruct.h
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngstruct.h	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngstruct.h	2025-03-08 21:56:41 UTC (rev 74539)
@@ -69,13 +69,7 @@
 
 /* Colorspace support; structures used in png_struct, png_info and in internal
  * functions to hold and communicate information about the color space.
- *
- * PNG_COLORSPACE_SUPPORTED is only required if the application will perform
- * colorspace corrections, otherwise all the colorspace information can be
- * skipped and the size of libpng can be reduced (significantly) by compiling
- * out the colorspace support.
  */
-#ifdef PNG_COLORSPACE_SUPPORTED
 /* The chromaticities of the red, green and blue colorants and the chromaticity
  * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)).
  */
@@ -96,49 +90,37 @@
    png_fixed_point green_X, green_Y, green_Z;
    png_fixed_point blue_X, blue_Y, blue_Z;
 } png_XYZ;
-#endif /* COLORSPACE */
 
-#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
-/* A colorspace is all the above plus, potentially, profile information;
- * however at present libpng does not use the profile internally so it is only
- * stored in the png_info struct (if iCCP is supported.)  The rendering intent
- * is retained here and is checked.
- *
- * The file gamma encoding information is also stored here and gamma correction
- * is done by libpng, whereas color correction must currently be done by the
- * application.
+/* Chunk index values as an enum, PNG_INDEX_unknown is also a count of the
+ * number of chunks.
  */
-typedef struct png_colorspace
+#define PNG_CHUNK(cHNK, i) PNG_INDEX_ ## cHNK = (i),
+typedef enum
 {
-#ifdef PNG_GAMMA_SUPPORTED
-   png_fixed_point gamma;        /* File gamma */
-#endif
+   PNG_KNOWN_CHUNKS
+   PNG_INDEX_unknown
+} png_index;
+#undef PNG_CHUNK
 
-#ifdef PNG_COLORSPACE_SUPPORTED
-   png_xy      end_points_xy;    /* End points as chromaticities */
-   png_XYZ     end_points_XYZ;   /* End points as CIE XYZ colorant values */
-   png_uint_16 rendering_intent; /* Rendering intent of a profile */
-#endif
+/* Chunk flag values.  These are (png_uint_32 values) with exactly one bit set
+ * and can be combined into a flag set with bitwise 'or'.
+ *
+ * TODO: C23: convert these macros to C23 inlines (which are static).
+ */
+#define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i)))
+   /* The flag coresponding to the given png_index enum value.  This is defined
+    * for png_unknown as well (until it reaches the value 32) but this should
+    * not be relied on.
+    */
 
-   /* Flags are always defined to simplify the code. */
-   png_uint_16 flags;            /* As defined below */
-} png_colorspace, * PNG_RESTRICT png_colorspacerp;
+#define png_file_has_chunk(png_ptr, i)\
+   (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0)
+   /* The chunk has been recorded in png_struct */
 
-typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
+#define png_file_add_chunk(pnt_ptr, i)\
+   ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i)))
+   /* Record the chunk in the png_struct */
 
-/* General flags for the 'flags' field */
-#define PNG_COLORSPACE_HAVE_GAMMA           0x0001
-#define PNG_COLORSPACE_HAVE_ENDPOINTS       0x0002
-#define PNG_COLORSPACE_HAVE_INTENT          0x0004
-#define PNG_COLORSPACE_FROM_gAMA            0x0008
-#define PNG_COLORSPACE_FROM_cHRM            0x0010
-#define PNG_COLORSPACE_FROM_sRGB            0x0020
-#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040
-#define PNG_COLORSPACE_MATCHES_sRGB         0x0080 /* exact match on profile */
-#define PNG_COLORSPACE_INVALID              0x8000
-#define PNG_COLORSPACE_CANCEL(flags)        (0xffff ^ (flags))
-#endif /* COLORSPACE || GAMMA */
-
 struct png_struct_def
 {
 #ifdef PNG_SETJMP_SUPPORTED
@@ -209,6 +191,11 @@
    int zlib_set_strategy;
 #endif
 
+   png_uint_32 chunks; /* PNG_CF_ for every chunk read or (NYI) written */
+#  define png_has_chunk(png_ptr, cHNK)\
+      png_file_has_chunk(png_ptr, PNG_INDEX_ ## cHNK)
+      /* Convenience accessor - use this to check for a known chunk by name */
+
    png_uint_32 width;         /* width of image in pixels */
    png_uint_32 height;        /* height of image in pixels */
    png_uint_32 num_rows;      /* number of rows in current pass */
@@ -285,9 +272,16 @@
    png_uint_32 flush_rows;    /* number of rows written since last flush */
 #endif
 
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+   png_xy          chromaticities; /* From mDVC, cICP, [iCCP], sRGB or cHRM */
+#endif
+
 #ifdef PNG_READ_GAMMA_SUPPORTED
    int gamma_shift;      /* number of "insignificant" bits in 16-bit gamma */
-   png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */
+   png_fixed_point screen_gamma; /* screen gamma value (display exponent) */
+   png_fixed_point file_gamma;   /* file gamma value (encoding exponent) */
+   png_fixed_point chunk_gamma;  /* from cICP, iCCP, sRGB or gAMA */
+   png_fixed_point default_gamma;/* from png_set_alpha_mode */
 
    png_bytep gamma_table;     /* gamma table for 8-bit depth files */
    png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
@@ -299,7 +293,7 @@
    png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
    png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
 #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
-#endif
+#endif /* READ_GAMMA */
 
 #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
    png_color_8 sig_bit;       /* significant bits in each available channel */
@@ -349,8 +343,8 @@
 /* To do: remove this from libpng-1.7 */
 #ifdef PNG_TIME_RFC1123_SUPPORTED
    char time_buffer[29]; /* String to hold RFC 1123 time text */
-#endif
-#endif
+#endif /* TIME_RFC1123 */
+#endif /* LIBPNG_VER < 10700 */
 
 /* New members added in libpng-1.0.6 */
 
@@ -360,8 +354,8 @@
    png_voidp user_chunk_ptr;
 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
    png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
-#endif
-#endif
+#endif /* READ_USER_CHUNKS */
+#endif /* USER_CHUNKS */
 
 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
    int          unknown_default; /* As PNG_HANDLE_* */
@@ -468,11 +462,5 @@
 /* New member added in libpng-1.5.7 */
    void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
       png_bytep row, png_const_bytep prev_row);
-
-#ifdef PNG_READ_SUPPORTED
-#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
-   png_colorspace   colorspace;
-#endif
-#endif
 };
 #endif /* PNGSTRUCT_H */

Modified: trunk/Build/source/libs/libpng/libpng-src/pngtest.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngtest.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngtest.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -50,7 +50,7 @@
 #define STDERR stdout
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_46 Your_png_h_is_not_version_1_6_46;
+typedef png_libpng_version_1_6_47 Your_png_h_is_not_version_1_6_47;
 
 /* Ensure that all version numbers in png.h are consistent with one another. */
 #if (PNG_LIBPNG_VER != PNG_LIBPNG_VER_MAJOR * 10000 + \
@@ -2137,6 +2137,7 @@
       fprintf(STDERR, " libpng FAILS test\n");
 
    dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+#ifdef PNG_USER_LIMITS_SUPPORTED
    fprintf(STDERR, " Default limits:\n");
    fprintf(STDERR, "  width_max  = %lu\n",
        (unsigned long) png_get_user_width_max(dummy_ptr));
@@ -2152,6 +2153,7 @@
    else
       fprintf(STDERR, "  malloc_max = %lu\n",
           (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
+#endif
    png_destroy_read_struct(&dummy_ptr, NULL, NULL);
 
    return (ierror != 0);

Modified: trunk/Build/source/libs/libpng/libpng-src/pngwrite.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngwrite.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngwrite.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -181,7 +181,6 @@
    }
 #endif
 
-#ifdef PNG_COLORSPACE_SUPPORTED
 #  ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */
    if ((info_ptr->valid & PNG_INFO_cICP) != 0)
       {
@@ -193,50 +192,28 @@
       }
 #  endif
 
-      /* PNG v3 change: it is now permitted to write both sRGB and ICC profiles,
-       * however because the libpng code auto-generates an sRGB for the
-       * corresponding ICC profiles and because PNG v2 disallowed this we need
-       * to only write one.
-       *
-       * Remove the PNG v2 warning about writing an sRGB ICC profile as well
-       * because it's invalid with PNG v3.
-       */
 #  ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */
-         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
-             (info_ptr->valid & PNG_INFO_iCCP) != 0)
+         if ((info_ptr->valid & PNG_INFO_iCCP) != 0)
          {
             png_write_iCCP(png_ptr, info_ptr->iccp_name,
-                info_ptr->iccp_profile);
+                info_ptr->iccp_profile, info_ptr->iccp_proflen);
          }
-#     ifdef PNG_WRITE_sRGB_SUPPORTED
-         else
-#     endif
 #  endif
 
 #  ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */
-         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
-             (info_ptr->valid & PNG_INFO_sRGB) != 0)
-            png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
+         if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
+            png_write_sRGB(png_ptr, info_ptr->rendering_intent);
 #  endif /* WRITE_sRGB */
-#endif /* COLORSPACE */
 
-#ifdef PNG_GAMMA_SUPPORTED
 #  ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */
-      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
-          (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
-          (info_ptr->valid & PNG_INFO_gAMA) != 0)
-         png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
+      if ((info_ptr->valid & PNG_INFO_gAMA) != 0)
+         png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
 #  endif
-#endif
 
-#ifdef PNG_COLORSPACE_SUPPORTED
 #  ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */
-         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
-             (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&
-             (info_ptr->valid & PNG_INFO_cHRM) != 0)
-            png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);
+         if ((info_ptr->valid & PNG_INFO_cHRM) != 0)
+            png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM);
 #  endif
-#endif
 
       png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
    }

Modified: trunk/Build/source/libs/libpng/libpng-src/pngwutil.c
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/pngwutil.c	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/pngwutil.c	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1132,10 +1132,9 @@
 /* Write an iCCP chunk */
 void /* PRIVATE */
 png_write_iCCP(png_structrp png_ptr, png_const_charp name,
-    png_const_bytep profile)
+    png_const_bytep profile, png_uint_32 profile_len)
 {
    png_uint_32 name_len;
-   png_uint_32 profile_len;
    png_byte new_name[81]; /* 1 byte for the compression byte */
    compression_state comp;
    png_uint_32 temp;
@@ -1148,11 +1147,12 @@
    if (profile == NULL)
       png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
 
-   profile_len = png_get_uint_32(profile);
-
    if (profile_len < 132)
       png_error(png_ptr, "ICC profile too short");
 
+   if (png_get_uint_32(profile) != profile_len)
+      png_error(png_ptr, "Incorrect data in iCCP");
+
    temp = (png_uint_32) (*(profile+8));
    if (temp > 3 && (profile_len & 0x03))
       png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");

Modified: trunk/Build/source/libs/libpng/libpng-src/scripts/libpng-config-head.in
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/scripts/libpng-config-head.in	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/scripts/libpng-config-head.in	2025-03-08 21:56:41 UTC (rev 74539)
@@ -11,7 +11,7 @@
 
 # Modeled after libxml-config.
 
-version=1.6.46
+version=1.6.47
 prefix=""
 libdir=""
 libs=""

Modified: trunk/Build/source/libs/libpng/libpng-src/scripts/libpng.pc.in
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/scripts/libpng.pc.in	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/scripts/libpng.pc.in	2025-03-08 21:56:41 UTC (rev 74539)
@@ -5,6 +5,6 @@
 
 Name: libpng
 Description: Loads and saves PNG files
-Version: 1.6.46
+Version: 1.6.47
 Libs: -L${libdir} -lpng16
 Cflags: -I${includedir}

Modified: trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.dfa
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.dfa	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.dfa	2025-03-08 21:56:41 UTC (rev 74539)
@@ -711,7 +711,7 @@
 # processing, it just validates the data in the PNG file.
 
 option GAMMA disabled
-option COLORSPACE enables GAMMA disabled
+option COLORSPACE disabled
 
 # When an ICC profile is read, or png_set, it will be checked for a match
 # against known sRGB profiles if the sRGB handling is enabled.  The
@@ -851,9 +851,9 @@
 chunk eXIf
 chunk gAMA enables GAMMA
 chunk hIST
-chunk iCCP enables COLORSPACE, GAMMA
+chunk iCCP enables GAMMA
 chunk iTXt enables TEXT
-chunk mDCV
+chunk mDCV enables COLORSPACE
 chunk oFFs
 chunk pCAL
 chunk pHYs
@@ -860,7 +860,7 @@
 chunk sBIT
 chunk sCAL
 chunk sPLT
-chunk sRGB enables COLORSPACE, GAMMA, SET_OPTION
+chunk sRGB enables GAMMA, SET_OPTION
 chunk tEXt requires TEXT
 chunk tIME
 chunk tRNS
@@ -995,7 +995,8 @@
       READ_EXPAND, READ_16BIT, READ_EXPAND_16, READ_SCALE_16_TO_8,
       READ_RGB_TO_GRAY, READ_ALPHA_MODE, READ_BACKGROUND, READ_STRIP_ALPHA,
       READ_FILLER, READ_SWAP, READ_PACK, READ_GRAY_TO_RGB, READ_GAMMA,
-      READ_tRNS, READ_bKGD, READ_gAMA, READ_cHRM, READ_sRGB, READ_sBIT
+      READ_tRNS, READ_bKGD, READ_gAMA, READ_cHRM, READ_sRGB, READ_mDCV,
+      READ_cICP, READ_sBIT
 
 # AFIRST and BGR read options:
 #  Prior to libpng 1.6.8 these were disabled but switched on if the low level

Modified: trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.h.prebuilt
===================================================================
--- trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.h.prebuilt	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/libpng-src/scripts/pnglibconf.h.prebuilt	2025-03-08 21:56:41 UTC (rev 74539)
@@ -1,6 +1,6 @@
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.6.46 */
+/* libpng version 1.6.47 */
 
 /* Copyright (c) 2018-2025 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */

Modified: trunk/Build/source/libs/libpng/version.ac
===================================================================
--- trunk/Build/source/libs/libpng/version.ac	2025-03-08 21:35:20 UTC (rev 74538)
+++ trunk/Build/source/libs/libpng/version.ac	2025-03-08 21:56:41 UTC (rev 74539)
@@ -8,4 +8,4 @@
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current libpng version
-m4_define([libpng_version], [1.6.46])
+m4_define([libpng_version], [1.6.47])



More information about the tex-live-commits mailing list.