[master] 27e02a1 - Update bundled libpng to version 1.6.50 dated 2025-07-01
"ManoloFLTK"
09:17 Sep 07
commit 27e02a1541db180e3d4260732461a080dab593a1
Author: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
AuthorDate: Sun Sep 7 18:06:14 2025 +0200
Commit: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
CommitDate: Sun Sep 7 18:06:39 2025 +0200
Update bundled libpng to version 1.6.50 dated 2025-07-01
documentation/src/bundled-libs.dox | 4 +-
png/ANNOUNCE | 41 +-
png/CHANGES | 60 ++
png/INSTALL | 11 +-
png/LICENSE | 4 +-
png/README | 6 +-
png/TODO | 43 +-
png/arm/arm_init.c | 9 +-
png/arm/filter_neon_intrinsics.c | 1 -
png/arm/palette_neon_intrinsics.c | 3 +-
png/libpng-manual.txt | 26 +-
png/libpng.3 | 32 +-
png/libpngpf.3 | 21 +-
png/png.5 | 35 +-
png/png.c | 1375 ++++++++-----------------
png/png.h | 175 +++-
png/pngconf.h | 50 +-
png/pngdebug.h | 9 +-
png/pngerror.c | 29 +-
png/pngget.c | 311 ++++--
png/pnginfo.h | 104 +-
png/pnglibconf.h | 191 ++--
png/pngmem.c | 40 +-
png/pngpread.c | 215 +---
png/pngprefix.h | 51 +-
png/pngpriv.h | 513 +++++-----
png/pngread.c | 364 +++----
png/pngrio.c | 5 +-
png/pngrtran.c | 346 ++++---
png/pngrutil.c | 1873 ++++++++++++++++++-----------------
png/pngset.c | 293 +++++-
png/pngstruct.h | 112 +--
png/pngtrans.c | 1 -
png/pngwio.c | 9 +-
png/pngwrite.c | 125 ++-
png/pngwtran.c | 1 -
png/pngwutil.c | 136 ++-
png/powerpc/filter_vsx_intrinsics.c | 2 +-
png/powerpc/powerpc_init.c | 3 +-
39 files changed, 3238 insertions(+), 3391 deletions(-)
diff --git documentation/src/bundled-libs.dox documentation/src/bundled-libs.dox
index fdc6ea0..610203f 100644
--- documentation/src/bundled-libs.dox
+++ documentation/src/bundled-libs.dox
@@ -23,12 +23,12 @@ The nanosvg library is not affected.
\section bundled-status Current status
\code
-Current versions of bundled libraries (as of May 21, 2025):
+Current versions of bundled libraries (as of Sept 7, 2025):
Library Version/git commit Release date FLTK Version
--------------------------------------------------------------------------
jpeg jpeg-9f 2024-01-14 1.4.0
nanosvg 7aeda550a8 [1] 2023-12-02 1.4.0
- png libpng-1.6.44 2024-09-12 1.4.1
+ png libpng-1.6.50 2025-07-01 1.5.0
zlib zlib-1.3.1 2024-01-22 1.4.0
libdecor 42f7a53a [2] 2025-05-14 1.5.0
--------------------------------------------------------------------------
diff --git png/ANNOUNCE png/ANNOUNCE
index a2a7ac3..516e078 100644
--- png/ANNOUNCE
+++ png/ANNOUNCE
@@ -1,5 +1,5 @@
-libpng 1.6.44 - September 12, 2024
-==================================
+libpng 1.6.50 - July 1, 2025
+============================
This is a public release of libpng, intended for use in production code.
@@ -9,13 +9,13 @@ Files available for download
Source files with LF line endings (for Unix/Linux):
- * libpng-1.6.44.tar.xz (LZMA-compressed, recommended)
- * libpng-1.6.44.tar.gz (deflate-compressed)
+ * libpng-1.6.50.tar.xz (LZMA-compressed, recommended)
+ * libpng-1.6.50.tar.gz (deflate-compressed)
Source files with CRLF line endings (for Windows):
- * lpng1644.7z (LZMA-compressed, recommended)
- * lpng1644.zip (deflate-compressed)
+ * lpng1650.7z (LZMA-compressed, recommended)
+ * lpng1650.zip (deflate-compressed)
Other information:
@@ -25,29 +25,18 @@ Other information:
* TRADEMARK.md
-Changes from version 1.6.43 to version 1.6.44
+Changes from version 1.6.49 to version 1.6.50
---------------------------------------------
- * Hardened calculations in chroma handling to prevent overflows, and
- relaxed a constraint in cHRM validation to accomodate the standard
- ACES AP1 set of color primaries.
+ * Improved the detection of the RVV Extension on the RISC-V platform.
+ (Contributed by Filip Wasil)
+ * Replaced inline ASM with C intrinsics in the RVV code.
+ (Contributed by Filip Wasil)
+ * Fixed a decoder defect in which unknown chunks trailing IDAT, set
+ to go through the unknown chunk handler, incorrectly triggered
+ out-of-place IEND errors.
(Contributed by John Bowler)
- * Removed the ASM implementation of ARM Neon optimizations and updated
- the build accordingly. Only the remaining C implementation shall be
- used from now on, thus ensuring the support of the PAC/BTI security
- features on ARM64.
- (Contributed by Ross Burton and John Bowler)
- * Fixed the pickup of the PNG_HARDWARE_OPTIMIZATIONS option in the
- CMake build on FreeBSD/amd64. This is an important performance fix
- on this platform.
- * Applied various fixes and improvements to the CMake build.
- (Contributed by Eric Riff, Benjamin Buch and Erik Scholz)
- * Added fuzzing targets for the simplified read API.
- (Contributed by Mikhail Khachayants)
- * Fixed a build error involving pngtest.c under a custom config.
- This was a regression introduced in a code cleanup in libpng-1.6.43.
- (Contributed by Ben Wagner)
- * Fixed and improved the config files for AppVeyor CI and Travis CI.
+ * Fixed the CMake file for cross-platform builds that require `libm`.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
diff --git png/CHANGES png/CHANGES
index 724ccca..b6499b1 100644
--- png/CHANGES
+++ png/CHANGES
@@ -6218,6 +6218,66 @@ Version 1.6.44 [September 12, 2024]
(Contributed by Ben Wagner)
Fixed and improved the config files for AppVeyor CI and Travis CI.
+Version 1.6.45 [January 7, 2025]
+ Added support for the cICP chunk.
+ (Contributed by Lucas Chollet and John Bowler)
+ Adjusted and improved various checks in colorspace calculations.
+ (Contributed by John Bowler)
+ Rearranged the write order of colorspace chunks for better conformance
+ with the PNG v3 draft specification.
+ (Contributed by John Bowler)
+ Raised the minimum required CMake version from 3.6 to 3.14.
+ Forked off a development branch for libpng version 1.8.
+
+Version 1.6.46 [January 23, 2025]
+ Added support for the mDCV and cLLI chunks.
+ (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.
+
+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)
+
+Version 1.6.48 [April 30, 2025]
+ Fixed the floating-point version of the mDCv setter `png_set_mDCv`.
+ (Reported by Mohit Bakshi; fixed by John Bowler)
+ Added #error directives to discourage the inclusion of private
+ libpng implementation header files in PNG-supporting applications.
+ Added the CMake build option `PNG_LIBCONF_HEADER`, to be used as an
+ alternative to `DFA_XTRA`.
+ Removed the Travis CI configuration files, with heartfelt thanks for
+ their generous support of our project over the past five years!
+
+Version 1.6.49 [June 12, 2025]
+ Added SIMD-optimized code for the RISC-V Vector Extension (RVV).
+ (Contributed by Manfred Schlaegl, Dragos Tiselice and Filip Wasil)
+ Added various fixes and improvements to the build scripts and to
+ the sample code.
+
+Version 1.6.50 [July 1, 2025]
+ Improved the detection of the RVV Extension on the RISC-V platform.
+ (Contributed by Filip Wasil)
+ Replaced inline ASM with C intrinsics in the RVV code.
+ (Contributed by Filip Wasil)
+ Fixed a decoder defect in which unknown chunks trailing IDAT, set
+ to go through the unknown chunk handler, incorrectly triggered
+ out-of-place IEND errors.
+ (Contributed by John Bowler)
+ Fixed the CMake file for cross-platform builds that require `libm`.
+
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
diff --git png/INSTALL png/INSTALL
index 042d729..1557fbd 100644
--- png/INSTALL
+++ png/INSTALL
@@ -1,4 +1,3 @@
-
Installing libpng
Contents
@@ -137,7 +136,7 @@ Your directory structure should look like this:
depcomp, install-sh, mkinstalldirs, test-pngtest.sh, etc.
contrib
arm-neon, conftest, examples, gregbook, libtests, pngminim,
- pngminus, pngsuite, tools, visupng
+ pngminus, pngsuite, tools, visupng, riscv-rvv
projects
owatcom, visualc71, vstudio
scripts
@@ -290,6 +289,7 @@ such as one of
--enable-mips-msa=yes
--enable-intel-sse=yes
--enable-powerpc-vsx=yes
+ --enable-riscv-rvv=yes
or enable them all at once with
@@ -302,6 +302,7 @@ or more of
CPPFLAGS += "-DPNG_MIPS_MSA"
CPPFLAGS += "-DPNG_INTEL_SSE"
CPPFLAGS += "-DPNG_POWERPC_VSX"
+ CPPFLAGS += "-DPNG_RISCV_RVV"
See for example scripts/makefile.linux-opt
@@ -318,13 +319,15 @@ to disable a particular one,
or via compiler-command options such as
CPPFLAGS += "-DPNG_ARM_NEON_OPT=0, -DPNG_MIPS_MSA_OPT=0,
- -DPNG_INTEL_SSE_OPT=0, -DPNG_POWERPC_VSX_OPT=0"
+ -DPNG_INTEL_SSE_OPT=0, -DPNG_POWERPC_VSX_OPT=0,
+ -DPNG_RISCV_RVV_OPT=0"
If you are using cmake, hardware optimizations are "on"
by default. To disable them, use
cmake . -DPNG_ARM_NEON=no -DPNG_INTEL_SSE=no \
- -DPNG_MIPS_MSA=no -DPNG_POWERPC_VSX=no
+ -DPNG_MIPS_MSA=no -DPNG_POWERPC_VSX=no \
+ -DPNG_RISCV_RVV=no
or disable them all at once with
diff --git png/LICENSE png/LICENSE
index 25f298f..ea6df98 100644
--- png/LICENSE
+++ png/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
PNG Reference Library License version 2
---------------------------------------
- * Copyright (c) 1995-2024 The PNG Reference Library Authors.
- * Copyright (c) 2018-2024 Cosmin Truta.
+ * Copyright (c) 1995-2025 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2025 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git png/README png/README
index 3af6068..2eb633a 100644
--- png/README
+++ png/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.44
+README for libpng version 1.6.50
================================
See the note about version numbers near the top of `png.h`.
@@ -147,6 +147,7 @@ Files included in this distribution
loongarch/ => Optimized code for LoongArch LSX
mips/ => Optimized code for MIPS MSA and MIPS MMI
powerpc/ => Optimized code for PowerPC VSX
+ riscv/ => Optimized code for the RISC-V platform
ci/ => Scripts for continuous integration
contrib/ => External contributions
arm-neon/ => Optimized code for the ARM-NEON platform
@@ -157,13 +158,12 @@ Files included in this distribution
"PNG: The Definitive Guide" by Greg Roelofs,
O'Reilly, 1999
libtests/ => Test programs
- oss-fuzz/ => Files used by the OSS-Fuzz project for fuzz-testing
- libpng
pngexif/ => Program to inspect the EXIF information in PNG files
pngminim/ => Minimal decoder, encoder, and progressive decoder
programs demonstrating the use of pngusr.dfa
pngminus/ => Simple pnm2png and png2pnm programs
pngsuite/ => Test images
+ riscv-rvv/ => Optimized code for the RISC-V Vector platform
testpngs/ => Test images
tools/ => Various tools
visupng/ => VisualPng, a Windows viewer for PNG images
diff --git png/TODO png/TODO
index 562dab0..8ddb7d1 100644
--- png/TODO
+++ png/TODO
@@ -1,23 +1,22 @@
-TODO - list of things to do for libpng:
+TODO list for libpng
+--------------------
-* Fix all defects (duh!)
-* Better C++ wrapper / full C++ implementation (?)
-* Fix the problems with C++ and 'extern "C"'.
-* cHRM transformation.
-* Palette creation.
-* "grayscale->palette" transformation and "palette->grayscale" detection.
-* Improved dithering.
-* Multi-lingual error and warning message support.
-* Complete sRGB transformation. (Currently it simply uses gamma=0.45455.)
-* Man pages for function calls.
-* Better documentation.
-* Better filter selection
- (e.g., counting huffman bits/precompression; filter inertia; filter costs).
-* Histogram creation.
-* Text conversion between different code pages (e.g., Latin-1 -> Mac).
-* Avoid building gamma tables whenever possible.
-* Greater precision in changing to linear gamma for compositing against
- background, and in doing rgb-to-gray transformations.
-* Investigate pre-incremented loop counters and other loop constructions.
-* Interpolated method of handling interlacing.
-* More validations for libpng transformations.
+ * Fix all defects (duh!)
+ * cHRM transformation.
+ * Palette creation.
+ * "grayscale->palette" transformation and "palette->grayscale" detection.
+ * Improved dithering.
+ * Multi-lingual error and warning message support.
+ * Complete sRGB transformation. (Currently it simply uses gamma=0.45455.)
+ * Man pages for function calls.
+ * Better documentation.
+ * Better filter selection
+ (e.g., counting huffman bits/precompression; filter inertia; filter costs).
+ * Histogram creation.
+ * Text conversion between different code pages (e.g., Latin-1 to Mac).
+ * Avoid building gamma tables whenever possible.
+ * Greater precision in changing to linear gamma for compositing against
+ background, and in doing rgb-to-gray transformations.
+ * Investigate pre-incremented loop counters and other loop constructions.
+ * Interpolated method of handling interlacing.
+ * More validations for libpng transformations.
diff --git png/arm/arm_init.c png/arm/arm_init.c
index 84d0555..0ea9c83 100644
--- png/arm/arm_init.c
+++ png/arm/arm_init.c
@@ -1,4 +1,3 @@
-
/* arm_init.c - NEON optimised filter functions
*
* Copyright (c) 2018-2022 Cosmin Truta
@@ -36,14 +35,14 @@
#ifndef PNG_ARM_NEON_FILE
# if defined(__aarch64__) || defined(_M_ARM64)
/* ARM Neon is expected to be unconditionally available on ARM64. */
-# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64"
+# error PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64
# elif defined(__ARM_NEON__) || defined(__ARM_NEON)
/* ARM Neon is expected to be available on the target CPU architecture. */
-# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch"
+# error PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch
# elif defined(__linux__)
# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
# else
-# error "No support for run-time ARM Neon checking; use compile-time options"
+# error No support for run-time ARM Neon checking; use compile-time options
# endif
#endif
@@ -54,7 +53,7 @@ static int png_have_neon(png_structp png_ptr);
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
-# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
+# error ALIGNED_MEMORY is required; please define PNG_ALIGNED_MEMORY_SUPPORTED
#endif
void
diff --git png/arm/filter_neon_intrinsics.c png/arm/filter_neon_intrinsics.c
index 4466d48..7c3e0da 100644
--- png/arm/filter_neon_intrinsics.c
+++ png/arm/filter_neon_intrinsics.c
@@ -1,4 +1,3 @@
-
/* filter_neon_intrinsics.c - NEON optimised filter functions
*
* Copyright (c) 2018 Cosmin Truta
diff --git png/arm/palette_neon_intrinsics.c png/arm/palette_neon_intrinsics.c
index 92c7d6f..3068e9b 100644
--- png/arm/palette_neon_intrinsics.c
+++ png/arm/palette_neon_intrinsics.c
@@ -1,4 +1,3 @@
-
/* palette_neon_intrinsics.c - NEON optimised palette expansion functions
*
* Copyright (c) 2018-2019 Cosmin Truta
@@ -64,7 +63,7 @@ png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info,
{
png_uint_32 row_width = row_info->width;
const png_uint_32 *riffled_palette =
- (const png_uint_32 *)png_ptr->riffled_palette;
+ png_aligncastconst(png_const_uint_32p, png_ptr->riffled_palette);
const png_uint_32 pixels_per_chunk = 4;
png_uint_32 i;
diff --git png/libpng-manual.txt png/libpng-manual.txt
index 2ce366d..6c07e10 100644
--- png/libpng-manual.txt
+++ png/libpng-manual.txt
@@ -1,6 +1,6 @@
libpng-manual.txt - A description on how to use and modify libpng
- Copyright (c) 2018-2024 Cosmin Truta
+ Copyright (c) 2018-2025 Cosmin Truta
Copyright (c) 1998-2018 Glenn Randers-Pehrson
This document is released under the libpng license.
@@ -9,9 +9,9 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng version 1.6.36, December 2018, through 1.6.44 - September 2024
+ libpng version 1.6.36, December 2018, through 1.6.50 - July 2025
Updated and distributed by Cosmin Truta
- Copyright (c) 2018-2024 Cosmin Truta
+ Copyright (c) 2018-2025 Cosmin Truta
libpng versions 0.97, January 1998, through 1.6.35 - July 2018
Updated and distributed by Glenn Randers-Pehrson
@@ -65,18 +65,22 @@ Libpng was written as a companion to the PNG specification, as a way
of reducing the amount of time and effort it takes to support the PNG
file format in application programs.
-The PNG specification (second edition), November 2003, is available as
+The PNG specification (Third Edition), June 2025, is available as
+a W3C Recommendation at
+<https://www.w3.org/TR/2025/REC-png-3-20250624/>.
+
+The PNG specification (Second Edition), November 2003, is available as
a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at
<https://www.w3.org/TR/2003/REC-PNG-20031110/>.
The W3C and ISO documents have identical technical content.
The PNG-1.2 specification is available at
-<https://png-mng.sourceforge.io/pub/png/spec/1.2/>.
-It is technically equivalent
-to the PNG specification (second edition) but has some additional material.
+<https://www.libpng.org/pub/png/spec/1.2/>.
+It is technically equivalent to the PNG specification (Second Edition)
+but has some additional material.
The PNG-1.0 specification is available as RFC 2083 at
-<https://png-mng.sourceforge.io/pub/png/spec/1.0/> and as a
+<https://www.libpng.org/pub/png/spec/1.0/> and as a
W3C Recommendation at <https://www.w3.org/TR/REC-png-961001>.
Some additional chunks are described in the special-purpose public chunks
@@ -4089,7 +4093,7 @@ READ APIs
is filled in from the PNG header in the file.
int png_image_begin_read_from_stdio (png_imagep image,
- FILE* file)
+ FILE *file)
The PNG header is read from the stdio FILE object.
@@ -4164,7 +4168,7 @@ be written:
int convert_to_8_bit, const void *buffer,
png_int_32 row_stride, const void *colormap)
- Write the image to the given (FILE*).
+ Write the image to the given FILE object.
With all write APIs if image is in one of the linear formats with
(png_uint_16) data then setting convert_to_8_bit will cause the output to be
@@ -5173,7 +5177,7 @@ a pre-existing bug where the per-chunk 'keep' setting is ignored, and makes
it possible to skip IDAT chunks in the sequential reader.
The machine-generated configure files are no longer included in branches
-libpng16 and later of the GIT repository. They continue to be included
+libpng17 and later of the GIT repository. They continue to be included
in the tarball releases, however.
Libpng-1.6.0 through 1.6.2 used the CMF bytes at the beginning of the IDAT
diff --git png/libpng.3 png/libpng.3
index 5a3c89c..8980a25 100644
--- png/libpng.3
+++ png/libpng.3
@@ -1,6 +1,6 @@
-.TH LIBPNG 3 "September 12, 2024"
+.TH LIBPNG 3 "July 1, 2025"
.SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.44
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.50
.SH SYNOPSIS
\fB#include <png.h>\fP
@@ -223,7 +223,7 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.6.44
\fBint png_image_begin_read_from_file (png_imagep \fP\fIimage\fP\fB, const char \fI*file_name\fP\fB);\fP
-\fBint png_image_begin_read_from_stdio (png_imagep \fP\fIimage\fP\fB, FILE* \fIfile\fP\fB);\fP
+\fBint png_image_begin_read_from_stdio (png_imagep \fP\fIimage\fP\fB, FILE *\fIfile\fP\fB);\fP
\fBint, png_image_begin_read_from_memory (png_imagep \fP\fIimage\fP\fB, png_const_voidp \fP\fImemory\fP\fB, size_t \fIsize\fP\fB);\fP
@@ -519,7 +519,7 @@ Following is a copy of the libpng-manual.txt file that accompanies libpng.
.SH LIBPNG.TXT
libpng-manual.txt - A description on how to use and modify libpng
- Copyright (c) 2018-2024 Cosmin Truta
+ Copyright (c) 2018-2025 Cosmin Truta
Copyright (c) 1998-2018 Glenn Randers-Pehrson
This document is released under the libpng license.
@@ -528,9 +528,9 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng version 1.6.36, December 2018, through 1.6.44 - September 2024
+ libpng version 1.6.36, December 2018, through 1.6.50 - July 2025
Updated and distributed by Cosmin Truta
- Copyright (c) 2018-2024 Cosmin Truta
+ Copyright (c) 2018-2025 Cosmin Truta
libpng versions 0.97, January 1998, through 1.6.35 - July 2018
Updated and distributed by Glenn Randers-Pehrson
@@ -584,18 +584,22 @@ Libpng was written as a companion to the PNG specification, as a way
of reducing the amount of time and effort it takes to support the PNG
file format in application programs.
-The PNG specification (second edition), November 2003, is available as
+The PNG specification (Third Edition), June 2025, is available as
+a W3C Recommendation at
+<https://www.w3.org/TR/2025/REC-png-3-20250624/>.
+
+The PNG specification (Second Edition), November 2003, is available as
a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at
<https://www.w3.org/TR/2003/REC-PNG-20031110/>.
The W3C and ISO documents have identical technical content.
The PNG-1.2 specification is available at
-<https://png-mng.sourceforge.io/pub/png/spec/1.2/>.
-It is technically equivalent
-to the PNG specification (second edition) but has some additional material.
+<https://www.libpng.org/pub/png/spec/1.2/>.
+It is technically equivalent to the PNG specification (Second Edition)
+but has some additional material.
The PNG-1.0 specification is available as RFC 2083 at
-<https://png-mng.sourceforge.io/pub/png/spec/1.0/> and as a
+<https://www.libpng.org/pub/png/spec/1.0/> and as a
W3C Recommendation at <https://www.w3.org/TR/REC-png-961001>.
Some additional chunks are described in the special-purpose public chunks
@@ -4608,7 +4612,7 @@ READ APIs
is filled in from the PNG header in the file.
int png_image_begin_read_from_stdio (png_imagep image,
- FILE* file)
+ FILE *file)
The PNG header is read from the stdio FILE object.
@@ -4683,7 +4687,7 @@ be written:
int convert_to_8_bit, const void *buffer,
png_int_32 row_stride, const void *colormap)
- Write the image to the given (FILE*).
+ Write the image to the given FILE object.
With all write APIs if image is in one of the linear formats with
(png_uint_16) data then setting convert_to_8_bit will cause the output to be
@@ -5692,7 +5696,7 @@ a pre-existing bug where the per-chunk 'keep' setting is ignored, and makes
it possible to skip IDAT chunks in the sequential reader.
The machine-generated configure files are no longer included in branches
-libpng16 and later of the GIT repository. They continue to be included
+libpng17 and later of the GIT repository. They continue to be included
in the tarball releases, however.
Libpng-1.6.0 through 1.6.2 used the CMF bytes at the beginning of the IDAT
diff --git png/libpngpf.3 png/libpngpf.3
index b7557ca..e3788f1 100644
--- png/libpngpf.3
+++ png/libpngpf.3
@@ -1,24 +1,17 @@
-.TH LIBPNGPF 3 "September 12, 2024"
+.TH LIBPNGPF 3 "July 1, 2025"
.SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.44
-(private functions)
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.50
.SH SYNOPSIS
-\fB#include \fI"pngpriv.h"
-
-\fBAs of libpng version \fP\fI1.5.1\fP\fB, this section is no longer
-\fP\fImaintained\fP\fB, now that the private function prototypes are hidden in
-\fP\fIpngpriv.h\fP\fB and not accessible to applications. Look in
-\fP\fIpngpriv.h\fP\fB for the prototypes and a short description of each
-function.
+\fB#include "pngpriv.h"\fP
.SH DESCRIPTION
-The functions previously listed here are used privately by libpng and are not
-available for use by applications. They are not "exported" to applications
-using shared libraries.
+As of libpng version 1.5.1, this manual is no longer maintained. The private
+function prototypes, declared in private header files, should not be accessed
+by applications.
.SH "SEE ALSO"
-.BR "png"(5), " libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
+.BR "libpng"(3)
.SH AUTHORS
Cosmin Truta, Glenn Randers-Pehrson
diff --git png/png.5 png/png.5
index 14a3c43..c230915 100644
--- png/png.5
+++ png/png.5
@@ -1,4 +1,4 @@
-.TH PNG 5 "September 12, 2024"
+.TH PNG 5 "July 1, 2025"
.SH NAME
png \- Portable Network Graphics (PNG) format
@@ -20,15 +20,25 @@ matching on heterogeneous platforms.
.SH "SEE ALSO"
.BR "libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
.LP
+PNG Specification (Third Edition), June 2025:
+.IP
+.br
+https://www.w3.org/TR/2025/REC-png-3-20250624/
+.LP
PNG Specification (Second Edition), November 2003:
.IP
.br
https://www.w3.org/TR/2003/REC-PNG-20031110/
.LP
-PNG 1.2 Specification, July 1999:
+PNG 1.2 Specification, August 1999:
+.IP
+.br
+https://www.libpng.org/pub/png/spec/1.2/
+.LP
+PNG 1.1 Specification, December 1998:
.IP
.br
-https://png-mng.sourceforge.io/pub/png/spec/1.2/
+https://www.libpng.org/pub/png/spec/1.1/
.LP
PNG 1.0 Specification, October 1996:
.IP
@@ -45,15 +55,24 @@ https://www.w3.org/TR/REC-png-961001
.SH AUTHORS
This man page: Glenn Randers-Pehrson, Cosmin Truta
.LP
+Portable Network Graphics (PNG) Specification (Third Edition).
+W3C Recommendation 24 June 2025:
+Chris Blume et al.
+.LP
Portable Network Graphics (PNG) Specification (Second Edition)
Information technology - Computer graphics and image processing -
Portable Network Graphics (PNG): Functional specification.
-ISO/IEC 15948:2003 (E) (November 10, 2003): David Duce and others.
+ISO/IEC 15948:2003 (E), W3C Recommendation 10 November 2003:
+David Duce et al.
+.LP
+Portable Network Graphics (PNG) Specification Version 1.2 (11 August 1999):
+Glenn Randers-Pehrson et al.
.LP
-Portable Network Graphics (PNG) Specification Version 1.2 (July 8, 1999):
-Glenn Randers-Pehrson and others.
+Portable Network Graphics (PNG) Specification Version 1.1 (31 December 1998):
+Glenn Randers-Pehrson et al.
.LP
-Portable Network Graphics (PNG) Specification Version 1.0 (October 1, 1996):
-Thomas Boutell and others.
+Portable Network Graphics (PNG) Specification Version 1.0.
+IETF RFC 2083, W3C Recommendation 1 October 1996:
+Thomas Boutell et al.
.\" end of man page
diff --git png/png.c png/png.c
index 9a9fb23..6e21915 100644
--- png/png.c
+++ png/png.c
@@ -1,7 +1,6 @@
-
/* png.c - location for general purpose libpng functions
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,7 +13,34 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_44 Your_png_h_is_not_version_1_6_44;
+typedef png_libpng_version_1_6_50 Your_png_h_is_not_version_1_6_50;
+
+/* 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
@@ -242,21 +268,23 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
*/
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
@@ -598,13 +626,6 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
/* 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);
@@ -679,7 +700,7 @@ png_get_io_ptr(png_const_structrp png_ptr)
* function of your own because "FILE *" isn't necessarily available.
*/
void PNGAPI
-png_init_io(png_structrp png_ptr, png_FILE_p fp)
+png_init_io(png_structrp png_ptr, FILE *fp)
{
png_debug(1, "in png_init_io");
@@ -794,8 +815,8 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.44" PNG_STRING_NEWLINE \
- "Copyright (c) 2018-2024 Cosmin Truta" PNG_STRING_NEWLINE \
+ "libpng version 1.6.50" 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 \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -1039,186 +1060,67 @@ png_zstream_error(png_structrp png_ptr, int ret)
}
}
-/* 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
- */
+#ifdef PNG_COLORSPACE_SUPPORTED
+static png_int_32
+png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error)
{
- png_fixed_point gtest;
-
- if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
- (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 ||
- png_gamma_significant(gtest) != 0))
+ /* Safely add two fixed point values setting an error flag and returning 0.5
+ * on overflow.
+ * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
+ * relying on addition of two positive values producing a negative one is not
+ * safe.
+ */
+ if (addend0 > 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;
- }
+ if (0x7fffffff - addend0 >= addend1)
+ return addend0+addend1;
}
-
- 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
+ else if (addend0 < 0)
{
- 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;
+ if (-0x7fffffff - addend0 <= addend1)
+ return addend0+addend1;
}
+ else
+ return addend1;
- /* Error exit - errmsg has been set. */
- colorspace->flags |= PNG_COLORSPACE_INVALID;
- png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
+ *error = 1;
+ return PNG_FP_1/2;
}
-void /* PRIVATE */
-png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)
+static png_int_32
+png_fp_sub(png_int_32 addend0, png_int_32 addend1, int *error)
{
- if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
+ /* As above but calculate addend0-addend1. */
+ if (addend1 > 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
+ if (-0x7fffffff + addend1 <= addend0)
+ return addend0-addend1;
}
-
- else
+ else if (addend1 < 0)
{
-# 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;
+ if (0x7fffffff + addend1 >= addend0)
+ return addend0-addend1;
}
-}
-
-#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;
+ else
+ return addend0;
- info_ptr->colorspace = png_ptr->colorspace;
- png_colorspace_sync_info(png_ptr, info_ptr);
+ *error = 1;
+ return PNG_FP_1/2;
}
-#endif
-#endif /* GAMMA */
-#ifdef PNG_COLORSPACE_SUPPORTED
static int
png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1,
- png_int_32 addend2) {
- /* Safely add three integers. Returns 0 on success, 1 on overlow.
- * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
- * relying on addition of two positive values producing a negative one is not
- * safe.
+ png_int_32 addend2)
+{
+ /* Safely add three integers. Returns 0 on success, 1 on overflow. Does not
+ * set the result on overflow.
*/
- int addend0 = *addend0_and_result;
- if (0x7fffffff - addend0 < addend1)
- return 1;
- addend0 += addend1;
- if (0x7fffffff - addend1 < addend2)
- return 1;
- *addend0_and_result = addend0 + addend2;
- return 0;
+ int error = 0;
+ int result = png_fp_add(*addend0_and_result,
+ png_fp_add(addend1, addend2, &error),
+ &error);
+ if (!error) *addend0_and_result = result;
+ return error;
}
/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
@@ -1226,10 +1128,11 @@ png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1,
* 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)
{
- png_int_32 d, dred, dgreen, dwhite, whiteX, whiteY;
+ /* 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,
* x, y and z are X,Y,Z/(X+Y+Z).
@@ -1237,44 +1140,52 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
d = XYZ->red_X;
if (png_safe_add(&d, XYZ->red_Y, XYZ->red_Z))
return 1;
- if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
+ dred = d;
+ if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, dred) == 0)
return 1;
- if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
+ if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, dred) == 0)
return 1;
- dred = d;
- whiteX = XYZ->red_X;
- whiteY = XYZ->red_Y;
d = XYZ->green_X;
if (png_safe_add(&d, XYZ->green_Y, XYZ->green_Z))
return 1;
- if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
+ dgreen = d;
+ if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, dgreen) == 0)
return 1;
- if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
+ if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, dgreen) == 0)
return 1;
- dgreen = d;
- whiteX += XYZ->green_X;
- whiteY += XYZ->green_Y;
d = XYZ->blue_X;
if (png_safe_add(&d, XYZ->blue_Y, XYZ->blue_Z))
return 1;
- if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
+ dblue = d;
+ if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, dblue) == 0)
return 1;
- if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
+ if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, dblue) == 0)
return 1;
- whiteX += XYZ->blue_X;
- whiteY += XYZ->blue_Y;
/* The reference white is simply the sum of the end-point (X,Y,Z) vectors so
* the fillowing calculates (X+Y+Z) of the reference white (media white,
* encoding white) itself:
*/
+ d = dblue;
if (png_safe_add(&d, dred, dgreen))
return 1;
-
dwhite = d;
+ /* Find the white X,Y values from the sum of the red, green and blue X,Y
+ * values.
+ */
+ d = XYZ->red_X;
+ if (png_safe_add(&d, XYZ->green_X, XYZ->blue_X))
+ return 1;
+ whiteX = d;
+
+ d = XYZ->red_Y;
+ if (png_safe_add(&d, XYZ->green_Y, XYZ->blue_Y))
+ return 1;
+ whiteY = d;
+
if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0)
return 1;
if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
@@ -1283,12 +1194,36 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
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;
+ /* Check xy and, implicitly, z. Note that wide gamut color spaces typically
+ * have end points with 0 tristimulus values (these are impossible end
+ * points, but they are used to cover the possible colors). We check
+ * xy->whitey against 5, not 0, to avoid a possible integer overflow.
+ *
+ * The limits here will *not* accept ACES AP0, where bluey is -7700
+ * (-0.0770) because the PNG spec itself requires the xy values to be
+ * unsigned. whitey is also required to be 5 or more to avoid overflow.
+ *
+ * Instead the upper limits have been relaxed to accomodate ACES AP1 where
+ * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range."
+ * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy.
+ */
+ const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10);
+ if (xy->redx < 0 || xy->redx > fpLimit) return 1;
+ if (xy->redy < 0 || xy->redy > fpLimit-xy->redx) return 1;
+ if (xy->greenx < 0 || xy->greenx > fpLimit) return 1;
+ if (xy->greeny < 0 || xy->greeny > fpLimit-xy->greenx) return 1;
+ if (xy->bluex < 0 || xy->bluex > fpLimit) return 1;
+ if (xy->bluey < 0 || xy->bluey > fpLimit-xy->bluex) return 1;
+ if (xy->whitex < 0 || xy->whitex > fpLimit) return 1;
+ if (xy->whitey < 5 || xy->whitey > fpLimit-xy->whitex) return 1;
+
/* The reverse calculation is more difficult because the original tristimulus
* value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
* derived values were recorded in the cHRM chunk;
@@ -1432,18 +1367,23 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
* (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
*
* Accuracy:
- * The input values have 5 decimal digits of accuracy. The values are all in
- * the range 0 < value < 1, so simple products are in the same range but may
- * need up to 10 decimal digits to preserve the original precision and avoid
- * underflow. Because we are using a 32-bit signed representation we cannot
- * match this; the best is a little over 9 decimal digits, less than 10.
+ * The input values have 5 decimal digits of accuracy.
+ *
+ * In the previous implementation the values were all in the range 0 < value
+ * < 1, so simple products are in the same range but may need up to 10
+ * decimal digits to preserve the original precision and avoid underflow.
+ * Because we are using a 32-bit signed representation we cannot match this;
+ * the best is a little over 9 decimal digits, less than 10.
+ *
+ * This range has now been extended to allow values up to 1.1, or 110,000 in
+ * fixed point.
*
* The approach used here is to preserve the maximum precision within the
* signed representation. Because the red-scale calculation above uses the
- * difference between two products of values that must be in the range -1..+1
- * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The
- * factor is irrelevant in the calculation because it is applied to both
- * numerator and denominator.
+ * difference between two products of values that must be in the range
+ * -1.1..+1.1 it is sufficient to divide the product by 8;
+ * ceil(121,000/32767*2). The factor is irrelevant in the calculation
+ * because it is applied to both numerator and denominator.
*
* Note that the values of the differences of the products of the
* chromaticities in the above equations tend to be small, for example for
@@ -1465,49 +1405,64 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
* Adobe Wide Gamut RGB
* 0.258728243040113 0.724682314948566 0.016589442011321
*/
- /* By the argument, above overflow should be impossible here. The return
- * value of 2 indicates an internal error to the caller.
- */
- if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0)
- return 1;
- if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
- return 1;
- denominator = left - right;
+ {
+ int error = 0;
- /* Now find the red numerator. */
- if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
- return 1;
- if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
- return 1;
+ /* By the argument above overflow should be impossible here, however the
+ * code now simply returns a failure code. The xy subtracts in the
+ * arguments to png_muldiv are *not* checked for overflow because the
+ * checks at the start guarantee they are in the range 0..110000 and
+ * png_fixed_point is a 32-bit signed number.
+ */
+ if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0)
+ return 1;
+ if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) ==
+ 0)
+ return 1;
+ denominator = png_fp_sub(left, right, &error);
+ if (error) return 1;
- /* Overflow is possible here and it indicates an extreme set of PNG cHRM
- * chunk values. This calculation actually returns the reciprocal of the
- * scale value because this allows us to delay the multiplication of white-y
- * into the denominator, which tends to produce a small number.
- */
- if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 ||
- red_inverse <= xy->whitey /* r+g+b scales = white scale */)
- return 1;
+ /* Now find the red numerator. */
+ if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
+ return 1;
+ if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) ==
+ 0)
+ return 1;
- /* Similarly for green_inverse: */
- if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
- return 1;
- if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
- return 1;
- if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
- green_inverse <= xy->whitey)
- return 1;
+ /* Overflow is possible here and it indicates an extreme set of PNG cHRM
+ * chunk values. This calculation actually returns the reciprocal of the
+ * scale value because this allows us to delay the multiplication of
+ * white-y into the denominator, which tends to produce a small number.
+ */
+ if (png_muldiv(&red_inverse, xy->whitey, denominator,
+ png_fp_sub(left, right, &error)) == 0 || error ||
+ red_inverse <= xy->whitey /* r+g+b scales = white scale */)
+ return 1;
- /* And the blue scale, the checks above guarantee this can't overflow but it
- * can still produce 0 for extreme cHRM values.
- */
- blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -
- png_reciprocal(green_inverse);
- if (blue_scale <= 0)
- return 1;
+ /* Similarly for green_inverse: */
+ if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
+ return 1;
+ if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
+ return 1;
+ if (png_muldiv(&green_inverse, xy->whitey, denominator,
+ png_fp_sub(left, right, &error)) == 0 || error ||
+ green_inverse <= xy->whitey)
+ return 1;
+ /* And the blue scale, the checks above guarantee this can't overflow but
+ * it can still produce 0 for extreme cHRM values.
+ */
+ blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey),
+ png_reciprocal(red_inverse), &error),
+ png_reciprocal(green_inverse), &error);
+ if (error || blue_scale <= 0)
+ return 1;
+ }
- /* And fill in the png_XYZ: */
+ /* And fill in the png_XYZ. Again the subtracts are safe because of the
+ * checks on the xy values at the start (the subtracts just calculate the
+ * corresponding z values.)
+ */
if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)
return 1;
if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)
@@ -1534,239 +1489,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
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_READ_iCCP_SUPPORTED
/* Error message generation */
static char
png_icc_tag_char(png_uint_32 byte)
@@ -1806,15 +1531,12 @@ is_ICC_signature(png_alloc_size_t it)
}
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 */
@@ -1841,109 +1563,11 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
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 */
-
-#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
/* 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:
*
@@ -1953,21 +1577,19 @@ static const png_byte D50_nCIEXYZ[12] =
{ 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
@@ -1976,30 +1598,17 @@ png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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;
@@ -2010,18 +1619,18 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
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
@@ -2029,14 +1638,14 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
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
* 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
@@ -2053,7 +1662,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
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
@@ -2064,7 +1673,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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:
@@ -2092,18 +1701,18 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
{
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");
}
@@ -2128,7 +1737,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
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' */
@@ -2138,7 +1747,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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' */
@@ -2146,7 +1755,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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;
@@ -2156,7 +1765,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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;
}
@@ -2172,7 +1781,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
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");
}
@@ -2180,9 +1789,9 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
}
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;
@@ -2208,7 +1817,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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)
@@ -2217,307 +1826,132 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* 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");
}
}
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
-{
- 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.
- */
- /* 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")
-
- /* 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")
-
- 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")
-
- /* 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")
-
- /* 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")
-};
-
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+#if (defined PNG_READ_mDCV_SUPPORTED) || (defined PNG_READ_cHRM_SUPPORTED)
static int
-png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
- png_const_bytep profile, uLong adler)
+have_chromaticities(png_const_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.
+ /* 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
*/
+# ifdef PNG_READ_mDCV_SUPPORTED
+ if (png_has_chunk(png_ptr, mDCV))
+ return 1;
+# define check_chromaticities 1
+# endif /*mDCV*/
- 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])
- {
- /* 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!)
- */
-# if PNG_sRGB_PROFILE_CHECKS == 0
- if (png_sRGB_checks[i].have_md5 != 0)
- return 1+png_sRGB_checks[i].is_broken;
-# endif
-
- /* Profile is unsigned or more checks have been configured in. */
- if (length == 0)
- {
- length = png_get_uint_32(profile);
- intent = png_get_uint_32(profile+64);
- }
-
- /* 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)
- {
- adler = adler32(0, NULL, 0);
- adler = adler32(adler, profile, length);
- }
-
- if (adler == png_sRGB_checks[i].adler)
- {
- /* 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;
- }
- }
+# ifdef PNG_READ_sRGB_SUPPORTED
+ if (png_has_chunk(png_ptr, sRGB))
+ return 0;
+# endif /*sRGB*/
-# 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
- }
- }
- }
+# ifdef PNG_READ_cHRM_SUPPORTED
+ if (png_has_chunk(png_ptr, cHRM))
+ return 1;
+# define check_chromaticities 1
+# endif /*cHRM*/
- return 0; /* no match */
+ return 0; /* sRGB defaults */
}
+#endif /* READ_mDCV || READ_cHRM */
void /* PRIVATE */
-png_icc_set_sRGB(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_const_bytep profile, uLong adler)
+png_set_rgb_coefficients(png_structrp png_ptr)
{
- /* Is this profile one of the known ICC sRGB profiles? If it is, just set
- * the sRGB information.
+ /* 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_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 (png_ptr->rgb_to_gray_coefficients_set == 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;
- }
+# if check_chromaticities
+ png_XYZ xyz;
- /* 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)
+ if (have_chromaticities(png_ptr) &&
+ png_XYZ_from_xy(&xyz, &png_ptr->chromaticities) == 0)
{
- /* 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
+ /* png_set_rgb_to_gray has not set the coefficients, get them from the
+ * Y * values of the colorspace colorants.
*/
- int add = 0;
+ 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;
+
+ 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)
+ {
+ /* 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 (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;
- }
+ 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");
+ /* 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;
+ else
+ {
+ png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
+ png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
+ }
}
}
-
- /* 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 /* check_chromaticities */
+ {
+ /* 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; */
+ }
}
}
#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,
@@ -3299,7 +2733,27 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
}
#endif
-#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
+ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
+ (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
+png_uint_32
+png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text)
+{
+ double r = floor(10000 * fp + .5);
+
+ if (r > 2147483647. || r < 0)
+ png_fixed_error(png_ptr, text);
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(text)
+# endif
+
+ return (png_uint_32)r;
+}
+#endif
+
+
+#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
@@ -3307,7 +2761,7 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
* 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)
{
@@ -3421,27 +2875,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
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)
@@ -3460,26 +2894,38 @@ png_reciprocal(png_fixed_point a)
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.
*/
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);
@@ -3495,9 +2941,8 @@ png_product2(png_fixed_point a, png_fixed_point b)
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)
{
@@ -4150,10 +3595,27 @@ png_destroy_gamma_table(png_structrp png_ptr)
* 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
@@ -4168,27 +3630,44 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
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
@@ -4254,32 +3733,26 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
* 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.
* 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 */
}
@@ -4494,7 +3967,7 @@ png_image_free_function(png_voidp argument)
# ifdef PNG_STDIO_SUPPORTED
if (cp->owned_file != 0)
{
- FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
+ FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr);
cp->owned_file = 0;
/* Ignore errors here. */
diff --git png/png.h png/png.h
index 04a233f..b9985e8 100644
--- png/png.h
+++ png/png.h
@@ -1,9 +1,8 @@
-
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.44
+ * libpng version 1.6.50
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -15,7 +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.44, September 2024:
+ * libpng versions 1.6.36, December 2018, through 1.6.50, July 2025:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -27,8 +26,8 @@
* PNG Reference Library License version 2
* ---------------------------------------
*
- * * Copyright (c) 1995-2024 The PNG Reference Library Authors.
- * * Copyright (c) 2018-2024 Cosmin Truta.
+ * * Copyright (c) 1995-2025 The PNG Reference Library Authors.
+ * * Copyright (c) 2018-2025 Cosmin Truta.
* * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* * Copyright (c) 1996-1997 Andreas Dilger.
* * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +238,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.44 16 10644 16.so.16.44[.0]
+ * 1.6.50 16 10650 16.so.16.50[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -275,7 +274,7 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.44"
+#define PNG_LIBPNG_VER_STRING "1.6.50"
#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
/* The versions of shared library builds should stay in sync, going forward */
@@ -286,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 44
+#define PNG_LIBPNG_VER_RELEASE 50
/* This should be zero for a public release, or non-zero for a
* development version.
@@ -317,7 +316,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10644 /* 1.6.44 */
+#define PNG_LIBPNG_VER 10650 /* 1.6.50 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -427,7 +426,7 @@ extern "C" {
/* 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_44;
+typedef char* png_libpng_version_1_6_50;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -745,6 +744,21 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
+#define PNG_INFO_cICP 0x20000U /* PNGv3: 1.6.45 */
+#define PNG_INFO_cLLI 0x40000U /* PNGv3: 1.6.45 */
+#define PNG_INFO_mDCV 0x80000U /* PNGv3: 1.6.45 */
+/* APNG: these chunks are stored as unknown, these flags are never set
+ * however they are provided as a convenience for implementors of APNG and
+ * avoids any merge conflicts.
+ *
+ * Private chunks: these chunk names violate the chunk name recommendations
+ * because the chunk definitions have no signature and because the private
+ * chunks with these names have been reserved. Private definitions should
+ * avoid them.
+ */
+#define PNG_INFO_acTL 0x100000U /* PNGv3: 1.6.45: unknown */
+#define PNG_INFO_fcTL 0x200000U /* PNGv3: 1.6.45: unknown */
+#define PNG_INFO_fdAT 0x400000U /* PNGv3: 1.6.45: unknown */
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -1556,7 +1570,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
#ifdef PNG_STDIO_SUPPORTED
/* Initialize the input/output for the PNG file to the default functions. */
-PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
+PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
#endif
/* Replace the (error and abort), and warning functions with user
@@ -1974,6 +1988,46 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
png_fixed_point int_blue_Z))
#endif
+#ifdef PNG_cICP_SUPPORTED
+PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_bytep colour_primaries,
+ png_bytep transfer_function, png_bytep matrix_coefficients,
+ png_bytep video_full_range_flag));
+#endif
+
+#ifdef PNG_cICP_SUPPORTED
+PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_byte colour_primaries,
+ png_byte transfer_function, png_byte matrix_coefficients,
+ png_byte video_full_range_flag));
+#endif
+
+#ifdef PNG_cLLI_SUPPORTED
+PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, double *maximum_content_light_level,
+ double *maximum_frame_average_light_level))
+PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr,
+ /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
+ * 100,000 as in the case of png_fixed_point.
+ */
+ png_uint_32p maximum_content_light_level_scaled_by_10000,
+ png_uint_32p maximum_frame_average_light_level_scaled_by_10000))
+#endif
+
+#ifdef PNG_cLLI_SUPPORTED
+PNG_FP_EXPORT(254, void, png_set_cLLI, (png_const_structrp png_ptr,
+ png_inforp info_ptr, double maximum_content_light_level,
+ double maximum_frame_average_light_level))
+PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr,
+ png_inforp info_ptr,
+ /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
+ * 100,000 as in the case of png_fixed_point.
+ */
+ png_uint_32 maximum_content_light_level_scaled_by_10000,
+ png_uint_32 maximum_frame_average_light_level_scaled_by_10000))
+#endif
+
#ifdef PNG_eXIf_SUPPORTED
PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
png_inforp info_ptr, png_bytep *exif));
@@ -2018,6 +2072,60 @@ PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
int color_type, int interlace_method, int compression_method,
int filter_method));
+#ifdef PNG_mDCV_SUPPORTED
+PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr,
+ /* The chromaticities of the mastering display. As cHRM, but independent of
+ * the encoding endpoints in cHRM, or cICP, or iCCP. These values will
+ * always be in the range 0 to 1.3107.
+ */
+ double *white_x, double *white_y, double *red_x, double *red_y,
+ double *green_x, double *green_y, double *blue_x, double *blue_y,
+ /* Mastering display luminance in cd/m2 (nits). */
+ double *mastering_display_maximum_luminance,
+ double *mastering_display_minimum_luminance))
+
+PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_fixed_point *int_white_x, png_fixed_point *int_white_y,
+ png_fixed_point *int_red_x, png_fixed_point *int_red_y,
+ png_fixed_point *int_green_x, png_fixed_point *int_green_y,
+ png_fixed_point *int_blue_x, png_fixed_point *int_blue_y,
+ /* Mastering display luminance in cd/m2 (nits) multiplied (scaled) by
+ * 10,000.
+ */
+ png_uint_32p mastering_display_maximum_luminance_scaled_by_10000,
+ png_uint_32p mastering_display_minimum_luminance_scaled_by_10000))
+#endif
+
+#ifdef PNG_mDCV_SUPPORTED
+PNG_FP_EXPORT(258, void, png_set_mDCV, (png_const_structrp png_ptr,
+ png_inforp info_ptr,
+ /* The chromaticities of the mastering display. As cHRM, but independent of
+ * the encoding endpoints in cHRM, or cICP, or iCCP.
+ */
+ double white_x, double white_y, double red_x, double red_y, double green_x,
+ double green_y, double blue_x, double blue_y,
+ /* Mastering display luminance in cd/m2 (nits). */
+ double mastering_display_maximum_luminance,
+ double mastering_display_minimum_luminance))
+
+PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr,
+ png_inforp info_ptr,
+ /* The admissible range of these values is not the full range of a PNG
+ * fixed point value. Negative values cannot be encoded and the maximum
+ * value is about 1.3 */
+ png_fixed_point int_white_x, png_fixed_point int_white_y,
+ png_fixed_point int_red_x, png_fixed_point int_red_y,
+ png_fixed_point int_green_x, png_fixed_point int_green_y,
+ png_fixed_point int_blue_x, png_fixed_point int_blue_y,
+ /* These are PNG unsigned 4 byte values: 31-bit unsigned values. The MSB
+ * must be zero.
+ */
+ png_uint_32 mastering_display_maximum_luminance_scaled_by_10000,
+ png_uint_32 mastering_display_minimum_luminance_scaled_by_10000))
+#endif
+
#ifdef PNG_oFFs_SUPPORTED
PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,
png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
@@ -2980,7 +3088,7 @@ PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
*/
PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
- FILE* file));
+ FILE *file));
/* The PNG header is read from the stdio FILE object. */
#endif /* STDIO */
@@ -3055,7 +3163,7 @@ PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
const void *colormap));
- /* Write the image to the given (FILE*). */
+ /* Write the image to the given FILE object. */
#endif /* SIMPLIFIED_WRITE_STDIO */
/* With all write APIs if image is in one of the linear formats with 16-bit
@@ -3195,26 +3303,45 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
* selected at run time.
*/
#ifdef PNG_SET_OPTION_SUPPORTED
+
+/* HARDWARE: ARM Neon SIMD instructions supported */
#ifdef PNG_ARM_NEON_API_SUPPORTED
-# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */
+# define PNG_ARM_NEON 0
#endif
-#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
-#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
+
+/* SOFTWARE: Force maximum window */
+#define PNG_MAXIMUM_INFLATE_WINDOW 2
+
+/* SOFTWARE: Check ICC profile for sRGB */
+#define PNG_SKIP_sRGB_CHECK_PROFILE 4
+
+/* HARDWARE: MIPS MSA SIMD instructions supported */
#ifdef PNG_MIPS_MSA_API_SUPPORTED
-# define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */
+# define PNG_MIPS_MSA 6
#endif
+
+/* SOFTWARE: Disable Adler32 check on IDAT */
#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
-# define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
+# define PNG_IGNORE_ADLER32 8
#endif
+
+/* HARDWARE: PowerPC VSX SIMD instructions supported */
#ifdef PNG_POWERPC_VSX_API_SUPPORTED
-# define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions
- * supported */
+# define PNG_POWERPC_VSX 10
#endif
+
+/* HARDWARE: MIPS MMI SIMD instructions supported */
#ifdef PNG_MIPS_MMI_API_SUPPORTED
-# define PNG_MIPS_MMI 12 /* HARDWARE: MIPS MMI SIMD instructions supported */
+# define PNG_MIPS_MMI 12
+#endif
+
+/* HARDWARE: RISC-V RVV SIMD instructions supported */
+#ifdef PNG_RISCV_RVV_API_SUPPORTED
+# define PNG_RISCV_RVV 14
#endif
-#define PNG_OPTION_NEXT 14 /* Next option - numbers must be even */
+/* Next option - numbers must be even */
+#define PNG_OPTION_NEXT 16
/* Return values: NOTE: there are four values and 'off' is *not* zero */
#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
@@ -3238,7 +3365,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(249);
+ PNG_EXPORT_LAST_ORDINAL(259);
#endif
#ifdef __cplusplus
diff --git png/pngconf.h png/pngconf.h
index 4a4b58a..d1081b5 100644
--- png/pngconf.h
+++ png/pngconf.h
@@ -1,9 +1,8 @@
-
/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.44
+ * libpng version 1.6.50
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -220,25 +219,13 @@
/* NOTE: PNGCBAPI always defaults to PNGCAPI. */
# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
-# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
+# error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
# endif
-# if (defined(_MSC_VER) && _MSC_VER < 800) ||\
- (defined(__BORLANDC__) && __BORLANDC__ < 0x500)
- /* older Borland and MSC
- * compilers used '__export' and required this to be after
- * the type.
- */
-# ifndef PNG_EXPORT_TYPE
-# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
-# endif
-# define PNG_DLL_EXPORT __export
-# else /* newer compiler */
-# define PNG_DLL_EXPORT __declspec(dllexport)
-# ifndef PNG_DLL_IMPORT
-# define PNG_DLL_IMPORT __declspec(dllimport)
-# endif
-# endif /* compiler */
+# define PNG_DLL_EXPORT __declspec(dllexport)
+# ifndef PNG_DLL_IMPORT
+# define PNG_DLL_IMPORT __declspec(dllimport)
+# endif
#else /* !Windows */
# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
@@ -480,7 +467,7 @@
#if CHAR_BIT == 8 && UCHAR_MAX == 255
typedef unsigned char png_byte;
#else
-# error "libpng requires 8-bit bytes"
+# error libpng requires 8-bit bytes
#endif
#if INT_MIN == -32768 && INT_MAX == 32767
@@ -488,7 +475,7 @@
#elif SHRT_MIN == -32768 && SHRT_MAX == 32767
typedef short png_int_16;
#else
-# error "libpng requires a signed 16-bit type"
+# error libpng requires a signed 16-bit integer type
#endif
#if UINT_MAX == 65535
@@ -496,7 +483,7 @@
#elif USHRT_MAX == 65535
typedef unsigned short png_uint_16;
#else
-# error "libpng requires an unsigned 16-bit type"
+# error libpng requires an unsigned 16-bit integer type
#endif
#if INT_MIN < -2147483646 && INT_MAX > 2147483646
@@ -504,7 +491,7 @@
#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
typedef long int png_int_32;
#else
-# error "libpng requires a signed 32-bit (or more) type"
+# error libpng requires a signed 32-bit (or longer) integer type
#endif
#if UINT_MAX > 4294967294U
@@ -512,7 +499,7 @@
#elif ULONG_MAX > 4294967294U
typedef unsigned long int png_uint_32;
#else
-# error "libpng requires an unsigned 32-bit (or more) type"
+# error libpng requires an unsigned 32-bit (or longer) integer type
#endif
/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
@@ -593,10 +580,6 @@ typedef const png_fixed_point * png_const_fixed_point_p;
typedef size_t * png_size_tp;
typedef const size_t * png_const_size_tp;
-#ifdef PNG_STDIO_SUPPORTED
-typedef FILE * png_FILE_p;
-#endif
-
#ifdef PNG_FLOATING_POINT_SUPPORTED
typedef double * png_doublep;
typedef const double * png_const_doublep;
@@ -618,6 +601,15 @@ typedef double * * png_doublepp;
/* Pointers to pointers to pointers; i.e., pointer to array */
typedef char * * * png_charppp;
+#ifdef PNG_STDIO_SUPPORTED
+/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were
+ * not necessarily stdio FILE streams, to allow building Windows applications
+ * before Win32 and Windows CE applications before WinCE 3.0, but that kind
+ * of support has long been discontinued.
+ */
+typedef FILE * png_FILE_p; /* [Deprecated] */
+#endif
+
#endif /* PNG_BUILDING_SYMBOL_TABLE */
#endif /* PNGCONF_H */
diff --git png/pngdebug.h png/pngdebug.h
index 00d5a45..af1ae9e 100644
--- png/pngdebug.h
+++ png/pngdebug.h
@@ -1,7 +1,6 @@
-
-/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
+/* pngdebug.h - internal debugging macros for libpng
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -11,6 +10,10 @@
* and license in png.h
*/
+#ifndef PNGPRIV_H
+# error This file must not be included by applications; please include <png.h>
+#endif
+
/* Define PNG_DEBUG at compile time for debugging information. Higher
* numbers for PNG_DEBUG mean more debugging information. This has
* only been added since version 0.95 so it is not implemented throughout
diff --git png/pngerror.c png/pngerror.c
index 1babf9f..01a7ef5 100644
--- png/pngerror.c
+++ png/pngerror.c
@@ -1,7 +1,6 @@
-
/* pngerror.c - stub functions for i/o and memory allocation
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -936,23 +935,37 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
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 */
diff --git png/pngget.c png/pngget.c
index 1084b26..1ebb114 100644
--- png/pngget.c
+++ png/pngget.c
@@ -1,7 +1,6 @@
-
/* pngget.c - retrieval of values from info struct
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -381,7 +380,13 @@ png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns)
* 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
@@ -391,7 +396,7 @@ png_get_x_offset_inches_fixed(png_const_structrp png_ptr,
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
@@ -519,44 +524,31 @@ png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
# 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;
}
@@ -569,38 +561,31 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
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;
}
@@ -617,29 +602,22 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
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;
}
@@ -648,31 +626,24 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
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;
}
@@ -689,11 +660,11 @@ png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
{
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;
}
@@ -708,12 +679,13 @@ png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,
{
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;
}
@@ -730,9 +702,10 @@ png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,
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;
}
@@ -785,6 +758,136 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
}
#endif
+#ifdef PNG_cICP_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cICP(png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_bytep colour_primaries,
+ png_bytep transfer_function, png_bytep matrix_coefficients,
+ png_bytep video_full_range_flag)
+{
+ png_debug1(1, "in %s retrieval function", "cICP");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_cICP) != 0 &&
+ colour_primaries != NULL && transfer_function != NULL &&
+ matrix_coefficients != NULL && video_full_range_flag != NULL)
+ {
+ *colour_primaries = info_ptr->cicp_colour_primaries;
+ *transfer_function = info_ptr->cicp_transfer_function;
+ *matrix_coefficients = info_ptr->cicp_matrix_coefficients;
+ *video_full_range_flag = info_ptr->cicp_video_full_range_flag;
+ return (PNG_INFO_cICP);
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef PNG_cLLI_SUPPORTED
+# ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cLLI_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32p maxCLL,
+ png_uint_32p maxFALL)
+{
+ png_debug1(1, "in %s retrieval function", "cLLI");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_cLLI) != 0)
+ {
+ if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL;
+ if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL;
+ return PNG_INFO_cLLI;
+ }
+
+ return 0;
+}
+# endif
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cLLI(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ double *maxCLL, double *maxFALL)
+{
+ png_debug1(1, "in %s retrieval function", "cLLI(float)");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_cLLI) != 0)
+ {
+ if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL * .0001;
+ if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL * .0001;
+ return PNG_INFO_cLLI;
+ }
+
+ return 0;
+}
+# endif
+#endif /* cLLI */
+
+#ifdef PNG_mDCV_SUPPORTED
+# ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_mDCV_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_uint_32p mastering_maxDL, png_uint_32p mastering_minDL)
+{
+ png_debug1(1, "in %s retrieval function", "mDCV");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_mDCV) != 0)
+ {
+ if (white_x != NULL) *white_x = info_ptr->mastering_white_x * 2;
+ if (white_y != NULL) *white_y = info_ptr->mastering_white_y * 2;
+ if (red_x != NULL) *red_x = info_ptr->mastering_red_x * 2;
+ if (red_y != NULL) *red_y = info_ptr->mastering_red_y * 2;
+ if (green_x != NULL) *green_x = info_ptr->mastering_green_x * 2;
+ if (green_y != NULL) *green_y = info_ptr->mastering_green_y * 2;
+ if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * 2;
+ if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * 2;
+ if (mastering_maxDL != NULL) *mastering_maxDL = info_ptr->mastering_maxDL;
+ if (mastering_minDL != NULL) *mastering_minDL = info_ptr->mastering_minDL;
+ return PNG_INFO_mDCV;
+ }
+
+ return 0;
+}
+# endif
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_mDCV(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 *mastering_maxDL, double *mastering_minDL)
+{
+ png_debug1(1, "in %s retrieval function", "mDCV(float)");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_mDCV) != 0)
+ {
+ if (white_x != NULL) *white_x = info_ptr->mastering_white_x * .00002;
+ if (white_y != NULL) *white_y = info_ptr->mastering_white_y * .00002;
+ if (red_x != NULL) *red_x = info_ptr->mastering_red_x * .00002;
+ if (red_y != NULL) *red_y = info_ptr->mastering_red_y * .00002;
+ if (green_x != NULL) *green_x = info_ptr->mastering_green_x * .00002;
+ if (green_y != NULL) *green_y = info_ptr->mastering_green_y * .00002;
+ if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * .00002;
+ if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * .00002;
+ if (mastering_maxDL != NULL)
+ *mastering_maxDL = info_ptr->mastering_maxDL * .0001;
+ if (mastering_minDL != NULL)
+ *mastering_minDL = info_ptr->mastering_minDL * .0001;
+ return PNG_INFO_mDCV;
+ }
+
+ return 0;
+}
+# endif /* FLOATING_POINT */
+#endif /* mDCV */
+
#ifdef PNG_eXIf_SUPPORTED
png_uint_32 PNGAPI
png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
diff --git png/pnginfo.h png/pnginfo.h
index 1f98ded..584a42f 100644
--- png/pnginfo.h
+++ png/pnginfo.h
@@ -1,7 +1,6 @@
-
-/* pnginfo.h - header file for PNG reference library
+/* pnginfo.h - internal structures for libpng
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -11,43 +10,20 @@
* and license in png.h
*/
- /* png_info is a structure that holds the information in a PNG file so
- * that the application can find out the characteristics of the image.
- * If you are reading the file, this structure will tell you what is
- * in the PNG file. If you are writing the file, fill in the information
- * you want to put into the PNG file, using png_set_*() functions, then
- * call png_write_info().
- *
- * The names chosen should be very close to the PNG specification, so
- * consult that document for information about the meaning of each field.
- *
- * With libpng < 0.95, it was only possible to directly set and read the
- * the values in the png_info_struct, which meant that the contents and
- * order of the values had to remain fixed. With libpng 0.95 and later,
- * however, there are now functions that abstract the contents of
- * png_info_struct from the application, so this makes it easier to use
- * libpng with dynamic libraries, and even makes it possible to use
- * libraries that don't have all of the libpng ancillary chunk-handing
- * functionality. In libpng-1.5.0 this was moved into a separate private
- * file that is not visible to applications.
+#ifndef PNGPRIV_H
+# error This file must not be included by applications; please include <png.h>
+#endif
+
+/* INTERNAL, PRIVATE definition of a PNG.
*
- * The following members may have allocated storage attached that should be
- * cleaned up before the structure is discarded: palette, trans, text,
- * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
- * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these
- * are automatically freed when the info structure is deallocated, if they were
- * allocated internally by libpng. This behavior can be changed by means
- * of the png_data_freer() function.
+ * png_info is a modifiable description of a PNG datastream. The fields inside
+ * this structure are accessed through png_get_<CHUNK>() functions and modified
+ * using png_set_<CHUNK>() functions.
*
- * More allocation details: all the chunk-reading functions that
- * change these members go through the corresponding png_set_*
- * functions. A function to clear these members is available: see
- * png_free_data(). The png_set_* functions do not depend on being
- * able to point info structure members to any of the storage they are
- * passed (they make their own copies), EXCEPT that the png_set_text
- * functions use the same storage passed to them in the text_ptr or
- * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
- * functions do not make their own copies.
+ * Some functions in libpng do directly access members of png_info. However,
+ * this should be avoided. png_struct objects contain members which hold
+ * caches, sometimes optimised, of the values from png_info objects, and
+ * png_info is not passed to the functions which read and write image data.
*/
#ifndef PNGINFO_H
#define PNGINFO_H
@@ -87,18 +63,12 @@ struct png_info_def
* 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;
+#ifdef PNG_cICP_SUPPORTED
+ /* cICP chunk data */
+ png_byte cicp_colour_primaries;
+ png_byte cicp_transfer_function;
+ png_byte cicp_matrix_coefficients;
+ png_byte cicp_video_full_range_flag;
#endif
#ifdef PNG_iCCP_SUPPORTED
@@ -108,6 +78,24 @@ struct png_info_def
png_uint_32 iccp_proflen; /* ICC profile data length */
#endif
+#ifdef PNG_cLLI_SUPPORTED
+ png_uint_32 maxCLL; /* cd/m2 (nits) * 10,000 */
+ png_uint_32 maxFALL;
+#endif
+
+#ifdef PNG_mDCV_SUPPORTED
+ png_uint_16 mastering_red_x; /* CIE (xy) x * 50,000 */
+ png_uint_16 mastering_red_y;
+ png_uint_16 mastering_green_x;
+ png_uint_16 mastering_green_y;
+ png_uint_16 mastering_blue_x;
+ png_uint_16 mastering_blue_y;
+ png_uint_16 mastering_white_x;
+ png_uint_16 mastering_white_y;
+ png_uint_32 mastering_maxDL; /* cd/m2 (nits) * 10,000 */
+ png_uint_32 mastering_minDL;
+#endif
+
#ifdef PNG_TEXT_SUPPORTED
/* The tEXt, and zTXt chunks contain human-readable textual data in
* uncompressed, compressed, and optionally compressed forms, respectively.
@@ -186,11 +174,8 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
#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
@@ -263,5 +248,16 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
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 */
diff --git png/pnglibconf.h png/pnglibconf.h
index b19b2b4..f3022e6 100644
--- png/pnglibconf.h
+++ png/pnglibconf.h
@@ -1,8 +1,8 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.44 */
+/* libpng version 1.6.50 */
-/* Copyright (c) 2018-2024 Cosmin Truta */
+/* Copyright (c) 2018-2025 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
@@ -22,8 +22,12 @@
#define PNG_BENIGN_ERRORS_SUPPORTED
#define PNG_BENIGN_READ_ERRORS_SUPPORTED
/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/
+#define PNG_bKGD_SUPPORTED
#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_cHRM_SUPPORTED
+#define PNG_cICP_SUPPORTED
+#define PNG_cLLI_SUPPORTED
#define PNG_COLORSPACE_SUPPORTED
#define PNG_CONSOLE_IO_SUPPORTED
#define PNG_CONVERT_tIME_SUPPORTED
@@ -31,22 +35,31 @@
#define PNG_EASY_ACCESS_SUPPORTED
/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
#define PNG_ERROR_TEXT_SUPPORTED
+#define PNG_eXIf_SUPPORTED
#define PNG_FIXED_POINT_SUPPORTED
#define PNG_FLOATING_ARITHMETIC_SUPPORTED
#define PNG_FLOATING_POINT_SUPPORTED
#define PNG_FORMAT_AFIRST_SUPPORTED
#define PNG_FORMAT_BGR_SUPPORTED
+#define PNG_gAMA_SUPPORTED
#define PNG_GAMMA_SUPPORTED
#define PNG_GET_PALETTE_MAX_SUPPORTED
#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+#define PNG_hIST_SUPPORTED
+#define PNG_iCCP_SUPPORTED
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
+#define PNG_iTXt_SUPPORTED
+#define PNG_mDCV_SUPPORTED
/*#undef PNG_MIPS_MMI_API_SUPPORTED*/
/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/
/*#undef PNG_MIPS_MSA_API_SUPPORTED*/
/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/
#define PNG_MNG_FEATURES_SUPPORTED
+#define PNG_oFFs_SUPPORTED
+#define PNG_pCAL_SUPPORTED
+#define PNG_pHYs_SUPPORTED
#define PNG_POINTER_INDEXING_SUPPORTED
/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/
@@ -56,61 +69,66 @@
#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_READ_BACKGROUND_SUPPORTED
#define PNG_READ_BGR_SUPPORTED
+#define PNG_READ_bKGD_SUPPORTED
#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_cICP_SUPPORTED
+#define PNG_READ_cLLI_SUPPORTED
#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
+#define PNG_READ_eXIf_SUPPORTED
#define PNG_READ_EXPAND_16_SUPPORTED
#define PNG_READ_EXPAND_SUPPORTED
#define PNG_READ_FILLER_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
#define PNG_READ_GAMMA_SUPPORTED
#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
#define PNG_READ_GRAY_TO_RGB_SUPPORTED
-#define PNG_READ_INTERLACING_SUPPORTED
+#define PNG_READ_hIST_SUPPORTED
+#define PNG_READ_iCCP_SUPPORTED
#define PNG_READ_INT_FUNCTIONS_SUPPORTED
+#define PNG_READ_INTERLACING_SUPPORTED
#define PNG_READ_INVERT_ALPHA_SUPPORTED
#define PNG_READ_INVERT_SUPPORTED
+#define PNG_READ_iTXt_SUPPORTED
+#define PNG_READ_mDCV_SUPPORTED
+#define PNG_READ_oFFs_SUPPORTED
#define PNG_READ_OPT_PLTE_SUPPORTED
-#define PNG_READ_PACKSWAP_SUPPORTED
#define PNG_READ_PACK_SUPPORTED
+#define PNG_READ_PACKSWAP_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
#define PNG_READ_QUANTIZE_SUPPORTED
#define PNG_READ_RGB_TO_GRAY_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_sCAL_SUPPORTED
#define PNG_READ_SCALE_16_TO_8_SUPPORTED
#define PNG_READ_SHIFT_SUPPORTED
+#define PNG_READ_sPLT_SUPPORTED
+#define PNG_READ_sRGB_SUPPORTED
#define PNG_READ_STRIP_16_TO_8_SUPPORTED
#define PNG_READ_STRIP_ALPHA_SUPPORTED
#define PNG_READ_SUPPORTED
#define PNG_READ_SWAP_ALPHA_SUPPORTED
#define PNG_READ_SWAP_SUPPORTED
+#define PNG_READ_tEXt_SUPPORTED
#define PNG_READ_TEXT_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
#define PNG_READ_TRANSFORMS_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_READ_USER_CHUNKS_SUPPORTED
#define PNG_READ_USER_TRANSFORM_SUPPORTED
-#define PNG_READ_bKGD_SUPPORTED
-#define PNG_READ_cHRM_SUPPORTED
-#define PNG_READ_eXIf_SUPPORTED
-#define PNG_READ_gAMA_SUPPORTED
-#define PNG_READ_hIST_SUPPORTED
-#define PNG_READ_iCCP_SUPPORTED
-#define PNG_READ_iTXt_SUPPORTED
-#define PNG_READ_oFFs_SUPPORTED
-#define PNG_READ_pCAL_SUPPORTED
-#define PNG_READ_pHYs_SUPPORTED
-#define PNG_READ_sBIT_SUPPORTED
-#define PNG_READ_sCAL_SUPPORTED
-#define PNG_READ_sPLT_SUPPORTED
-#define PNG_READ_sRGB_SUPPORTED
-#define PNG_READ_tEXt_SUPPORTED
-#define PNG_READ_tIME_SUPPORTED
-#define PNG_READ_tRNS_SUPPORTED
#define PNG_READ_zTXt_SUPPORTED
#define PNG_SAVE_INT_32_SUPPORTED
#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_sBIT_SUPPORTED
+#define PNG_sCAL_SUPPORTED
#define PNG_SEQUENTIAL_READ_SUPPORTED
-#define PNG_SETJMP_SUPPORTED
#define PNG_SET_OPTION_SUPPORTED
#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_SET_USER_LIMITS_SUPPORTED
+#define PNG_SETJMP_SUPPORTED
#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED
#define PNG_SIMPLIFIED_READ_SUPPORTED
@@ -118,10 +136,15 @@
#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_SUPPORTED
+#define PNG_sPLT_SUPPORTED
+#define PNG_sRGB_SUPPORTED
#define PNG_STDIO_SUPPORTED
#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_tEXt_SUPPORTED
#define PNG_TEXT_SUPPORTED
#define PNG_TIME_RFC1123_SUPPORTED
+#define PNG_tIME_SUPPORTED
+#define PNG_tRNS_SUPPORTED
#define PNG_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_USER_CHUNKS_SUPPORTED
#define PNG_USER_LIMITS_SUPPORTED
@@ -132,65 +155,51 @@
#define PNG_WRITE_16BIT_SUPPORTED
#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_WRITE_BGR_SUPPORTED
+#define PNG_WRITE_bKGD_SUPPORTED
#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_cICP_SUPPORTED
+#define PNG_WRITE_cLLI_SUPPORTED
#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+#define PNG_WRITE_eXIf_SUPPORTED
#define PNG_WRITE_FILLER_SUPPORTED
#define PNG_WRITE_FILTER_SUPPORTED
#define PNG_WRITE_FLUSH_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
-#define PNG_WRITE_INTERLACING_SUPPORTED
+#define PNG_WRITE_hIST_SUPPORTED
+#define PNG_WRITE_iCCP_SUPPORTED
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+#define PNG_WRITE_INTERLACING_SUPPORTED
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
#define PNG_WRITE_INVERT_SUPPORTED
-#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
-#define PNG_WRITE_PACKSWAP_SUPPORTED
-#define PNG_WRITE_PACK_SUPPORTED
-#define PNG_WRITE_SHIFT_SUPPORTED
-#define PNG_WRITE_SUPPORTED
-#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
-#define PNG_WRITE_SWAP_SUPPORTED
-#define PNG_WRITE_TEXT_SUPPORTED
-#define PNG_WRITE_TRANSFORMS_SUPPORTED
-#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
-#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
-#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-#define PNG_WRITE_bKGD_SUPPORTED
-#define PNG_WRITE_cHRM_SUPPORTED
-#define PNG_WRITE_eXIf_SUPPORTED
-#define PNG_WRITE_gAMA_SUPPORTED
-#define PNG_WRITE_hIST_SUPPORTED
-#define PNG_WRITE_iCCP_SUPPORTED
#define PNG_WRITE_iTXt_SUPPORTED
+#define PNG_WRITE_mDCV_SUPPORTED
#define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+#define PNG_WRITE_PACK_SUPPORTED
+#define PNG_WRITE_PACKSWAP_SUPPORTED
#define PNG_WRITE_pCAL_SUPPORTED
#define PNG_WRITE_pHYs_SUPPORTED
#define PNG_WRITE_sBIT_SUPPORTED
#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_SHIFT_SUPPORTED
#define PNG_WRITE_sPLT_SUPPORTED
#define PNG_WRITE_sRGB_SUPPORTED
+#define PNG_WRITE_SUPPORTED
+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#define PNG_WRITE_SWAP_SUPPORTED
#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_TEXT_SUPPORTED
#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_TRANSFORMS_SUPPORTED
#define PNG_WRITE_tRNS_SUPPORTED
+#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#define PNG_WRITE_zTXt_SUPPORTED
-#define PNG_bKGD_SUPPORTED
-#define PNG_cHRM_SUPPORTED
-#define PNG_eXIf_SUPPORTED
-#define PNG_gAMA_SUPPORTED
-#define PNG_hIST_SUPPORTED
-#define PNG_iCCP_SUPPORTED
-#define PNG_iTXt_SUPPORTED
-#define PNG_oFFs_SUPPORTED
-#define PNG_pCAL_SUPPORTED
-#define PNG_pHYs_SUPPORTED
-#define PNG_sBIT_SUPPORTED
-#define PNG_sCAL_SUPPORTED
-#define PNG_sPLT_SUPPORTED
-#define PNG_sRGB_SUPPORTED
-#define PNG_tEXt_SUPPORTED
-#define PNG_tIME_SUPPORTED
-#define PNG_tRNS_SUPPORTED
#define PNG_zTXt_SUPPORTED
/* end of options */
/* settings */
@@ -208,19 +217,19 @@
#define PNG_QUANTIZE_BLUE_BITS 5
#define PNG_QUANTIZE_GREEN_BITS 5
#define PNG_QUANTIZE_RED_BITS 5
+#define PNG_sCAL_PRECISION 5
+#define PNG_sRGB_PROFILE_CHECKS 2
#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
#define PNG_TEXT_Z_DEFAULT_STRATEGY 0
#define PNG_USER_CHUNK_CACHE_MAX 1000
#define PNG_USER_CHUNK_MALLOC_MAX 8000000
#define PNG_USER_HEIGHT_MAX 1000000
#define PNG_USER_WIDTH_MAX 1000000
-#define PNG_ZBUF_SIZE 8192
-#define PNG_ZLIB_VERNUM 0x1310
#define PNG_Z_DEFAULT_COMPRESSION (-1)
#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0
#define PNG_Z_DEFAULT_STRATEGY 1
-#define PNG_sCAL_PRECISION 5
-#define PNG_sRGB_PROFILE_CHECKS 2
+#define PNG_ZBUF_SIZE 8192
+#define PNG_ZLIB_VERNUM 0x1310
/* end of settings */
#define png_access_version_number fltk_png_access_version_number
#define png_benign_error fltk_png_benign_error
@@ -246,33 +255,35 @@
#define png_free fltk_png_free
#define png_free_data fltk_png_free_data
#define png_free_default fltk_png_free_default
-#define png_get_IHDR fltk_png_get_IHDR
-#define png_get_PLTE fltk_png_get_PLTE
-#define png_get_bKGD fltk_png_get_bKGD
#define png_get_bit_depth fltk_png_get_bit_depth
+#define png_get_bKGD fltk_png_get_bKGD
+#define png_get_channels fltk_png_get_channels
#define png_get_cHRM fltk_png_get_cHRM
+#define png_get_cHRM_fixed fltk_png_get_cHRM_fixed
#define png_get_cHRM_XYZ fltk_png_get_cHRM_XYZ
#define png_get_cHRM_XYZ_fixed fltk_png_get_cHRM_XYZ_fixed
-#define png_get_cHRM_fixed fltk_png_get_cHRM_fixed
-#define png_get_channels fltk_png_get_channels
#define png_get_chunk_cache_max fltk_png_get_chunk_cache_max
#define png_get_chunk_malloc_max fltk_png_get_chunk_malloc_max
+#define png_get_cICP fltk_png_get_cICP
+#define png_get_cLLI fltk_png_get_cLLI
+#define png_get_cLLI_fixed fltk_png_get_cLLI_fixed
#define png_get_color_type fltk_png_get_color_type
#define png_get_compression_buffer_size fltk_png_get_compression_buffer_size
#define png_get_compression_type fltk_png_get_compression_type
#define png_get_copyright fltk_png_get_copyright
#define png_get_current_pass_number fltk_png_get_current_pass_number
#define png_get_current_row_number fltk_png_get_current_row_number
+#define png_get_error_ptr fltk_png_get_error_ptr
#define png_get_eXIf fltk_png_get_eXIf
#define png_get_eXIf_1 fltk_png_get_eXIf_1
-#define png_get_error_ptr fltk_png_get_error_ptr
#define png_get_filter_type fltk_png_get_filter_type
#define png_get_gAMA fltk_png_get_gAMA
#define png_get_gAMA_fixed fltk_png_get_gAMA_fixed
-#define png_get_hIST fltk_png_get_hIST
#define png_get_header_ver fltk_png_get_header_ver
#define png_get_header_version fltk_png_get_header_version
+#define png_get_hIST fltk_png_get_hIST
#define png_get_iCCP fltk_png_get_iCCP
+#define png_get_IHDR fltk_png_get_IHDR
#define png_get_image_height fltk_png_get_image_height
#define png_get_image_width fltk_png_get_image_width
#define png_get_int_32 fltk_png_get_int_32
@@ -281,16 +292,19 @@
#define png_get_io_ptr fltk_png_get_io_ptr
#define png_get_io_state fltk_png_get_io_state
#define png_get_libpng_ver fltk_png_get_libpng_ver
+#define png_get_mDCV fltk_png_get_mDCV
+#define png_get_mDCV_fixed fltk_png_get_mDCV_fixed
#define png_get_mem_ptr fltk_png_get_mem_ptr
#define png_get_oFFs fltk_png_get_oFFs
+#define png_get_palette_max fltk_png_get_palette_max
#define png_get_pCAL fltk_png_get_pCAL
#define png_get_pHYs fltk_png_get_pHYs
#define png_get_pHYs_dpi fltk_png_get_pHYs_dpi
-#define png_get_palette_max fltk_png_get_palette_max
#define png_get_pixel_aspect_ratio fltk_png_get_pixel_aspect_ratio
#define png_get_pixel_aspect_ratio_fixed fltk_png_get_pixel_aspect_ratio_fixed
#define png_get_pixels_per_inch fltk_png_get_pixels_per_inch
#define png_get_pixels_per_meter fltk_png_get_pixels_per_meter
+#define png_get_PLTE fltk_png_get_PLTE
#define png_get_progressive_ptr fltk_png_get_progressive_ptr
#define png_get_rgb_to_gray_status fltk_png_get_rgb_to_gray_status
#define png_get_rowbytes fltk_png_get_rowbytes
@@ -299,12 +313,12 @@
#define png_get_sCAL fltk_png_get_sCAL
#define png_get_sCAL_fixed fltk_png_get_sCAL_fixed
#define png_get_sCAL_s fltk_png_get_sCAL_s
+#define png_get_signature fltk_png_get_signature
#define png_get_sPLT fltk_png_get_sPLT
#define png_get_sRGB fltk_png_get_sRGB
-#define png_get_signature fltk_png_get_signature
+#define png_get_text fltk_png_get_text
#define png_get_tIME fltk_png_get_tIME
#define png_get_tRNS fltk_png_get_tRNS
-#define png_get_text fltk_png_get_text
#define png_get_uint_16 fltk_png_get_uint_16
#define png_get_uint_31 fltk_png_get_uint_31
#define png_get_uint_32 fltk_png_get_uint_32
@@ -357,23 +371,24 @@
#define png_save_int_32 fltk_png_save_int_32
#define png_save_uint_16 fltk_png_save_uint_16
#define png_save_uint_32 fltk_png_save_uint_32
-#define png_set_IHDR fltk_png_set_IHDR
-#define png_set_PLTE fltk_png_set_PLTE
#define png_set_add_alpha fltk_png_set_add_alpha
#define png_set_alpha_mode fltk_png_set_alpha_mode
#define png_set_alpha_mode_fixed fltk_png_set_alpha_mode_fixed
-#define png_set_bKGD fltk_png_set_bKGD
#define png_set_background fltk_png_set_background
#define png_set_background_fixed fltk_png_set_background_fixed
#define png_set_benign_errors fltk_png_set_benign_errors
#define png_set_bgr fltk_png_set_bgr
+#define png_set_bKGD fltk_png_set_bKGD
+#define png_set_check_for_invalid_index fltk_png_set_check_for_invalid_index
#define png_set_cHRM fltk_png_set_cHRM
+#define png_set_cHRM_fixed fltk_png_set_cHRM_fixed
#define png_set_cHRM_XYZ fltk_png_set_cHRM_XYZ
#define png_set_cHRM_XYZ_fixed fltk_png_set_cHRM_XYZ_fixed
-#define png_set_cHRM_fixed fltk_png_set_cHRM_fixed
-#define png_set_check_for_invalid_index fltk_png_set_check_for_invalid_index
#define png_set_chunk_cache_max fltk_png_set_chunk_cache_max
#define png_set_chunk_malloc_max fltk_png_set_chunk_malloc_max
+#define png_set_cICP fltk_png_set_cICP
+#define png_set_cLLI fltk_png_set_cLLI
+#define png_set_cLLI_fixed fltk_png_set_cLLI_fixed
#define png_set_compression_buffer_size fltk_png_set_compression_buffer_size
#define png_set_compression_level fltk_png_set_compression_level
#define png_set_compression_mem_level fltk_png_set_compression_mem_level
@@ -381,9 +396,9 @@
#define png_set_compression_strategy fltk_png_set_compression_strategy
#define png_set_compression_window_bits fltk_png_set_compression_window_bits
#define png_set_crc_action fltk_png_set_crc_action
+#define png_set_error_fn fltk_png_set_error_fn
#define png_set_eXIf fltk_png_set_eXIf
#define png_set_eXIf_1 fltk_png_set_eXIf_1
-#define png_set_error_fn fltk_png_set_error_fn
#define png_set_expand fltk_png_set_expand
#define png_set_expand_16 fltk_png_set_expand_16
#define png_set_expand_gray_1_2_4_to_8 fltk_png_set_expand_gray_1_2_4_to_8
@@ -399,20 +414,24 @@
#define png_set_gray_to_rgb fltk_png_set_gray_to_rgb
#define png_set_hIST fltk_png_set_hIST
#define png_set_iCCP fltk_png_set_iCCP
+#define png_set_IHDR fltk_png_set_IHDR
#define png_set_interlace_handling fltk_png_set_interlace_handling
#define png_set_invalid fltk_png_set_invalid
#define png_set_invert_alpha fltk_png_set_invert_alpha
#define png_set_invert_mono fltk_png_set_invert_mono
#define png_set_keep_unknown_chunks fltk_png_set_keep_unknown_chunks
#define png_set_longjmp_fn fltk_png_set_longjmp_fn
+#define png_set_mDCV fltk_png_set_mDCV
+#define png_set_mDCV_fixed fltk_png_set_mDCV_fixed
#define png_set_mem_fn fltk_png_set_mem_fn
#define png_set_oFFs fltk_png_set_oFFs
#define png_set_option fltk_png_set_option
-#define png_set_pCAL fltk_png_set_pCAL
-#define png_set_pHYs fltk_png_set_pHYs
#define png_set_packing fltk_png_set_packing
#define png_set_packswap fltk_png_set_packswap
#define png_set_palette_to_rgb fltk_png_set_palette_to_rgb
+#define png_set_pCAL fltk_png_set_pCAL
+#define png_set_pHYs fltk_png_set_pHYs
+#define png_set_PLTE fltk_png_set_PLTE
#define png_set_progressive_read_fn fltk_png_set_progressive_read_fn
#define png_set_quantize fltk_png_set_quantize
#define png_set_read_fn fltk_png_set_read_fn
@@ -426,25 +445,25 @@
#define png_set_sCAL fltk_png_set_sCAL
#define png_set_sCAL_fixed fltk_png_set_sCAL_fixed
#define png_set_sCAL_s fltk_png_set_sCAL_s
-#define png_set_sPLT fltk_png_set_sPLT
-#define png_set_sRGB fltk_png_set_sRGB
-#define png_set_sRGB_gAMA_and_cHRM fltk_png_set_sRGB_gAMA_and_cHRM
#define png_set_scale_16 fltk_png_set_scale_16
#define png_set_shift fltk_png_set_shift
#define png_set_sig_bytes fltk_png_set_sig_bytes
+#define png_set_sPLT fltk_png_set_sPLT
+#define png_set_sRGB fltk_png_set_sRGB
+#define png_set_sRGB_gAMA_and_cHRM fltk_png_set_sRGB_gAMA_and_cHRM
#define png_set_strip_16 fltk_png_set_strip_16
#define png_set_strip_alpha fltk_png_set_strip_alpha
#define png_set_swap fltk_png_set_swap
#define png_set_swap_alpha fltk_png_set_swap_alpha
-#define png_set_tIME fltk_png_set_tIME
-#define png_set_tRNS fltk_png_set_tRNS
-#define png_set_tRNS_to_alpha fltk_png_set_tRNS_to_alpha
#define png_set_text fltk_png_set_text
#define png_set_text_compression_level fltk_png_set_text_compression_level
#define png_set_text_compression_mem_level fltk_png_set_text_compression_mem_level
#define png_set_text_compression_method fltk_png_set_text_compression_method
#define png_set_text_compression_strategy fltk_png_set_text_compression_strategy
#define png_set_text_compression_window_bits fltk_png_set_text_compression_window_bits
+#define png_set_tIME fltk_png_set_tIME
+#define png_set_tRNS fltk_png_set_tRNS
+#define png_set_tRNS_to_alpha fltk_png_set_tRNS_to_alpha
#define png_set_unknown_chunk_location fltk_png_set_unknown_chunk_location
#define png_set_unknown_chunks fltk_png_set_unknown_chunks
#define png_set_user_limits fltk_png_set_user_limits
diff --git png/pngmem.c png/pngmem.c
index 09ed9c1..71e61c9 100644
--- png/pngmem.c
+++ png/pngmem.c
@@ -1,7 +1,6 @@
-
/* pngmem.c - stub functions for memory allocation
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -73,30 +72,29 @@ png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),
* 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) ||\
diff --git png/pngpread.c png/pngpread.c
index ffab19c..37aa432 100644
--- png/pngpread.c
+++ png/pngpread.c
@@ -1,7 +1,6 @@
-
/* pngpread.c - read a png file in push mode
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -32,6 +31,21 @@ if (png_ptr->push_length + 4 > png_ptr->buffer_size) \
if (png_ptr->buffer_size < N) \
{ png_push_save_buffer(png_ptr); return; }
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
+
+/* Start of interlace block */
+static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+/* Offset to next interlace block */
+static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+/* Start of interlace block in the y direction */
+static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+/* Offset to next interlace block in the y direction */
+static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+
+/* TODO: Move these arrays to a common utility module to avoid duplication. */
+#endif
+
void PNGAPI
png_process_data(png_structrp png_ptr, png_inforp info_ptr,
png_bytep buffer, size_t buffer_size)
@@ -179,17 +193,8 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
*/
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;
}
@@ -224,19 +229,27 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_benign_error(png_ptr, "Too many IDATs found");
}
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
+ {
+ /* These flags must be set consistently for all non-IDAT chunks,
+ * including the unknown chunks.
+ */
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
+ }
+
if (chunk_name == png_IHDR)
{
if (png_ptr->push_length != 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);
@@ -253,12 +266,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
}
#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;
@@ -271,155 +278,10 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
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_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;
@@ -976,27 +838,6 @@ png_push_process_row(png_structrp png_ptr)
void /* PRIVATE */
png_read_push_finish_row(png_structrp png_ptr)
{
-#ifdef PNG_READ_INTERLACING_SUPPORTED
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- static const png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- static const png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
-
- /* Height of interlace block. This is not currently used - if you need
- * it, uncomment it here and in png.h
- static const png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
- */
-#endif
-
png_ptr->row_number++;
if (png_ptr->row_number < png_ptr->num_rows)
return;
diff --git png/pngprefix.h png/pngprefix.h
index 9fcc0ad..26d8715 100644
--- png/pngprefix.h
+++ png/pngprefix.h
@@ -4,6 +4,7 @@
#define png_zstream_error fltk_png_zstream_error
#define png_free_buffer_list fltk_png_free_buffer_list
#define png_fixed fltk_png_fixed
+#define png_fixed_ITU fltk_png_fixed_ITU
#define png_user_version_check fltk_png_user_version_check
#define png_malloc_base fltk_png_malloc_base
#define png_malloc_array fltk_png_malloc_array
@@ -24,7 +25,6 @@
#define png_read_data fltk_png_read_data
#define png_crc_read fltk_png_crc_read
#define png_crc_finish fltk_png_crc_finish
-#define png_crc_error fltk_png_crc_error
#define png_calculate_crc fltk_png_calculate_crc
#define png_flush fltk_png_flush
#define png_write_IHDR fltk_png_write_IHDR
@@ -34,6 +34,9 @@
#define png_write_gAMA_fixed fltk_png_write_gAMA_fixed
#define png_write_sBIT fltk_png_write_sBIT
#define png_write_cHRM_fixed fltk_png_write_cHRM_fixed
+#define png_write_cICP fltk_png_write_cICP
+#define png_write_cLLI_fixed fltk_png_write_cLLI_fixed
+#define png_write_mDCV_fixed fltk_png_write_mDCV_fixed
#define png_write_sRGB fltk_png_write_sRGB
#define png_write_eXIf fltk_png_write_eXIf
#define png_write_iCCP fltk_png_write_iCCP
@@ -75,30 +78,8 @@
#define png_do_packswap fltk_png_do_packswap
#define png_do_invert fltk_png_do_invert
#define png_do_bgr fltk_png_do_bgr
-#define png_handle_IHDR fltk_png_handle_IHDR
-#define png_handle_PLTE fltk_png_handle_PLTE
-#define png_handle_IEND fltk_png_handle_IEND
-#define png_handle_bKGD fltk_png_handle_bKGD
-#define png_handle_cHRM fltk_png_handle_cHRM
-#define png_handle_eXIf fltk_png_handle_eXIf
-#define png_handle_gAMA fltk_png_handle_gAMA
-#define png_handle_hIST fltk_png_handle_hIST
-#define png_handle_iCCP fltk_png_handle_iCCP
-#define png_handle_iTXt fltk_png_handle_iTXt
-#define png_handle_oFFs fltk_png_handle_oFFs
-#define png_handle_pCAL fltk_png_handle_pCAL
-#define png_handle_pHYs fltk_png_handle_pHYs
-#define png_handle_sBIT fltk_png_handle_sBIT
-#define png_handle_sCAL fltk_png_handle_sCAL
-#define png_handle_sPLT fltk_png_handle_sPLT
-#define png_handle_sRGB fltk_png_handle_sRGB
-#define png_handle_tEXt fltk_png_handle_tEXt
-#define png_handle_tIME fltk_png_handle_tIME
-#define png_handle_tRNS fltk_png_handle_tRNS
-#define png_handle_zTXt fltk_png_handle_zTXt
-#define png_check_chunk_name fltk_png_check_chunk_name
-#define png_check_chunk_length fltk_png_check_chunk_length
#define png_handle_unknown fltk_png_handle_unknown
+#define png_handle_chunk fltk_png_handle_chunk
#define png_chunk_unknown_handling fltk_png_chunk_unknown_handling
#define png_do_read_transformations fltk_png_do_read_transformations
#define png_do_write_transformations fltk_png_do_write_transformations
@@ -111,31 +92,16 @@
#define png_push_read_IDAT fltk_png_push_read_IDAT
#define png_process_IDAT_data fltk_png_process_IDAT_data
#define png_push_process_row fltk_png_push_process_row
-#define png_push_handle_unknown fltk_png_push_handle_unknown
#define png_push_have_info fltk_png_push_have_info
#define png_push_have_end fltk_png_push_have_end
#define png_push_have_row fltk_png_push_have_row
#define png_push_read_end fltk_png_push_read_end
#define png_process_some_data fltk_png_process_some_data
#define png_read_push_finish_row fltk_png_read_push_finish_row
-#define png_push_handle_tEXt fltk_png_push_handle_tEXt
-#define png_push_read_tEXt fltk_png_push_read_tEXt
-#define png_push_handle_zTXt fltk_png_push_handle_zTXt
-#define png_push_read_zTXt fltk_png_push_read_zTXt
-#define png_push_handle_iTXt fltk_png_push_handle_iTXt
-#define png_push_read_iTXt fltk_png_push_read_iTXt
-#define png_colorspace_set_gamma fltk_png_colorspace_set_gamma
-#define png_colorspace_sync_info fltk_png_colorspace_sync_info
-#define png_colorspace_sync fltk_png_colorspace_sync
-#define png_colorspace_set_chromaticities fltk_png_colorspace_set_chromaticities
-#define png_colorspace_set_endpoints fltk_png_colorspace_set_endpoints
-#define png_colorspace_set_sRGB fltk_png_colorspace_set_sRGB
-#define png_colorspace_set_ICC fltk_png_colorspace_set_ICC
#define png_icc_check_length fltk_png_icc_check_length
#define png_icc_check_header fltk_png_icc_check_header
#define png_icc_check_tag_table fltk_png_icc_check_tag_table
-#define png_icc_set_sRGB fltk_png_icc_set_sRGB
-#define png_colorspace_set_rgb_coefficients fltk_png_colorspace_set_rgb_coefficients
+#define png_set_rgb_coefficients fltk_png_set_rgb_coefficients
#define png_check_IHDR fltk_png_check_IHDR
#define png_do_check_palette_indexes fltk_png_do_check_palette_indexes
#define png_fixed_error fltk_png_fixed_error
@@ -153,15 +119,18 @@
#define png_check_fp_number fltk_png_check_fp_number
#define png_check_fp_string fltk_png_check_fp_string
#define png_muldiv fltk_png_muldiv
-#define png_muldiv_warn fltk_png_muldiv_warn
#define png_reciprocal fltk_png_reciprocal
#define png_reciprocal2 fltk_png_reciprocal2
#define png_gamma_significant fltk_png_gamma_significant
+#define png_resolve_file_gamma fltk_png_resolve_file_gamma
#define png_gamma_correct fltk_png_gamma_correct
#define png_gamma_16bit_correct fltk_png_gamma_16bit_correct
#define png_gamma_8bit_correct fltk_png_gamma_8bit_correct
#define png_destroy_gamma_table fltk_png_destroy_gamma_table
#define png_build_gamma_table fltk_png_build_gamma_table
+#define png_set_rgb_coefficients fltk_png_set_rgb_coefficients
+#define png_XYZ_from_xy fltk_png_XYZ_from_xy
+#define png_xy_from_XYZ fltk_png_xy_from_XYZ
#define png_safe_error fltk_png_safe_error
#define png_safe_warning fltk_png_safe_warning
#define png_safe_execute fltk_png_safe_execute
diff --git png/pngpriv.h png/pngpriv.h
index b59084e..e3054b9 100644
--- png/pngpriv.h
+++ png/pngpriv.h
@@ -1,7 +1,6 @@
-
/* pngpriv.h - private declarations for use inside libpng
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -20,8 +19,20 @@
* they should be well aware of the issues that may arise from doing so.
*/
+
+/* pngpriv.h must be included first in each translation unit inside libpng.
+ * On the other hand, it must not be included at all, directly or indirectly,
+ * by any application code that uses the libpng API.
+ */
#ifndef PNGPRIV_H
-#define PNGPRIV_H
+# define PNGPRIV_H
+#else
+# error Duplicate inclusion of pngpriv.h; please check the libpng source files
+#endif
+
+#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H)
+# error This file must not be included by applications; please include <png.h>
+#endif
/* Feature Test Macros. The following are defined here to ensure that correctly
* implemented libraries reveal the APIs libpng needs to build and hide those
@@ -58,7 +69,6 @@
*/
#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
# include <config.h>
-
/* Pick up the definition of 'restrict' from config.h if it was read: */
# define PNG_RESTRICT restrict
#endif
@@ -68,9 +78,7 @@
* are not internal definitions may be required. This is handled below just
* before png.h is included, but load the configuration now if it is available.
*/
-#ifndef PNGLCONF_H
-# include "pnglibconf.h"
-#endif
+#include "pnglibconf.h"
/* Local renames may change non-exported API functions from png.h */
#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
@@ -135,6 +143,20 @@
# endif
#endif
+#ifndef PNG_RISCV_RVV_OPT
+ /* RISCV_RVV optimizations are being controlled by the compiler settings,
+ * typically the target compiler will define __riscv but the rvv extension
+ * availability has to be explicitly stated. This is why if no
+ * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed.
+ *
+ * To enable RISCV_RVV optimizations unconditionally, and compile the
+ * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on
+ * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS.
+ */
+
+# define PNG_RISCV_RVV_OPT 0
+#endif
+
#if PNG_ARM_NEON_OPT > 0
/* NEON optimizations are to be at least considered by libpng, so enable the
* callbacks to do this.
@@ -280,6 +302,16 @@
# define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
#endif
+#if PNG_RISCV_RVV_OPT > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv
+# ifndef PNG_RISCV_RVV_IMPLEMENTATION
+ /* Use the intrinsics code by default. */
+# define PNG_RISCV_RVV_IMPLEMENTATION 1
+# endif
+#else
+# define PNG_RISCV_RVV_IMPLEMENTATION 0
+#endif
+
/* Is this a build of a DLL where compilation of the object modules requires
* different preprocessor settings to those required for a simple library? If
* so PNG_BUILD_DLL must be set.
@@ -672,7 +704,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 */
@@ -783,6 +815,8 @@
#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED
#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\
((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))
+#define png_fixed_ITU(png_ptr, fp, s) ((fp) <= 214748 && (fp) >= 0 ?\
+ ((png_uint_32)(10000 * (fp))) : (png_fixed_error(png_ptr, s),0))
#endif
/* else the corresponding function is defined below, inside the scope of the
* cplusplus test.
@@ -801,11 +835,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.
@@ -833,9 +887,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)
@@ -844,6 +903,7 @@
#define png_hIST PNG_U32(104, 73, 83, 84)
#define png_iCCP PNG_U32(105, 67, 67, 80)
#define png_iTXt PNG_U32(105, 84, 88, 116)
+#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */
#define png_oFFs PNG_U32(111, 70, 70, 115)
#define png_pCAL PNG_U32(112, 67, 65, 76)
#define png_pHYs PNG_U32(112, 72, 89, 115)
@@ -884,11 +944,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.
*/
@@ -901,17 +1024,15 @@
* must match that used in the build, or we must be using pnglibconf.h.prebuilt:
*/
#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
-# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
- "-I (include path) error: see the notes in pngpriv.h"
- /* This means that when pnglibconf.h was built the copy of zlib.h that it
- * used is not the same as the one being used here. Because the build of
- * libpng makes decisions to use inflateInit2 and inflateReset2 based on the
- * zlib version number and because this affects handling of certain broken
- * PNG files the -I directives must match.
+# error The include path of <zlib.h> is incorrect
+ /* When pnglibconf.h was built, the copy of zlib.h that it used was not the
+ * same as the one being used here. Considering how libpng makes decisions
+ * to use the zlib API based on the zlib version number, the -I options must
+ * match.
*
- * The most likely explanation is that you passed a -I in CFLAGS. This will
- * not work; all the preprocessor directives and in particular all the -I
- * directives must be in CPPFLAGS.
+ * A possible cause of this mismatch is that you passed an -I option in
+ * CFLAGS, which is unlikely to work. All the preprocessor options, and all
+ * the -I options in particular, should be in CPPFLAGS.
*/
#endif
@@ -952,7 +1073,6 @@ extern "C" {
*
* 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),
@@ -971,6 +1091,7 @@ PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
(defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_mDCV_SUPPORTED) || \
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \
(defined(PNG_sCAL_SUPPORTED) && \
defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
@@ -978,12 +1099,38 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,
double fp, png_const_charp text),PNG_EMPTY);
#endif
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
+ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
+ (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
+PNG_INTERNAL_FUNCTION(png_uint_32,png_fixed_ITU,(png_const_structrp png_ptr,
+ double fp, png_const_charp text),PNG_EMPTY);
+#endif
+
/* Check the user version string for compatibility, returns false if the version
* numbers aren't compatible.
*/
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.)
@@ -1083,9 +1230,6 @@ PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,
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.
@@ -1131,6 +1275,26 @@ PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,
/* The xy value must have been previously validated */
#endif
+#ifdef PNG_WRITE_cICP_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr,
+ png_byte colour_primaries, png_byte transfer_function,
+ png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_cLLI_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_cLLI_fixed,(png_structrp png_ptr,
+ png_uint_32 maxCLL, png_uint_32 maxFALL), PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_mDCV_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_mDCV_fixed,(png_structrp png_ptr,
+ png_uint_16 red_x, png_uint_16 red_y,
+ png_uint_16 green_x, png_uint_16 green_y,
+ png_uint_16 blue_x, png_uint_16 blue_y,
+ png_uint_16 white_x, png_uint_16 white_y,
+ png_uint_32 maxDL, png_uint_32 minDL), PNG_EMPTY);
+#endif
+
#ifdef PNG_WRITE_sRGB_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
int intent),PNG_EMPTY);
@@ -1143,10 +1307,10 @@ PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,
#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
@@ -1382,6 +1546,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
#endif
+#if PNG_RISCV_RVV_OPT > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
/* Choose the best filter to use and filter the row data */
PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
png_row_infop row_info),PNG_EMPTY);
@@ -1455,119 +1636,36 @@ PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,
/* The following decodes the appropriate chunks, and does error correction,
* then calls the appropriate callback for the chunk if it is valid.
*/
-
-/* 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_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_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);
+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;
+
+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
* 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,
@@ -1607,8 +1705,6 @@ PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr,
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,
@@ -1621,109 +1717,28 @@ PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr,
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,
@@ -1985,8 +2000,10 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
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)
@@ -1995,22 +2012,14 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
*/
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.
*/
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
@@ -2019,14 +2028,22 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
*/
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.
@@ -2044,6 +2061,22 @@ PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),
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 */
@@ -2142,6 +2175,11 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
#endif
+# if PNG_RISCV_RVV_OPT > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
png_const_charp key, png_bytep new_key), PNG_EMPTY);
@@ -2177,4 +2215,3 @@ PNG_INTERNAL_FUNCTION(int,
#endif
#endif /* PNG_VERSION_INFO_ONLY */
-#endif /* PNGPRIV_H */
diff --git png/pngread.c png/pngread.c
index 07a39df..212afb7 100644
--- png/pngread.c
+++ png/pngread.c
@@ -1,7 +1,6 @@
-
/* pngread.c - read a PNG file
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -132,14 +131,11 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
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)
@@ -156,8 +152,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
}
}
#endif
- else if (chunk_name == png_PLTE)
- png_handle_PLTE(png_ptr, info_ptr, length);
else if (chunk_name == png_IDAT)
{
@@ -165,99 +159,8 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
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_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_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 */
@@ -799,13 +702,18 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
png_uint_32 chunk_name = png_ptr->chunk_name;
if (chunk_name != png_IDAT)
- png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+ {
+ /* These flags must be set consistently for all non-IDAT chunks,
+ * including the unknown chunks.
+ */
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_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);
@@ -839,102 +747,9 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
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_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_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 */
@@ -999,7 +814,8 @@ png_read_destroy(png_structrp png_ptr)
#endif
#if defined(PNG_READ_EXPAND_SUPPORTED) && \
- defined(PNG_ARM_NEON_IMPLEMENTATION)
+ (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
+ defined(PNG_RISCV_RVV_IMPLEMENTATION))
png_free(png_ptr, png_ptr->riffled_palette);
png_ptr->riffled_palette = NULL;
#endif
@@ -1385,6 +1201,31 @@ png_image_format(png_structrp png_ptr)
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
@@ -1393,16 +1234,11 @@ png_image_format(png_structrp png_ptr)
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
@@ -1410,6 +1246,33 @@ png_gamma_not_sRGB(png_fixed_point g)
* 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);
@@ -1430,17 +1293,13 @@ png_image_read_header(png_voidp argument)
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
@@ -1475,7 +1334,7 @@ png_image_read_header(png_voidp argument)
#ifdef PNG_STDIO_SUPPORTED
int PNGAPI
-png_image_begin_read_from_stdio(png_imagep image, FILE* file)
+png_image_begin_read_from_stdio(png_imagep image, FILE *file)
{
if (image != NULL && image->version == PNG_IMAGE_VERSION)
{
@@ -1628,21 +1487,18 @@ png_image_skip_unused_chunks(png_structrp png_ptr)
* 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.
@@ -1671,7 +1527,15 @@ png_image_skip_unused_chunks(png_structrp png_ptr)
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)
@@ -2159,24 +2023,18 @@ png_image_read_colormap(png_voidp argument)
/* 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;
-
- else
- png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;
+ if (png_ptr->bit_depth == 16 &&
+ (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
+ png_ptr->default_gamma = PNG_GAMMA_LINEAR;
- png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
- }
+ else
+ png_ptr->default_gamma = PNG_GAMMA_sRGB_INVERSE;
/* 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
@@ -2554,6 +2412,8 @@ png_image_read_colormap(png_voidp argument)
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.
@@ -2568,10 +2428,13 @@ png_image_read_colormap(png_voidp argument)
* 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;
@@ -2603,8 +2466,8 @@ png_image_read_colormap(png_voidp argument)
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.
@@ -3735,6 +3598,12 @@ png_image_read_direct(png_voidp argument)
/* 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 &&
@@ -3790,8 +3659,9 @@ png_image_read_direct(png_voidp argument)
* yet; it's set below. png_struct::gamma, however, is set to the
* final value.
*/
- if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma,
- PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)
+ if (png_muldiv(>est, 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)
diff --git png/pngrio.c png/pngrio.c
index 7946358..b4a2161 100644
--- png/pngrio.c
+++ png/pngrio.c
@@ -1,7 +1,6 @@
-
/* pngrio.c - functions for data input
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -57,7 +56,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
/* fread() returns 0 on error, so it is OK to store this in a size_t
* instead of an int, which is what fread() actually returns.
*/
- check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
+ check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr));
if (check != length)
png_error(png_ptr, "Read Error");
diff --git png/pngrtran.c png/pngrtran.c
index 1526123..1809db7 100644
--- png/pngrtran.c
+++ png/pngrtran.c
@@ -1,7 +1,6 @@
-
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -29,6 +28,12 @@
# endif
#endif
+#ifdef PNG_RISCV_RVV_IMPLEMENTATION
+# if PNG_RISCV_RVV_IMPLEMENTATION == 1
+# define PNG_RISCV_RVV_INTRINSICS_AVAILABLE
+# endif
+#endif
+
#ifdef PNG_READ_SUPPORTED
/* Set the action on getting a CRC error for an ancillary or critical chunk. */
@@ -219,9 +224,59 @@ png_set_strip_alpha(png_structrp png_ptr)
#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
@@ -231,14 +286,6 @@ translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
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
@@ -280,6 +327,33 @@ convert_gamma_value(png_structrp png_ptr, double output_gamma)
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
@@ -287,31 +361,29 @@ void PNGFAPI
png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
png_fixed_point output_gamma)
{
- int compose = 0;
png_fixed_point file_gamma;
+ int compose = 0;
png_debug(1, "in png_set_alpha_mode_fixed");
if (png_rtran_ok(png_ptr, 0) == 0)
return;
- output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
-
- /* 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");
+ output_gamma = translate_gamma_flags(output_gamma, 1/*screen*/);
+ if (unsupported_gamma(png_ptr, output_gamma, 0/*error*/))
+ return;
/* 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:
@@ -362,17 +434,7 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
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
@@ -382,7 +444,7 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
{
/* 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;
@@ -820,8 +882,8 @@ png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
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
@@ -835,17 +897,19 @@ png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
* 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");
+
+ if (unsupported_gamma(png_ptr, file_gamma, 1/*warn*/) ||
+ unsupported_gamma(png_ptr, scrn_gamma, 1/*warn*/))
+ return;
- /* 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.
+ /* 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;
}
@@ -1023,26 +1087,9 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
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");
}
}
@@ -1283,6 +1330,80 @@ png_init_rgb_transformations(png_structrp png_ptr)
#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)
{
@@ -1302,59 +1423,22 @@ png_init_read_transformations(png_structrp png_ptr)
* 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_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);
+ if (png_init_gamma_values(png_ptr) != 0)
+ png_ptr->transformations |= PNG_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
@@ -1426,7 +1510,7 @@ png_init_read_transformations(png_structrp png_ptr)
* 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
@@ -1569,10 +1653,10 @@ png_init_read_transformations(png_structrp png_ptr)
*/
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 &&
@@ -1628,8 +1712,8 @@ png_init_read_transformations(png_structrp png_ptr)
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;
@@ -1737,8 +1821,8 @@ png_init_read_transformations(png_structrp png_ptr)
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;
@@ -1988,11 +2072,11 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
* 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)
diff --git png/pngrutil.c png/pngrutil.c
index d31dc21..e7c7bbe 100644
--- png/pngrutil.c
+++ png/pngrutil.c
@@ -1,7 +1,6 @@
-
/* pngrutil.c - utilities to read a PNG file
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -18,6 +17,26 @@
#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. */
+
+/* Start of interlace block */
+static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+/* Offset to next interlace block */
+static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+/* Start of interlace block in the y direction */
+static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+/* Offset to next interlace block in the y direction */
+static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+
+/* TODO: Move these arrays to a common utility module to avoid duplication. */
+#endif
+
png_uint_32 PNGAPI
png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
{
@@ -29,30 +48,6 @@ png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
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,
@@ -149,6 +144,38 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
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.
*/
@@ -156,33 +183,36 @@ png_uint_32 /* PRIVATE */
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);
-
- /* Check for too-large chunk length */
- png_check_chunk_length(png_ptr, length);
+ if (!check_chunk_name(chunk_name))
+ png_chunk_error(png_ptr, "bad header (invalid type)");
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
@@ -202,13 +232,85 @@ png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
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.
@@ -226,14 +328,24 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
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");
@@ -244,61 +356,29 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
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;
@@ -313,24 +393,17 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
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
@@ -617,16 +690,7 @@ png_decompress_chunk(png_structrp png_ptr,
* 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;
-
-# 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
+ png_alloc_size_t limit = png_chunk_max(png_ptr);
if (limit >= prefix_size + (terminate != 0))
{
@@ -831,9 +895,9 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,
}
#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];
@@ -843,12 +907,7 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_IHDR");
- if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)
- png_chunk_error(png_ptr, "out of place");
-
- /* Check the length */
- if (length != 13)
- png_chunk_error(png_ptr, "invalid");
+ /* Length and position are checked by the caller. */
png_ptr->mode |= PNG_HAVE_IHDR;
@@ -902,257 +961,196 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
- png_chunk_benign_error(png_ptr, "invalid");
+ /* 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;
- else
- png_chunk_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;
- return;
- }
+ unsigned i, j;
+ png_byte buf[3*PNG_MAX_PALETTE_LENGTH];
+ png_color palette[PNG_MAX_PALETTE_LENGTH];
- /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
- num = (int)length / 3;
+ /* 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);
- /* 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;
-
- if (num > max_palette_length)
- num = max_palette_length;
+ for (i = 0U, j = 0U; i < num; i++)
+ {
+ palette[i].red = buf[j++];
+ palette[i].green = buf[j++];
+ palette[i].blue = buf[j++];
+ }
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
- for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
- {
- png_byte buf[3];
+ /* A valid PLTE chunk has been read */
+ png_ptr->mode |= PNG_HAVE_PLTE;
- png_crc_read(png_ptr, buf, 3);
- pal_ptr->red = buf[0];
- pal_ptr->green = buf[1];
- pal_ptr->blue = buf[2];
- }
-#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];
+ /* 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;
}
-#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);
-
- /* 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;
-
- 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
+ return errmsg != NULL ? handled_error : handled_error;
}
-void /* PRIVATE */
+/* On read the IDAT chunk is always handled specially, even if marked for
+ * unknown handling (this is allowed), so:
+ */
+#define png_handle_IDAT NULL
+
+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;
-
- igamma = png_get_fixed_point(NULL, buf);
+#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*/
- 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;
@@ -1161,23 +1159,6 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -1190,25 +1171,25 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
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)
{
if (buf[i] == 0 || buf[i] > sample_depth)
{
png_chunk_benign_error(png_ptr, "invalid");
- return;
+ return handled_error;
}
}
@@ -1220,7 +1201,7 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_ptr->sig_bit.alpha = buf[3];
}
- else
+ else /* grayscale */
{
png_ptr->sig_bit.gray = buf[0];
png_ptr->sig_bit.red = buf[0];
@@ -1230,133 +1211,132 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
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 */
-png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
+static png_int_32
+png_get_int_32_checked(png_const_bytep buf, int *error)
{
- png_byte buf[32];
- png_xy xy;
+ png_uint_32 uval = png_get_uint_32(buf);
+ if ((uval & 0x80000000) == 0) /* non-negative */
+ return (png_int_32)uval;
- png_debug(1, "in png_handle_cHRM");
+ uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
+ if ((uval & 0x80000000) == 0) /* no overflow */
+ return -(png_int_32)uval;
- if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
- png_chunk_error(png_ptr, "missing IHDR");
+ /* This version of png_get_int_32 has a way of returning the error to the
+ * caller, so:
+ */
+ *error = 1;
+ return 0; /* Safe */
+}
- 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;
- }
+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];
- if (length != 32)
- {
- png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "invalid");
- return;
- }
+ png_debug(1, "in png_handle_cHRM");
png_crc_read(png_ptr, buf, 32);
if (png_crc_finish(png_ptr, 0) != 0)
- return;
+ return handled_error;
+
+ 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);
- 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);
-
- 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;
png_debug(1, "in png_handle_sRGB");
- 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 != 1)
- {
- png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "invalid");
- return;
- }
-
png_crc_read(png_ptr, &intent, 1);
if (png_crc_finish(png_ptr, 0) != 0)
- return;
+ return handled_error;
- /* 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.
+ /* 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 ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)
+ if (intent > 3/*PNGv3 spec*/)
{
- png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
- png_colorspace_sync(png_ptr, info_ptr);
- png_chunk_benign_error(png_ptr, "too many profiles");
- return;
+ png_chunk_benign_error(png_ptr, "invalid");
+ return handled_error;
}
- (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
- png_colorspace_sync(png_ptr, info_ptr);
+ 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.
+ */
+
+#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*/
+
+ 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 */
{
@@ -1365,44 +1345,10 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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];
@@ -1412,19 +1358,16 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
*/
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;
@@ -1461,15 +1404,14 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
*/
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
@@ -1479,7 +1421,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
@@ -1498,8 +1440,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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.
@@ -1531,13 +1472,6 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
@@ -1560,11 +1494,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
else
- {
- png_ptr->colorspace.flags |=
- PNG_COLORSPACE_INVALID;
errmsg = "out of memory";
- }
}
/* else the profile remains in the read
@@ -1572,13 +1502,10 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
* 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)
@@ -1619,22 +1546,21 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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 */
{
@@ -1655,43 +1581,24 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
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;
}
@@ -1702,7 +1609,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, skip) != 0)
- return;
+ return handled_error;
buffer[length] = 0;
@@ -1715,7 +1622,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
if (length < 2U || entry_start > buffer + (length - 2U))
{
png_warning(png_ptr, "malformed sPLT chunk");
- return;
+ return handled_error;
}
new_palette.depth = *entry_start++;
@@ -1729,7 +1636,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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);
@@ -1738,7 +1645,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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);
@@ -1749,10 +1656,9 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -1775,31 +1681,6 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -1807,34 +1688,20 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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];
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];
@@ -1843,7 +1710,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
- return;
+ return handled_error;
}
png_crc_read(png_ptr, buf, 2);
@@ -1859,7 +1726,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
- return;
+ return handled_error;
}
png_crc_read(png_ptr, buf, length);
@@ -1873,10 +1740,9 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
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 ||
@@ -1885,7 +1751,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
- return;
+ return handled_error;
}
png_crc_read(png_ptr, readbuf, length);
@@ -1896,13 +1762,13 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
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
@@ -1911,11 +1777,14 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
*/
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;
@@ -1924,27 +1793,17 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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))
- {
- 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_bKGD) != 0)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "duplicate");
- 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;
+ }
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
truelen = 1;
+ }
else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
truelen = 6;
@@ -1956,13 +1815,13 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
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
@@ -1978,7 +1837,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -1999,7 +1858,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
}
}
@@ -2017,7 +1876,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0)
{
png_chunk_benign_error(png_ptr, "invalid color");
- return;
+ return handled_error;
}
}
@@ -2029,75 +1888,174 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
png_set_bKGD(png_ptr, info_ptr, &background);
+ return handled_ok;
}
+#else
+# define png_handle_bKGD NULL
+#endif
+
+#ifdef PNG_READ_cICP_SUPPORTED
+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];
+
+ png_debug(1, "in png_handle_cICP");
+
+ png_crc_read(png_ptr, buf, 4);
+
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return handled_error;
+
+ png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]);
+
+ /* 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 */
+
+#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*/
+
+ return handled_ok;
+ PNG_UNUSED(length)
+}
+#else
+# define png_handle_cICP NULL
+#endif
+
+#ifdef PNG_READ_cLLI_SUPPORTED
+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];
+
+ png_debug(1, "in png_handle_cLLI");
+
+ png_crc_read(png_ptr, buf, 8);
+
+ if (png_crc_finish(png_ptr, 0) != 0)
+ 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
+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");
+
+ png_crc_read(png_ptr, buf, 24);
+
+ if (png_crc_finish(png_ptr, 0) != 0)
+ 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
+ * only two bytes so a <<1 is safe.
+ *
+ * WARNING: the PNG specification defines the cHRM chunk to **start** with
+ * the white point (x,y). The W3C PNG v3 specification puts the white point
+ * **after* R,G,B. The x,y values in mDCV are also scaled by 50,000 and
+ * stored in just two bytes, whereas those in cHRM are scaled by 100,000 and
+ * 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,
+ 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");
-
- if (length < 2)
- {
- png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "too short");
- return;
- }
+ buffer = png_read_buffer(png_ptr, length);
- else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)
+ if (buffer == NULL)
{
png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "duplicate");
- return;
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return handled_error;
}
- info_ptr->free_me |= PNG_FREE_EXIF;
+ png_crc_read(png_ptr, buffer, length);
- info_ptr->eXIf_buf = png_voidcast(png_bytep,
- png_malloc_warn(png_ptr, length));
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return handled_error;
- 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;
@@ -2105,25 +2063,13 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_hIST");
- 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->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 ;
+ /* 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 ;
if (length != num * 2 ||
num != (unsigned int)png_ptr->num_palette ||
@@ -2131,7 +2077,7 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
- return;
+ return handled_error;
}
for (i = 0; i < num; i++)
@@ -2143,14 +2089,17 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
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];
@@ -2159,44 +2108,24 @@ png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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];
@@ -2205,45 +2134,25 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -2253,40 +2162,22 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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 */
@@ -2302,7 +2193,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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");
@@ -2322,7 +2213,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
(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)
@@ -2341,7 +2232,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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. */
@@ -2359,20 +2250,29 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_free(png_ptr, params);
png_chunk_benign_error(png_ptr, "invalid data");
- return;
+ return handled_error;
}
}
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;
@@ -2380,55 +2280,29 @@ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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_chunk_benign_error(png_ptr, "out of memory");
png_crc_finish(png_ptr, length);
- return;
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return handled_error;
}
png_crc_read(png_ptr, buffer, length);
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
@@ -2457,15 +2331,22 @@ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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];
@@ -2473,30 +2354,17 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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];
@@ -2506,12 +2374,16 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -2528,45 +2400,31 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
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");
-
- 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, 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, skip) != 0)
- return;
+ return handled_error;
key = (png_charp)buffer;
key[length] = 0;
@@ -2585,14 +2443,19 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -2607,40 +2470,35 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
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");
-
- 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;
@@ -2693,8 +2551,10 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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";
}
}
@@ -2702,14 +2562,16 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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;
@@ -2724,37 +2586,31 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
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");
-
- 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;
@@ -2844,8 +2700,10 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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";
}
}
@@ -2854,7 +2712,10 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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
@@ -2862,7 +2723,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
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)
{
@@ -2870,16 +2731,6 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
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);
@@ -2918,11 +2769,11 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
#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");
@@ -2969,7 +2820,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
* 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)
@@ -3003,7 +2854,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
else /* chunk was handled */
{
- handled = 1;
+ handled = handled_ok;
/* Critical chunks can be safely discarded at this point. */
keep = PNG_HANDLE_CHUNK_NEVER;
}
@@ -3088,7 +2939,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
*/
png_set_unknown_chunks(png_ptr, info_ptr,
&png_ptr->unknown_chunk, 1);
- handled = 1;
+ handled = handled_saved;
# ifdef PNG_USER_LIMITS_SUPPORTED
break;
}
@@ -3114,79 +2965,267 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
#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.
*/
-
-void /* PRIVATE */
-png_check_chunk_name(png_const_structrp png_ptr, png_uint_32 chunk_name)
+static const struct
{
- int i;
- png_uint_32 cn=chunk_name;
-
- png_debug(1, "in png_check_chunk_name");
+ 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.
+ */
- for (i=1; i<=4; ++i)
+ /* 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] =
+{
+ /* 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 */
+
+#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
+
+ /* 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 */
+
+ PNG_KNOWN_CHUNKS
- if (c < 65 || c > 122 || (c > 90 && c < 97))
- png_chunk_error(png_ptr, "invalid chunk type");
+# undef PNG_CHUNK
- cn >>= 8;
+ 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;
-
-# 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)
+ /* 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);
+
+ 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);
+ }
+
+ /* 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))
+ {
+ 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);
+ }
}
- if (length > limit)
+ else if (handled >= handled_saved)
{
- png_debug2(0," length = %lu, limit = %lu",
- (unsigned long)length,(unsigned long)limit);
- png_benign_error(png_ptr, "chunk data is too large");
+ 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
@@ -3684,10 +3723,6 @@ void /* PRIVATE */
png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
png_uint_32 transformations /* Because these may affect the byte layout */)
{
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* Offset to next interlace block */
- static const unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
png_debug(1, "in png_do_read_interlace");
if (row != NULL && row_info != NULL)
{
@@ -4180,6 +4215,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
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;
@@ -4187,8 +4225,13 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
* 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;
@@ -4325,20 +4368,6 @@ png_read_finish_IDAT(png_structrp png_ptr)
void /* PRIVATE */
png_read_finish_row(png_structrp png_ptr)
{
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-
png_debug(1, "in png_read_finish_row");
png_ptr->row_number++;
if (png_ptr->row_number < png_ptr->num_rows)
@@ -4390,20 +4419,6 @@ png_read_finish_row(png_structrp png_ptr)
void /* PRIVATE */
png_read_start_row(png_structrp png_ptr)
{
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-
unsigned int max_pixel_depth;
size_t row_bytes;
diff --git png/pngset.c png/pngset.c
index eb1c8c7..3e63c27 100644
--- png/pngset.c
+++ png/pngset.c
@@ -1,7 +1,6 @@
-
/* pngset.c - storage of image information into info struct
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -42,27 +41,21 @@ png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
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
@@ -74,6 +67,7 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
png_fixed_point int_blue_Z)
{
png_XYZ XYZ;
+ png_xy xy;
png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
@@ -90,11 +84,14 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
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
@@ -134,6 +131,189 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
#endif /* cHRM */
+#ifdef PNG_cICP_SUPPORTED
+void PNGAPI
+png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_byte colour_primaries, png_byte transfer_function,
+ png_byte matrix_coefficients, png_byte video_full_range_flag)
+{
+ png_debug1(1, "in %s storage function", "cICP");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->cicp_colour_primaries = colour_primaries;
+ info_ptr->cicp_transfer_function = transfer_function;
+ info_ptr->cicp_matrix_coefficients = matrix_coefficients;
+ info_ptr->cicp_video_full_range_flag = video_full_range_flag;
+
+ if (info_ptr->cicp_matrix_coefficients != 0)
+ {
+ png_warning(png_ptr, "Invalid cICP matrix coefficients");
+ return;
+ }
+
+ info_ptr->valid |= PNG_INFO_cICP;
+}
+#endif /* cICP */
+
+#ifdef PNG_cLLI_SUPPORTED
+void PNGFAPI
+png_set_cLLI_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
+ /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
+ * 100,000 as in the case of png_fixed_point.
+ */
+ png_uint_32 maxCLL, png_uint_32 maxFALL)
+{
+ png_debug1(1, "in %s storage function", "cLLI");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* Check the light level range: */
+ if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
+ {
+ /* The limit is 200kcd/m2; somewhat bright but not inconceivable because
+ * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2.
+ *
+ * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
+ * 2kcd/m2.
+ */
+ png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ info_ptr->maxCLL = maxCLL;
+ info_ptr->maxFALL = maxFALL;
+ info_ptr->valid |= PNG_INFO_cLLI;
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_cLLI(png_const_structrp png_ptr, png_inforp info_ptr,
+ double maxCLL, double maxFALL)
+{
+ png_set_cLLI_fixed(png_ptr, info_ptr,
+ png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"),
+ png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)"));
+}
+# endif /* FLOATING_POINT */
+#endif /* cLLI */
+
+#ifdef PNG_mDCV_SUPPORTED
+static png_uint_16
+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
+ * png_fixed() internal function with regard to errors: it's an error on
+ * write, a chunk_benign_error on read: See the definition of
+ * png_chunk_report in pngpriv.h.
+ */
+ v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
+ if (v > 65535 || v < 0)
+ {
+ *error = 1;
+ return 0;
+ }
+
+ return (png_uint_16)/*SAFE*/v;
+}
+
+void PNGAPI
+png_set_mDCV_fixed(png_const_structrp png_ptr, png_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_uint_32 maxDL,
+ 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");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* Check the input values to ensure they are in the expected range: */
+ 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)
+ {
+ /* The limit is 200kcd/m2; somewhat bright but not inconceivable because
+ * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2.
+ *
+ * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
+ * 2kcd/m2.
+ */
+ png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ /* All values are safe, the settings are accepted.
+ *
+ * IMPLEMENTATION NOTE: in practice the values can be checked and assigned
+ * but the result is confusing if a writing app calls png_set_mDCV more than
+ * once, the second time with an invalid value. This approach is more
+ * obviously correct at the cost of typing and a very slight machine
+ * overhead.
+ */
+ info_ptr->mastering_red_x = rx;
+ info_ptr->mastering_red_y = ry;
+ info_ptr->mastering_green_x = gx;
+ info_ptr->mastering_green_y = gy;
+ info_ptr->mastering_blue_x = bx;
+ info_ptr->mastering_blue_y = by;
+ info_ptr->mastering_white_x = wx;
+ info_ptr->mastering_white_y = wy;
+ info_ptr->mastering_maxDL = maxDL;
+ info_ptr->mastering_minDL = minDL;
+ info_ptr->valid |= PNG_INFO_mDCV;
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_mDCV(png_const_structrp png_ptr, png_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 maxDL, double minDL)
+{
+ png_set_mDCV_fixed(png_ptr, info_ptr,
+ png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
+ png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
+ png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
+ png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
+ png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
+ png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
+ png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
+ png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
+ png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
+ png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
+}
+# endif /* FLOATING_POINT */
+#endif /* mDCV */
+
#ifdef PNG_eXIf_SUPPORTED
void PNGAPI
png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
@@ -185,8 +365,8 @@ png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
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
@@ -645,8 +825,8 @@ png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
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
@@ -658,15 +838,20 @@ png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
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);
+
+# ifdef PNG_gAMA_SUPPORTED
+ png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
+# endif /* gAMA */
- png_colorspace_sync_info(png_ptr, info_ptr);
+# 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 */
@@ -689,27 +874,6 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
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));
@@ -1395,11 +1559,14 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
static const png_byte chunks_to_ignore[] = {
98, 75, 71, 68, '\0', /* bKGD */
99, 72, 82, 77, '\0', /* cHRM */
+ 99, 73, 67, 80, '\0', /* cICP */
+ 99, 76, 76, 73, '\0', /* cLLI */
101, 88, 73, 102, '\0', /* eXIf */
103, 65, 77, 65, '\0', /* gAMA */
104, 73, 83, 84, '\0', /* hIST */
105, 67, 67, 80, '\0', /* iCCP */
105, 84, 88, 116, '\0', /* iTXt */
+ 109, 68, 67, 86, '\0', /* mDCV */
111, 70, 70, 115, '\0', /* oFFs */
112, 67, 65, 76, '\0', /* pCAL */
112, 72, 89, 115, '\0', /* pHYs */
@@ -1661,8 +1828,24 @@ png_set_chunk_malloc_max(png_structrp png_ptr,
{
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 */
diff --git png/pngstruct.h png/pngstruct.h
index e591d94..084422b 100644
--- png/pngstruct.h
+++ png/pngstruct.h
@@ -1,7 +1,6 @@
-
-/* pngstruct.h - header file for PNG reference library
+/* pngstruct.h - internal structures for libpng
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -11,11 +10,9 @@
* and license in png.h
*/
-/* The structure that holds the information to read and write PNG files.
- * The only people who need to care about what is inside of this are the
- * people who will be modifying the library for their own special needs.
- * It should NOT be accessed directly by an application.
- */
+#ifndef PNGPRIV_H
+# error This file must not be included by applications; please include <png.h>
+#endif
#ifndef PNGSTRUCT_H
#define PNGSTRUCT_H
@@ -70,13 +67,7 @@ typedef struct png_compression_buffer
/* 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)).
*/
@@ -97,48 +88,36 @@ typedef struct png_XYZ
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
-
- /* Flags are always defined to simplify the code. */
- png_uint_16 flags; /* As defined below */
-} png_colorspace, * PNG_RESTRICT png_colorspacerp;
+/* 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.
+ */
-typedef const png_colorspace * PNG_RESTRICT png_const_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 */
-/* 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 */
+#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 */
struct png_struct_def
{
@@ -210,6 +189,11 @@ struct png_struct_def
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 */
@@ -286,9 +270,16 @@ struct png_struct_def
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 */
@@ -300,7 +291,7 @@ struct png_struct_def
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 */
@@ -350,8 +341,8 @@ struct png_struct_def
/* 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 */
@@ -361,8 +352,8 @@ struct png_struct_def
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_* */
@@ -384,7 +375,8 @@ struct png_struct_def
/* New member added in libpng-1.6.36 */
#if defined(PNG_READ_EXPAND_SUPPORTED) && \
- defined(PNG_ARM_NEON_IMPLEMENTATION)
+ (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
+ defined(PNG_RISCV_RVV_IMPLEMENTATION))
png_bytep riffled_palette; /* buffer for accelerated palette expansion */
#endif
@@ -469,11 +461,5 @@ struct png_struct_def
/* 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 */
diff --git png/pngtrans.c png/pngtrans.c
index 62cb21e..222b498 100644
--- png/pngtrans.c
+++ png/pngtrans.c
@@ -1,4 +1,3 @@
-
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
* Copyright (c) 2018-2024 Cosmin Truta
diff --git png/pngwio.c png/pngwio.c
index 10e919d..96a3187 100644
--- png/pngwio.c
+++ png/pngwio.c
@@ -1,7 +1,6 @@
-
/* pngwio.c - functions for data output
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2014,2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -55,7 +54,7 @@ png_default_write_data(png_structp png_ptr, png_bytep data, size_t length)
if (png_ptr == NULL)
return;
- check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
+ check = fwrite(data, 1, length, (FILE *)png_ptr->io_ptr);
if (check != length)
png_error(png_ptr, "Write Error");
@@ -78,12 +77,12 @@ png_flush(png_structrp png_ptr)
void PNGCBAPI
png_default_flush(png_structp png_ptr)
{
- png_FILE_p io_ptr;
+ FILE *io_ptr;
if (png_ptr == NULL)
return;
- io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));
+ io_ptr = png_voidcast(FILE *, png_ptr->io_ptr);
fflush(io_ptr);
}
# endif
diff --git png/pngwrite.c png/pngwrite.c
index 77e412f..35a5d17 100644
--- png/pngwrite.c
+++ png/pngwrite.c
@@ -1,7 +1,6 @@
-
/* pngwrite.c - general routines to write a PNG file
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -128,61 +127,93 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
* the application continues writing the PNG. So check the 'invalid'
* flag here too.
*/
-#ifdef PNG_GAMMA_SUPPORTED
-# ifdef PNG_WRITE_gAMA_SUPPORTED
- 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);
-# endif
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ /* Write unknown chunks first; PNG v3 establishes a precedence order
+ * for colourspace chunks. It is certain therefore that new
+ * colourspace chunks will have a precedence and very likely it will be
+ * higher than all known so far. Writing the unknown chunks here is
+ * most likely to present the chunks in the most convenient order.
+ *
+ * FUTURE: maybe write chunks in the order the app calls png_set_chnk
+ * to give the app control.
+ */
+ write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
#endif
-#ifdef PNG_COLORSPACE_SUPPORTED
- /* Write only one of sRGB or an ICC profile. If a profile was supplied
- * and it matches one of the known sRGB ones issue a warning.
- */
-# ifdef PNG_WRITE_iCCP_SUPPORTED
- if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
- (info_ptr->valid & PNG_INFO_iCCP) != 0)
- {
-# ifdef PNG_WRITE_sRGB_SUPPORTED
- if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
- png_app_warning(png_ptr,
- "profile matches sRGB but writing iCCP instead");
-# endif
+#ifdef PNG_WRITE_sBIT_SUPPORTED
+ /* PNG v3: a streaming app will need to see this before cICP because
+ * the information is helpful in handling HLG encoding (which is
+ * natively 10 bits but gets expanded to 16 in PNG.)
+ *
+ * The app shouldn't care about the order ideally, but it might have
+ * no choice. In PNG v3, apps are allowed to reject PNGs where the
+ * APNG chunks are out of order so it behooves libpng to be nice here.
+ */
+ if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+#endif
+ /* PNG v3: the July 2004 version of the TR introduced the concept of colour
+ * space priority. As above it therefore behooves libpng to write the colour
+ * space chunks in the priority order so that a streaming app need not buffer
+ * them.
+ *
+ * PNG v3: Chunks mDCV and cLLI provide ancillary information for the
+ * interpretation of the colourspace chunkgs but do not require support for
+ * those chunks so are outside the "COLORSPACE" check but before the write of
+ * the colourspace chunks themselves.
+ */
+#ifdef PNG_WRITE_cLLI_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_cLLI) != 0)
+ {
+ png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL);
+ }
+#endif
+#ifdef PNG_WRITE_mDCV_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_mDCV) != 0)
+ {
+ png_write_mDCV_fixed(png_ptr,
+ info_ptr->mastering_red_x, info_ptr->mastering_red_y,
+ info_ptr->mastering_green_x, info_ptr->mastering_green_y,
+ info_ptr->mastering_blue_x, info_ptr->mastering_blue_y,
+ info_ptr->mastering_white_x, info_ptr->mastering_white_y,
+ info_ptr->mastering_maxDL, info_ptr->mastering_minDL);
+ }
+#endif
+
+# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */
+ if ((info_ptr->valid & PNG_INFO_cICP) != 0)
+ {
+ png_write_cICP(png_ptr,
+ info_ptr->cicp_colour_primaries,
+ info_ptr->cicp_transfer_function,
+ info_ptr->cicp_matrix_coefficients,
+ info_ptr->cicp_video_full_range_flag);
+ }
+# endif
+
+# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */
+ 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
- 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);
+# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */
+ if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
+ png_write_sRGB(png_ptr, info_ptr->rendering_intent);
# endif /* WRITE_sRGB */
-#endif /* COLORSPACE */
-#ifdef PNG_WRITE_sBIT_SUPPORTED
- if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
- png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
-#endif
-
-#ifdef PNG_COLORSPACE_SUPPORTED
-# ifdef PNG_WRITE_cHRM_SUPPORTED
- 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);
+# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */
+ if ((info_ptr->valid & PNG_INFO_gAMA) != 0)
+ png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
# endif
-#endif
-#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
- write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
-#endif
+# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */
+ if ((info_ptr->valid & PNG_INFO_cHRM) != 0)
+ png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM);
+# endif
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
}
@@ -2302,7 +2333,7 @@ int PNGAPI
png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
const void *buffer, png_int_32 row_stride, const void *colormap)
{
- /* Write the image to the given (FILE*). */
+ /* Write the image to the given FILE object. */
if (image != NULL && image->version == PNG_IMAGE_VERSION)
{
if (file != NULL && buffer != NULL)
diff --git png/pngwtran.c png/pngwtran.c
index 49a13c1..a208470 100644
--- png/pngwtran.c
+++ png/pngwtran.c
@@ -1,4 +1,3 @@
-
/* pngwtran.c - transforms the data in a row for PNG writers
*
* Copyright (c) 2018 Cosmin Truta
diff --git png/pngwutil.c png/pngwutil.c
index 14cc4ce..863ffe8 100644
--- png/pngwutil.c
+++ png/pngwutil.c
@@ -1,7 +1,6 @@
-
/* pngwutil.c - utilities to write a PNG file
*
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -9,12 +8,30 @@
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
+ *
+ * This file contains routines that are only called from within
+ * libpng itself during the course of writing an image.
*/
#include "pngpriv.h"
#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
+
+/* Start of interlace block */
+static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+/* Offset to next interlace block */
+static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+/* Start of interlace block in the y direction */
+static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+/* Offset to next interlace block in the y direction */
+static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+
+/* TODO: Move these arrays to a common utility module to avoid duplication. */
+#endif
+
#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
/* Place a 32-bit number into a buffer in PNG byte order. We work
* with unsigned numbers for convenience, although one supported
@@ -1115,10 +1132,9 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent)
/* 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;
@@ -1131,11 +1147,12 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name,
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)");
@@ -1471,6 +1488,73 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
}
#endif
+#ifdef PNG_WRITE_cICP_SUPPORTED
+/* Write the cICP data */
+void /* PRIVATE */
+png_write_cICP(png_structrp png_ptr,
+ png_byte colour_primaries, png_byte transfer_function,
+ png_byte matrix_coefficients, png_byte video_full_range_flag)
+{
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_cICP");
+
+ png_write_chunk_header(png_ptr, png_cICP, 4);
+
+ buf[0] = colour_primaries;
+ buf[1] = transfer_function;
+ buf[2] = matrix_coefficients;
+ buf[3] = video_full_range_flag;
+ png_write_chunk_data(png_ptr, buf, 4);
+
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#ifdef PNG_WRITE_cLLI_SUPPORTED
+void /* PRIVATE */
+png_write_cLLI_fixed(png_structrp png_ptr, png_uint_32 maxCLL,
+ png_uint_32 maxFALL)
+{
+ png_byte buf[8];
+
+ png_debug(1, "in png_write_cLLI_fixed");
+
+ png_save_uint_32(buf, maxCLL);
+ png_save_uint_32(buf + 4, maxFALL);
+
+ png_write_complete_chunk(png_ptr, png_cLLI, buf, 8);
+}
+#endif
+
+#ifdef PNG_WRITE_mDCV_SUPPORTED
+void /* PRIVATE */
+png_write_mDCV_fixed(png_structrp png_ptr,
+ png_uint_16 red_x, png_uint_16 red_y,
+ png_uint_16 green_x, png_uint_16 green_y,
+ png_uint_16 blue_x, png_uint_16 blue_y,
+ png_uint_16 white_x, png_uint_16 white_y,
+ png_uint_32 maxDL, png_uint_32 minDL)
+{
+ png_byte buf[24];
+
+ png_debug(1, "in png_write_mDCV_fixed");
+
+ png_save_uint_16(buf + 0, red_x);
+ png_save_uint_16(buf + 2, red_y);
+ png_save_uint_16(buf + 4, green_x);
+ png_save_uint_16(buf + 6, green_y);
+ png_save_uint_16(buf + 8, blue_x);
+ png_save_uint_16(buf + 10, blue_y);
+ png_save_uint_16(buf + 12, white_x);
+ png_save_uint_16(buf + 14, white_y);
+ png_save_uint_32(buf + 16, maxDL);
+ png_save_uint_32(buf + 20, minDL);
+
+ png_write_complete_chunk(png_ptr, png_mDCV, buf, 24);
+}
+#endif
+
#ifdef PNG_WRITE_eXIf_SUPPORTED
/* Write the Exif data */
void /* PRIVATE */
@@ -1889,22 +1973,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
void /* PRIVATE */
png_write_start_row(png_structrp png_ptr)
{
-#ifdef PNG_WRITE_INTERLACING_SUPPORTED
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
-
png_alloc_size_t buf_size;
int usr_pixel_depth;
@@ -2004,22 +2072,6 @@ png_write_start_row(png_structrp png_ptr)
void /* PRIVATE */
png_write_finish_row(png_structrp png_ptr)
{
-#ifdef PNG_WRITE_INTERLACING_SUPPORTED
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
-
png_debug(1, "in png_write_finish_row");
/* Next row */
@@ -2095,14 +2147,6 @@ png_write_finish_row(png_structrp png_ptr)
void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-
png_debug(1, "in png_do_write_interlace");
/* We don't have to do anything on the last pass (6) */
diff --git png/powerpc/filter_vsx_intrinsics.c png/powerpc/filter_vsx_intrinsics.c
index 01cf880..5acc17c 100644
--- png/powerpc/filter_vsx_intrinsics.c
+++ png/powerpc/filter_vsx_intrinsics.c
@@ -23,7 +23,7 @@
#if PNG_POWERPC_VSX_OPT > 0
#ifndef __VSX__
-# error "This code requires VSX support (POWER7 and later). Please provide -mvsx compiler flag."
+# error This code requires VSX support (POWER7 and later); please compile with -mvsx
#endif
#define vec_ld_unaligned(vec,data) vec = vec_vsx_ld(0,data)
diff --git png/powerpc/powerpc_init.c png/powerpc/powerpc_init.c
index 54426c5..70782ed 100644
--- png/powerpc/powerpc_init.c
+++ png/powerpc/powerpc_init.c
@@ -1,4 +1,3 @@
-
/* powerpc_init.c - POWERPC optimised filter functions
*
* Copyright (c) 2018 Cosmin Truta
@@ -47,7 +46,7 @@ static int png_have_vsx(png_structp png_ptr);
#include PNG_POWERPC_VSX_FILE
#else /* PNG_POWERPC_VSX_FILE */
-# error "PNG_POWERPC_VSX_FILE undefined: no support for run-time POWERPC VSX checks"
+# error PNG_POWERPC_VSX_FILE undefined: no support for run-time POWERPC VSX checks
#endif /* PNG_POWERPC_VSX_FILE */
#endif /* PNG_POWERPC_VSX_CHECK_SUPPORTED */
Comments are owned by the poster. All other content is copyright 1998-2025 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.