diff --git a/PDF/CMakeLists.txt b/PDF/CMakeLists.txt
index b2492487e..1e9ad9b18 100644
--- a/PDF/CMakeLists.txt
+++ b/PDF/CMakeLists.txt
@@ -139,7 +139,9 @@ if(POCO_UNBUNDLED)
target_link_libraries(PDF PUBLIC ZLIB::ZLIB)
target_link_libraries(PDF PUBLIC ${PNG_LIBRARY})
target_compile_definitions(PDF PUBLIC POCO_UNBUNDLED)
-
+else()
+ # libpng: Do not try to use ARM intrinsics on ARM architecture: source files not included
+ target_compile_definitions(PDF PRIVATE PNG_ARM_NEON_OPT=0)
endif(POCO_UNBUNDLED)
target_link_libraries(PDF PUBLIC Poco::XML Poco::Util)
diff --git a/PDF/include/Poco/PDF/png.h b/PDF/include/Poco/PDF/png.h
index 307244945..83d390312 100644
--- a/PDF/include/Poco/PDF/png.h
+++ b/PDF/include/Poco/PDF/png.h
@@ -1,18 +1,192 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.2.24 - December 14, 2007
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * libpng version 1.6.43
+ *
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license. (See LICENSE, below.)
*
* Authors and maintainers:
- * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
- * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.2.24 - December 14, 2007: Glenn
- * See also "Contributing Authors", below.
+ * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
+ * 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.43, February 2024:
+ * Cosmin Truta
+ * See also "Contributing Authors", below.
+ */
+
+/*
+ * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
+ * =========================================
*
- * Note about libpng version numbers:
+ * PNG Reference Library License version 2
+ * ---------------------------------------
+ *
+ * * Copyright (c) 1995-2024 The PNG Reference Library Authors.
+ * * Copyright (c) 2018-2024 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.
+ *
+ * The software is supplied "as is", without warranty of any kind,
+ * express or implied, including, without limitation, the warranties
+ * of merchantability, fitness for a particular purpose, title, and
+ * non-infringement. In no event shall the Copyright owners, or
+ * anyone distributing the software, be liable for any damages or
+ * other liability, whether in contract, tort or otherwise, arising
+ * from, out of, or in connection with the software, or the use or
+ * other dealings in the software, even if advised of the possibility
+ * of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute
+ * this software, or portions hereof, for any purpose, without fee,
+ * subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you
+ * must not claim that you wrote the original software. If you
+ * use this software in a product, an acknowledgment in the product
+ * documentation would be appreciated, but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 3. This Copyright notice may not be removed or altered from any
+ * source or altered source distribution.
+ *
+ *
+ * PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)
+ * -----------------------------------------------------------------------
+ *
+ * libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are
+ * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are
+ * derived from libpng-1.0.6, and are distributed according to the same
+ * disclaimer and license as libpng-1.0.6 with the following individuals
+ * added to the list of Contributing Authors:
+ *
+ * Simon-Pierre Cadieux
+ * Eric S. Raymond
+ * Mans Rullgard
+ * Cosmin Truta
+ * Gilles Vollant
+ * James Yu
+ * Mandar Sahastrabuddhe
+ * Google Inc.
+ * Vadim Barkov
+ *
+ * and with the following additions to the disclaimer:
+ *
+ * There is no warranty against interference with your enjoyment of
+ * the library or against infringement. There is no warranty that our
+ * efforts or the library will fulfill any of your particular purposes
+ * or needs. This library is provided with all faults, and the entire
+ * risk of satisfactory quality, performance, accuracy, and effort is
+ * with the user.
+ *
+ * Some files in the "contrib" directory and some configure-generated
+ * files that are distributed with libpng have other copyright owners, and
+ * are released under other open source licenses.
+ *
+ * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+ * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+ * libpng-0.96, and are distributed according to the same disclaimer and
+ * license as libpng-0.96, with the following individuals added to the
+ * list of Contributing Authors:
+ *
+ * Tom Lane
+ * Glenn Randers-Pehrson
+ * Willem van Schaik
+ *
+ * libpng versions 0.89, June 1996, through 0.96, May 1997, are
+ * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+ * and are distributed according to the same disclaimer and license as
+ * libpng-0.88, with the following individuals added to the list of
+ * Contributing Authors:
+ *
+ * John Bowler
+ * Kevin Bracey
+ * Sam Bushell
+ * Magnus Holmgren
+ * Greg Roelofs
+ * Tom Tanner
+ *
+ * Some files in the "scripts" directory have other copyright owners,
+ * but are released under this license.
+ *
+ * libpng versions 0.5, May 1995, through 0.88, January 1996, are
+ * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+ *
+ * For the purposes of this copyright and license, "Contributing Authors"
+ * is defined as the following set of individuals:
+ *
+ * Andreas Dilger
+ * Dave Martindale
+ * Guy Eric Schalnat
+ * Paul Schmidt
+ * Tim Wegner
+ *
+ * The PNG Reference Library is supplied "AS IS". The Contributing
+ * Authors and Group 42, Inc. disclaim all warranties, expressed or
+ * implied, including, without limitation, the warranties of
+ * merchantability and of fitness for any purpose. The Contributing
+ * Authors and Group 42, Inc. assume no liability for direct, indirect,
+ * incidental, special, exemplary, or consequential damages, which may
+ * result from the use of the PNG Reference Library, even if advised of
+ * the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ *
+ * 1. The origin of this source code must not be misrepresented.
+ *
+ * 2. Altered versions must be plainly marked as such and must not
+ * be misrepresented as being the original source.
+ *
+ * 3. This Copyright notice may not be removed or altered from any
+ * source or altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit,
+ * without fee, and encourage the use of this source code as a component
+ * to supporting the PNG file format in commercial products. If you use
+ * this source code in a product, acknowledgment is not required but would
+ * be appreciated.
+ *
+ * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.
+ *
+ * TRADEMARK
+ * =========
+ *
+ * The name "libpng" has not been registered by the Copyright owners
+ * as a trademark in any jurisdiction. However, because libpng has
+ * been distributed and maintained world-wide, continually since 1995,
+ * the Copyright owners claim "common-law trademark protection" in any
+ * jurisdiction where common-law trademark is recognized.
+ */
+
+/*
+ * A "png_get_copyright" function is available, for convenient use in "about"
+ * boxes and the like:
+ *
+ * printf("%s", png_get_copyright(NULL));
+ *
+ * Also, the PNG logo (in PNG format, of course) is supplied in the
+ * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+ */
+
+/*
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience. This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ */
+
+/* Note about libpng version numbers:
*
* Due to various miscommunications, unforeseen code incompatibilities
* and occasional factors outside the authors' control, version numbering
@@ -56,342 +230,67 @@
* 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible)
* 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible)
* 1.0.7 1 10007 (still compatible)
- * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4
- * 1.0.8rc1 1 10008 2.1.0.8rc1
- * 1.0.8 1 10008 2.1.0.8
- * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6
- * 1.0.9rc1 1 10009 2.1.0.9rc1
- * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10
- * 1.0.9rc2 1 10009 2.1.0.9rc2
- * 1.0.9 1 10009 2.1.0.9
- * 1.0.10beta1 1 10010 2.1.0.10beta1
- * 1.0.10rc1 1 10010 2.1.0.10rc1
- * 1.0.10 1 10010 2.1.0.10
- * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3
- * 1.0.11rc1 1 10011 2.1.0.11rc1
- * 1.0.11 1 10011 2.1.0.11
- * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2
- * 1.0.12rc1 2 10012 2.1.0.12rc1
- * 1.0.12 2 10012 2.1.0.12
- * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned)
- * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2
- * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5
- * 1.2.0rc1 3 10200 3.1.2.0rc1
- * 1.2.0 3 10200 3.1.2.0
- * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4
- * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2
- * 1.2.1 3 10201 3.1.2.1
- * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6
- * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1
- * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1
- * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1
- * 1.0.13 10 10013 10.so.0.1.0.13
- * 1.2.2 12 10202 12.so.0.1.2.2
- * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6
- * 1.2.3 12 10203 12.so.0.1.2.3
- * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3
- * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1
- * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1
- * 1.0.14 10 10014 10.so.0.1.0.14
- * 1.2.4 13 10204 12.so.0.1.2.4
- * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2
- * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3
- * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3
- * 1.0.15 10 10015 10.so.0.1.0.15
- * 1.2.5 13 10205 12.so.0.1.2.5
- * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4
- * 1.0.16 10 10016 10.so.0.1.0.16
- * 1.2.6 13 10206 12.so.0.1.2.6
- * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2
- * 1.0.17rc1 10 10017 10.so.0.1.0.17rc1
- * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1
- * 1.0.17 10 10017 10.so.0.1.0.17
- * 1.2.7 13 10207 12.so.0.1.2.7
- * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5
- * 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5
- * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5
- * 1.0.18 10 10018 10.so.0.1.0.18
- * 1.2.8 13 10208 12.so.0.1.2.8
- * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3
- * 1.2.9beta4-11 13 10209 12.so.0.9[.0]
- * 1.2.9rc1 13 10209 12.so.0.9[.0]
- * 1.2.9 13 10209 12.so.0.9[.0]
- * 1.2.10beta1-8 13 10210 12.so.0.10[.0]
- * 1.2.10rc1-3 13 10210 12.so.0.10[.0]
- * 1.2.10 13 10210 12.so.0.10[.0]
- * 1.2.11beta1-4 13 10211 12.so.0.11[.0]
- * 1.0.19rc1-5 10 10019 10.so.0.19[.0]
- * 1.2.11rc1-5 13 10211 12.so.0.11[.0]
- * 1.0.19 10 10019 10.so.0.19[.0]
- * 1.2.11 13 10211 12.so.0.11[.0]
- * 1.0.20 10 10020 10.so.0.20[.0]
- * 1.2.12 13 10212 12.so.0.12[.0]
- * 1.2.13beta1 13 10213 12.so.0.13[.0]
- * 1.0.21 10 10021 10.so.0.21[.0]
- * 1.2.13 13 10213 12.so.0.13[.0]
- * 1.2.14beta1-2 13 10214 12.so.0.14[.0]
- * 1.0.22rc1 10 10022 10.so.0.22[.0]
- * 1.2.14rc1 13 10214 12.so.0.14[.0]
- * 1.0.22 10 10022 10.so.0.22[.0]
- * 1.2.14 13 10214 12.so.0.14[.0]
- * 1.2.15beta1-6 13 10215 12.so.0.15[.0]
- * 1.0.23rc1-5 10 10023 10.so.0.23[.0]
- * 1.2.15rc1-5 13 10215 12.so.0.15[.0]
- * 1.0.23 10 10023 10.so.0.23[.0]
- * 1.2.15 13 10215 12.so.0.15[.0]
- * 1.2.16beta1-2 13 10216 12.so.0.16[.0]
- * 1.2.16rc1 13 10216 12.so.0.16[.0]
- * 1.0.24 10 10024 10.so.0.24[.0]
- * 1.2.16 13 10216 12.so.0.16[.0]
- * 1.2.17beta1-2 13 10217 12.so.0.17[.0]
- * 1.0.25rc1 10 10025 10.so.0.25[.0]
- * 1.2.17rc1-3 13 10217 12.so.0.17[.0]
- * 1.0.25 10 10025 10.so.0.25[.0]
- * 1.2.17 13 10217 12.so.0.17[.0]
- * 1.0.26 10 10026 10.so.0.26[.0]
- * 1.2.18 13 10218 12.so.0.18[.0]
- * 1.2.19beta1-31 13 10219 12.so.0.19[.0]
- * 1.0.27rc1-6 10 10027 10.so.0.27[.0]
- * 1.2.19rc1-6 13 10219 12.so.0.19[.0]
- * 1.0.27 10 10027 10.so.0.27[.0]
- * 1.2.19 13 10219 12.so.0.19[.0]
- * 1.2.20beta01-04 13 10220 12.so.0.20[.0]
- * 1.0.28rc1-6 10 10028 10.so.0.28[.0]
- * 1.2.20rc1-6 13 10220 12.so.0.20[.0]
- * 1.0.28 10 10028 10.so.0.28[.0]
- * 1.2.20 13 10220 12.so.0.20[.0]
- * 1.2.21beta1-2 13 10221 12.so.0.21[.0]
- * 1.2.21rc1-3 13 10221 12.so.0.21[.0]
- * 1.0.29 10 10029 10.so.0.29[.0]
- * 1.2.21 13 10221 12.so.0.21[.0]
- * 1.2.22beta1-4 13 10222 12.so.0.22[.0]
- * 1.0.30rc1 10 10030 10.so.0.30[.0]
- * 1.2.22rc1 13 10222 12.so.0.22[.0]
- * 1.0.30 10 10030 10.so.0.30[.0]
- * 1.2.22 13 10222 12.so.0.22[.0]
- * 1.2.23beta01-05 13 10223 12.so.0.23[.0]
- * 1.2.23rc01 13 10223 12.so.0.23[.0]
- * 1.2.23 13 10223 12.so.0.23[.0]
- * 1.2.24beta01-02 13 10224 12.so.0.24[.0]
- * 1.2.24rc01 13 10224 12.so.0.24[.0]
- * 1.2.24 13 10224 12.so.0.24[.0]
+ * ...
+ * 1.0.69 10 10069 10.so.0.69[.0]
+ * ...
+ * 1.2.59 13 10259 12.so.0.59[.0]
+ * ...
+ * 1.4.20 14 10420 14.so.0.20[.0]
+ * ...
+ * 1.5.30 15 10530 15.so.15.30[.0]
+ * ...
+ * 1.6.43 16 10643 16.so.16.43[.0]
*
- * Henceforth the source version will match the shared-library major
- * and minor numbers; the shared-library major version number will be
- * used for changes in backward compatibility, as it is intended. The
- * PNG_LIBPNG_VER macro, which is not used within libpng but is available
- * for applications, is an unsigned integer of the form xyyzz corresponding
- * to the source version x.y.z (leading zeros in y and z). Beta versions
- * were given the previous public release number plus a letter, until
- * version 1.0.6j; from then on they were given the upcoming public
- * release number plus "betaNN" or "rcN".
+ * Henceforth the source version will match the shared-library major and
+ * minor numbers; the shared-library major version number will be used for
+ * changes in backward compatibility, as it is intended.
+ * The PNG_LIBPNG_VER macro, which is not used within libpng but is
+ * available for applications, is an unsigned integer of the form XYYZZ
+ * corresponding to the source version X.Y.Z (leading zeros in Y and Z).
+ * Beta versions were given the previous public release number plus a
+ * letter, until version 1.0.6j; from then on they were given the upcoming
+ * public release number plus "betaNN" or "rcNN".
*
* Binary incompatibility exists only when applications make direct access
* to the info_ptr or png_ptr members through png.h, and the compiled
* application is loaded with a different version of the library.
*
- * DLLNUM will change each time there are forward or backward changes
- * in binary compatibility (e.g., when a new feature is added).
- *
* See libpng.txt or libpng.3 for more information. The PNG specification
- * is available as a W3C Recommendation and as an ISO Specification,
- *
*/
#ifndef PNG_H
#define PNG_H
-/* This is not the place to learn how to use libpng. The file libpng.txt
+/* This is not the place to learn how to use libpng. The file libpng-manual.txt
* describes how to use libpng, and the file example.c summarizes it
* with some code on which to build. This file is useful for looking
- * at the actual function definitions and structure components.
+ * at the actual function definitions and structure components. If that
+ * file has been stripped from your copy of libpng, you can find it at
+ *
+ *
+ * If you just need to read a PNG file and don't want to read the documentation
+ * skip to the end of this file and read the section entitled 'simplified API'.
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.2.24"
-#define PNG_HEADER_VERSION_STRING \
- " libpng version 1.2.24 - December 14, 2007\n"
+#define PNG_LIBPNG_VER_STRING "1.6.43"
+#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
-#define PNG_LIBPNG_VER_SONUM 0
-#define PNG_LIBPNG_VER_DLLNUM 13
+/* The versions of shared library builds should stay in sync, going forward */
+#define PNG_LIBPNG_VER_SHAREDLIB 16
+#define PNG_LIBPNG_VER_SONUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
+#define PNG_LIBPNG_VER_DLLNUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
-#define PNG_LIBPNG_VER_MINOR 2
-#define PNG_LIBPNG_VER_RELEASE 24
-/* This should match the numeric part of the final component of
- * PNG_LIBPNG_VER_STRING, omitting any leading zero: */
+#define PNG_LIBPNG_VER_MINOR 6
+#define PNG_LIBPNG_VER_RELEASE 43
+/* This should be zero for a public release, or non-zero for a
+ * development version.
+ */
#define PNG_LIBPNG_VER_BUILD 0
/* Release Status */
@@ -411,24 +310,34 @@
#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
-/* Careful here. At one time, Guy wanted to use 082, but that would be octal.
- * We must not include leading zeros.
- * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
- * version 1.0.0 was mis-numbered 100 instead of 10000). From
- * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */
-#define PNG_LIBPNG_VER 10224 /* 1.2.24 */
+/* Careful here. At one time, Guy wanted to use 082, but that
+ * would be octal. We must not include leading zeros.
+ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here
+ * (only version 1.0.0 was mis-numbered 100 instead of 10000).
+ * From version 1.0.1 it is:
+ * XXYYZZ, where XX=major, YY=minor, ZZ=release
+ */
+#define PNG_LIBPNG_VER 10643 /* 1.6.43 */
-#ifndef PNG_VERSION_INFO_ONLY
-/* include the compression library's header */
-#include "zlib.h"
+/* Library configuration: these options cannot be changed after
+ * the library has been built.
+ */
+#ifndef PNGLCONF_H
+/* If pnglibconf.h is missing, you can
+ * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h
+ */
+# include "pnglibconf.h"
#endif
-/* include all user configurable info, including optional assembler routines */
-#include "pngconf.h"
+#ifndef PNG_VERSION_INFO_ONLY
+/* Machine specific configuration. */
+# include "pngconf.h"
+#endif
/*
- * Added at libpng-1.2.8 */
-/* Ref MSDN: Private as priority over Special
+ * Added at libpng-1.2.8
+ *
+ * Ref MSDN: Private as priority over Special
* VS_FF_PRIVATEBUILD File *was not* built using standard release
* procedures. If this value is given, the StringFileInfo block must
* contain a PrivateBuild string.
@@ -439,13 +348,13 @@
* StringFileInfo block must contain a SpecialBuild string.
*/
-#if defined(PNG_USER_PRIVATEBUILD)
+#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */
# define PNG_LIBPNG_BUILD_TYPE \
- (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE)
+ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE)
#else
-# if defined(PNG_LIBPNG_SPECIALBUILD)
+# ifdef PNG_LIBPNG_SPECIALBUILD
# define PNG_LIBPNG_BUILD_TYPE \
- (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL)
+ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL)
# else
# define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE)
# endif
@@ -458,73 +367,108 @@
extern "C" {
#endif /* __cplusplus */
-/* This file is arranged in several sections. The first section contains
- * structure and type definitions. The second section contains the external
- * library functions, while the third has the internal library functions,
- * which applications aren't expected to use directly.
- */
-
-#ifndef PNG_NO_TYPECAST_NULL
-#define int_p_NULL (int *)NULL
-#define png_bytep_NULL (png_bytep)NULL
-#define png_bytepp_NULL (png_bytepp)NULL
-#define png_doublep_NULL (png_doublep)NULL
-#define png_error_ptr_NULL (png_error_ptr)NULL
-#define png_flush_ptr_NULL (png_flush_ptr)NULL
-#define png_free_ptr_NULL (png_free_ptr)NULL
-#define png_infopp_NULL (png_infopp)NULL
-#define png_malloc_ptr_NULL (png_malloc_ptr)NULL
-#define png_read_status_ptr_NULL (png_read_status_ptr)NULL
-#define png_rw_ptr_NULL (png_rw_ptr)NULL
-#define png_structp_NULL (png_structp)NULL
-#define png_uint_16p_NULL (png_uint_16p)NULL
-#define png_voidp_NULL (png_voidp)NULL
-#define png_write_status_ptr_NULL (png_write_status_ptr)NULL
-#else
-#define int_p_NULL NULL
-#define png_bytep_NULL NULL
-#define png_bytepp_NULL NULL
-#define png_doublep_NULL NULL
-#define png_error_ptr_NULL NULL
-#define png_flush_ptr_NULL NULL
-#define png_free_ptr_NULL NULL
-#define png_infopp_NULL NULL
-#define png_malloc_ptr_NULL NULL
-#define png_read_status_ptr_NULL NULL
-#define png_rw_ptr_NULL NULL
-#define png_structp_NULL NULL
-#define png_uint_16p_NULL NULL
-#define png_voidp_NULL NULL
-#define png_write_status_ptr_NULL NULL
-#endif
-
-/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
-#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
/* Version information for C files, stored in png.c. This had better match
* the version above.
*/
-#ifdef PNG_USE_GLOBAL_ARRAYS
-PNG_EXPORT_VAR (PNG_CONST char) png_libpng_ver[18];
- /* need room for 99.99.99beta99z */
-#else
#define png_libpng_ver png_get_header_ver(NULL)
-#endif
-#ifdef PNG_USE_GLOBAL_ARRAYS
-/* This was removed in version 1.0.5c */
-/* Structures to facilitate easy interlacing. See png.c for more details */
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_start[7];
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_inc[7];
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_ystart[7];
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_yinc[7];
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_mask[7];
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_dsp_mask[7];
-/* This isn't currently used. If you need it, see png.c for more details.
-PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_height[7];
-*/
-#endif
+/* This file is arranged in several sections:
+ *
+ * 1. [omitted]
+ * 2. Any configuration options that can be specified by for the application
+ * code when it is built. (Build time configuration is in pnglibconf.h)
+ * 3. Type definitions (base types are defined in pngconf.h), structure
+ * definitions.
+ * 4. Exported library functions.
+ * 5. Simplified API.
+ * 6. Implementation options.
+ *
+ * The library source code has additional files (principally pngpriv.h) that
+ * allow configuration of the library.
+ */
-#endif /* PNG_NO_EXTERN */
+/* Section 1: [omitted] */
+
+/* Section 2: run time configuration
+ * See pnglibconf.h for build time configuration
+ *
+ * Run time configuration allows the application to choose between
+ * implementations of certain arithmetic APIs. The default is set
+ * at build time and recorded in pnglibconf.h, but it is safe to
+ * override these (and only these) settings. Note that this won't
+ * change what the library does, only application code, and the
+ * settings can (and probably should) be made on a per-file basis
+ * by setting the #defines before including png.h
+ *
+ * Use macros to read integers from PNG data or use the exported
+ * functions?
+ * PNG_USE_READ_MACROS: use the macros (see below) Note that
+ * the macros evaluate their argument multiple times.
+ * PNG_NO_USE_READ_MACROS: call the relevant library function.
+ *
+ * Use the alternative algorithm for compositing alpha samples that
+ * does not use division?
+ * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division'
+ * algorithm.
+ * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm.
+ *
+ * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is
+ * false?
+ * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error
+ * APIs to png_warning.
+ * Otherwise the calls are mapped to png_error.
+ */
+
+/* Section 3: type definitions, including structures and compile time
+ * constants.
+ * See pngconf.h for base types that vary by machine/system
+ */
+
+/* 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_43;
+
+/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
+ *
+ * png_struct is the cache of information used while reading or writing a single
+ * PNG file. One of these is always required, although the simplified API
+ * (below) hides the creation and destruction of it.
+ */
+typedef struct png_struct_def png_struct;
+typedef const png_struct * png_const_structp;
+typedef png_struct * png_structp;
+typedef png_struct * * png_structpp;
+
+/* png_info contains information read from or to be written to a PNG file. One
+ * or more of these must exist while reading or creating a PNG file. The
+ * information is not used by libpng during read but is used to control what
+ * gets written when a PNG file is created. "png_get_" function calls read
+ * information during read and "png_set_" functions calls write information
+ * when creating a PNG.
+ * been moved into a separate header file that is not accessible to
+ * applications. Read libpng-manual.txt or libpng.3 for more info.
+ */
+typedef struct png_info_def png_info;
+typedef png_info * png_infop;
+typedef const png_info * png_const_infop;
+typedef png_info * * png_infopp;
+
+/* Types with names ending 'p' are pointer types. The corresponding types with
+ * names ending 'rp' are identical pointer types except that the pointer is
+ * marked 'restrict', which means that it is the only pointer to the object
+ * passed to the function. Applications should not use the 'restrict' types;
+ * it is always valid to pass 'p' to a pointer with a function argument of the
+ * corresponding 'rp' type. Different compilers have different rules with
+ * regard to type matching in the presence of 'restrict'. For backward
+ * compatibility libpng callbacks never have 'restrict' in their parameters and,
+ * consequentially, writing portable application code is extremely difficult if
+ * an attempt is made to use 'restrict'.
+ */
+typedef png_struct * PNG_RESTRICT png_structrp;
+typedef const png_struct * PNG_RESTRICT png_const_structrp;
+typedef png_info * PNG_RESTRICT png_inforp;
+typedef const png_info * PNG_RESTRICT png_const_inforp;
/* Three color definitions. The order of the red, green, and blue, (and the
* exact size) is not important, although the size of the fields need to
@@ -536,8 +480,9 @@ typedef struct png_color_struct
png_byte green;
png_byte blue;
} png_color;
-typedef png_color FAR * png_colorp;
-typedef png_color FAR * FAR * png_colorpp;
+typedef png_color * png_colorp;
+typedef const png_color * png_const_colorp;
+typedef png_color * * png_colorpp;
typedef struct png_color_16_struct
{
@@ -547,8 +492,9 @@ typedef struct png_color_16_struct
png_uint_16 blue;
png_uint_16 gray; /* for use in grayscale files */
} png_color_16;
-typedef png_color_16 FAR * png_color_16p;
-typedef png_color_16 FAR * FAR * png_color_16pp;
+typedef png_color_16 * png_color_16p;
+typedef const png_color_16 * png_const_color_16p;
+typedef png_color_16 * * png_color_16pp;
typedef struct png_color_8_struct
{
@@ -558,8 +504,9 @@ typedef struct png_color_8_struct
png_byte gray; /* for use in grayscale files */
png_byte alpha; /* for alpha channel files */
} png_color_8;
-typedef png_color_8 FAR * png_color_8p;
-typedef png_color_8 FAR * FAR * png_color_8pp;
+typedef png_color_8 * png_color_8p;
+typedef const png_color_8 * png_const_color_8p;
+typedef png_color_8 * * png_color_8pp;
/*
* The following two structures are used for the in-core representation
@@ -573,8 +520,9 @@ typedef struct png_sPLT_entry_struct
png_uint_16 alpha;
png_uint_16 frequency;
} png_sPLT_entry;
-typedef png_sPLT_entry FAR * png_sPLT_entryp;
-typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp;
+typedef png_sPLT_entry * png_sPLT_entryp;
+typedef const png_sPLT_entry * png_const_sPLT_entryp;
+typedef png_sPLT_entry * * png_sPLT_entrypp;
/* When the depth of the sPLT palette is 8 bits, the color and alpha samples
* occupy the LSB of their respective members, and the MSB of each member
@@ -588,17 +536,27 @@ typedef struct png_sPLT_struct
png_sPLT_entryp entries; /* palette entries */
png_int_32 nentries; /* number of palette entries */
} png_sPLT_t;
-typedef png_sPLT_t FAR * png_sPLT_tp;
-typedef png_sPLT_t FAR * FAR * png_sPLT_tpp;
+typedef png_sPLT_t * png_sPLT_tp;
+typedef const png_sPLT_t * png_const_sPLT_tp;
+typedef png_sPLT_t * * png_sPLT_tpp;
#ifdef PNG_TEXT_SUPPORTED
/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file,
* and whether that contents is compressed or not. The "key" field
- * points to a regular zero-terminated C string. The "text", "lang", and
- * "lang_key" fields can be regular C strings, empty strings, or NULL pointers.
- * However, the * structure returned by png_get_text() will always contain
- * regular zero-terminated C strings (possibly empty), never NULL pointers,
- * so they can be safely used in printf() and other string-handling functions.
+ * points to a regular zero-terminated C string. The "text" fields can be a
+ * regular C string, an empty string, or a NULL pointer.
+ * However, the structure returned by png_get_text() will always contain
+ * the "text" field as a regular zero-terminated C string (possibly
+ * empty), never a NULL pointer, so it can be safely used in printf() and
+ * other string-handling functions. Note that the "itxt_length", "lang", and
+ * "lang_key" members of the structure only exist when the library is built
+ * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by
+ * default without iTXt support. Also note that when iTXt *is* supported,
+ * the "lang" and "lang_key" fields contain NULL pointers when the
+ * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or
+ * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the
+ * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag"
+ * which is always 0 or 1, or its "compression method" which is always 0.
*/
typedef struct png_text_struct
{
@@ -610,17 +568,16 @@ typedef struct png_text_struct
png_charp key; /* keyword, 1-79 character description of "text" */
png_charp text; /* comment, may be an empty string (ie "")
or a NULL pointer */
- png_size_t text_length; /* length of the text string */
-#ifdef PNG_iTXt_SUPPORTED
- png_size_t itxt_length; /* length of the itxt string */
+ size_t text_length; /* length of the text string */
+ size_t itxt_length; /* length of the itxt string */
png_charp lang; /* language code, 0-79 characters
or a NULL pointer */
png_charp lang_key; /* keyword translated UTF-8 string, 0 or more
chars or a NULL pointer */
-#endif
} png_text;
-typedef png_text FAR * png_textp;
-typedef png_text FAR * FAR * png_textpp;
+typedef png_text * png_textp;
+typedef const png_text * png_const_textp;
+typedef png_text * * png_textpp;
#endif
/* Supported compression types for text in PNG files (tEXt, and zTXt).
@@ -648,318 +605,57 @@ typedef struct png_time_struct
png_byte minute; /* minute of hour, 0 - 59 */
png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
} png_time;
-typedef png_time FAR * png_timep;
-typedef png_time FAR * FAR * png_timepp;
+typedef png_time * png_timep;
+typedef const png_time * png_const_timep;
+typedef png_time * * png_timepp;
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\
+ defined(PNG_USER_CHUNKS_SUPPORTED)
/* png_unknown_chunk is a structure to hold queued chunks for which there is
* no specific support. The idea is that we can use this to queue
* up private chunks for output even though the library doesn't actually
* know about their semantics.
+ *
+ * The data in the structure is set by libpng on read and used on write.
*/
-#define PNG_CHUNK_NAME_LENGTH 5
typedef struct png_unknown_chunk_t
{
- png_byte name[PNG_CHUNK_NAME_LENGTH];
- png_byte *data;
- png_size_t size;
+ png_byte name[5]; /* Textual chunk name with '\0' terminator */
+ png_byte *data; /* Data, should not be modified on read! */
+ size_t size;
- /* libpng-using applications should NOT directly modify this byte. */
- png_byte location; /* mode of operation at read time */
+ /* On write 'location' must be set using the flag values listed below.
+ * Notice that on read it is set by libpng however the values stored have
+ * more bits set than are listed below. Always treat the value as a
+ * bitmask. On write set only one bit - setting multiple bits may cause the
+ * chunk to be written in multiple places.
+ */
+ png_byte location; /* mode of operation at read time */
}
png_unknown_chunk;
-typedef png_unknown_chunk FAR * png_unknown_chunkp;
-typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp;
+
+typedef png_unknown_chunk * png_unknown_chunkp;
+typedef const png_unknown_chunk * png_const_unknown_chunkp;
+typedef png_unknown_chunk * * png_unknown_chunkpp;
#endif
-/* 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, 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 any case, the order of the parameters in png_info_struct should NOT
- * be changed for as long as possible to keep compatibility with applications
- * that use the old direct-access method with png_info_struct.
- *
- * 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.
- *
- * 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.
- */
-typedef struct png_info_struct
-{
- /* the following are necessary for every PNG file */
- png_uint_32 width; /* width of image in pixels (from IHDR) */
- png_uint_32 height; /* height of image in pixels (from IHDR) */
- png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
- png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */
- png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
- png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
- png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
- png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
- png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
- /* The following three should have been named *_method not *_type */
- png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
- png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
- png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
-
- /* The following is informational only on read, and not used on writes. */
- png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */
- png_byte pixel_depth; /* number of bits per pixel */
- png_byte spare_byte; /* to align the data, and for future use */
- png_byte signature[8]; /* magic bytes read by libpng from start of file */
-
- /* The rest of the data is optional. If you are reading, check the
- * valid field to see if the information in these are valid. If you
- * are writing, set the valid field to those chunks you want written,
- * and initialize the appropriate fields below.
- */
-
-#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
- /* The gAMA chunk describes the gamma characteristics of the system
- * on which the image was created, normally in the range [1.0, 2.5].
- * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
- */
- float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
-#endif
-
-#if defined(PNG_sRGB_SUPPORTED)
- /* GR-P, 0.96a */
- /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */
- png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */
-#endif
-
-#if defined(PNG_TEXT_SUPPORTED)
- /* The tEXt, and zTXt chunks contain human-readable textual data in
- * uncompressed, compressed, and optionally compressed forms, respectively.
- * The data in "text" is an array of pointers to uncompressed,
- * null-terminated C strings. Each chunk has a keyword that describes the
- * textual data contained in that chunk. Keywords are not required to be
- * unique, and the text string may be empty. Any number of text chunks may
- * be in an image.
- */
- int num_text; /* number of comments read/to write */
- int max_text; /* current size of text array */
- png_textp text; /* array of comments read/to write */
-#endif /* PNG_TEXT_SUPPORTED */
-
-#if defined(PNG_tIME_SUPPORTED)
- /* The tIME chunk holds the last time the displayed image data was
- * modified. See the png_time struct for the contents of this struct.
- */
- png_time mod_time;
-#endif
-
-#if defined(PNG_sBIT_SUPPORTED)
- /* The sBIT chunk specifies the number of significant high-order bits
- * in the pixel data. Values are in the range [1, bit_depth], and are
- * only specified for the channels in the pixel data. The contents of
- * the low-order bits is not specified. Data is valid if
- * (valid & PNG_INFO_sBIT) is non-zero.
- */
- png_color_8 sig_bit; /* significant bits in color channels */
-#endif
-
-#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \
-defined(PNG_READ_BACKGROUND_SUPPORTED)
- /* The tRNS chunk supplies transparency data for paletted images and
- * other image types that don't need a full alpha channel. There are
- * "num_trans" transparency values for a paletted image, stored in the
- * same order as the palette colors, starting from index 0. Values
- * for the data are in the range [0, 255], ranging from fully transparent
- * to fully opaque, respectively. For non-paletted images, there is a
- * single color specified that should be treated as fully transparent.
- * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
- */
- png_bytep trans; /* transparent values for paletted image */
- png_color_16 trans_values; /* transparent color for non-palette image */
-#endif
-
-#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- /* The bKGD chunk gives the suggested image background color if the
- * display program does not have its own background color and the image
- * is needs to composited onto a background before display. The colors
- * in "background" are normally in the same color space/depth as the
- * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
- */
- png_color_16 background;
-#endif
-
-#if defined(PNG_oFFs_SUPPORTED)
- /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
- * and downwards from the top-left corner of the display, page, or other
- * application-specific co-ordinate space. See the PNG_OFFSET_ defines
- * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
- */
- png_int_32 x_offset; /* x offset on page */
- png_int_32 y_offset; /* y offset on page */
- png_byte offset_unit_type; /* offset units type */
-#endif
-
-#if defined(PNG_pHYs_SUPPORTED)
- /* The pHYs chunk gives the physical pixel density of the image for
- * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
- * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
- */
- png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
- png_uint_32 y_pixels_per_unit; /* vertical pixel density */
- png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
-#endif
-
-#if defined(PNG_hIST_SUPPORTED)
- /* The hIST chunk contains the relative frequency or importance of the
- * various palette entries, so that a viewer can intelligently select a
- * reduced-color palette, if required. Data is an array of "num_palette"
- * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
- * is non-zero.
- */
- png_uint_16p hist;
-#endif
-
-#ifdef PNG_cHRM_SUPPORTED
- /* The cHRM chunk describes the CIE color characteristics of the monitor
- * on which the PNG was created. This data allows the viewer to do gamut
- * mapping of the input image to ensure that the viewer sees the same
- * colors in the image as the creator. Values are in the range
- * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero.
- */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float x_white;
- float y_white;
- float x_red;
- float y_red;
- float x_green;
- float y_green;
- float x_blue;
- float y_blue;
-#endif
-#endif
-
-#if defined(PNG_pCAL_SUPPORTED)
- /* The pCAL chunk describes a transformation between the stored pixel
- * values and original physical data values used to create the image.
- * The integer range [0, 2^bit_depth - 1] maps to the floating-point
- * range given by [pcal_X0, pcal_X1], and are further transformed by a
- * (possibly non-linear) transformation function given by "pcal_type"
- * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
- * defines below, and the PNG-Group's PNG extensions document for a
- * complete description of the transformations and how they should be
- * implemented, and for a description of the ASCII parameter strings.
- * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
- */
- png_charp pcal_purpose; /* pCAL chunk description string */
- png_int_32 pcal_X0; /* minimum value */
- png_int_32 pcal_X1; /* maximum value */
- png_charp pcal_units; /* Latin-1 string giving physical units */
- png_charpp pcal_params; /* ASCII strings containing parameter values */
- png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
- png_byte pcal_nparams; /* number of parameters given in pcal_params */
-#endif
-
-/* New members added in libpng-1.0.6 */
-#ifdef PNG_FREE_ME_SUPPORTED
- png_uint_32 free_me; /* flags items libpng is responsible for freeing */
-#endif
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- /* storage for unknown chunks that the library doesn't recognize. */
- png_unknown_chunkp unknown_chunks;
- png_size_t unknown_chunks_num;
-#endif
-
-#if defined(PNG_iCCP_SUPPORTED)
- /* iCCP chunk data. */
- png_charp iccp_name; /* profile name */
- png_charp iccp_profile; /* International Color Consortium profile data */
- /* Note to maintainer: should be png_bytep */
- png_uint_32 iccp_proflen; /* ICC profile data length */
- png_byte iccp_compression; /* Always zero */
-#endif
-
-#if defined(PNG_sPLT_SUPPORTED)
- /* data on sPLT chunks (there may be more than one). */
- png_sPLT_tp splt_palettes;
- png_uint_32 splt_palettes_num;
-#endif
-
-#if defined(PNG_sCAL_SUPPORTED)
- /* The sCAL chunk describes the actual physical dimensions of the
- * subject matter of the graphic. The chunk contains a unit specification
- * a byte value, and two ASCII strings representing floating-point
- * values. The values are width and height corresponsing to one pixel
- * in the image. This external representation is converted to double
- * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero.
- */
- png_byte scal_unit; /* unit of physical scale */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- double scal_pixel_width; /* width of one pixel */
- double scal_pixel_height; /* height of one pixel */
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_charp scal_s_width; /* string containing height */
- png_charp scal_s_height; /* string containing width */
-#endif
-#endif
-
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
- /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */
- /* Data valid if (valid & PNG_INFO_IDAT) non-zero */
- png_bytepp row_pointers; /* the image bits */
-#endif
-
-#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED)
- png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */
-#endif
-
-#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED)
- png_fixed_point int_x_white;
- png_fixed_point int_y_white;
- png_fixed_point int_x_red;
- png_fixed_point int_y_red;
- png_fixed_point int_x_green;
- png_fixed_point int_y_green;
- png_fixed_point int_x_blue;
- png_fixed_point int_y_blue;
-#endif
-
-} png_info;
-
-typedef png_info FAR * png_infop;
-typedef png_info FAR * FAR * png_infopp;
+/* Flag values for the unknown chunk location byte. */
+#define PNG_HAVE_IHDR 0x01
+#define PNG_HAVE_PLTE 0x02
+#define PNG_AFTER_IDAT 0x08
/* Maximum positive integer used in PNG is (2^31)-1 */
#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL)
#define PNG_UINT_32_MAX ((png_uint_32)(-1))
-#define PNG_SIZE_MAX ((png_size_t)(-1))
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* PNG_MAX_UINT is deprecated; use PNG_UINT_31_MAX instead. */
-#define PNG_MAX_UINT PNG_UINT_31_MAX
-#endif
+#define PNG_SIZE_MAX ((size_t)(-1))
+
+/* These are constants for fixed point values encoded in the
+ * PNG specification manner (x100000)
+ */
+#define PNG_FP_1 100000
+#define PNG_FP_HALF 50000
+#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL)
+#define PNG_FP_MIN (-PNG_FP_MAX)
/* These describe the color_type field in png_info. */
/* color type masks */
@@ -1032,22 +728,23 @@ typedef png_info FAR * FAR * png_infopp;
* data in the info_struct to be written into the output file. The values
* of the PNG_INFO_ defines should NOT be changed.
*/
-#define PNG_INFO_gAMA 0x0001
-#define PNG_INFO_sBIT 0x0002
-#define PNG_INFO_cHRM 0x0004
-#define PNG_INFO_PLTE 0x0008
-#define PNG_INFO_tRNS 0x0010
-#define PNG_INFO_bKGD 0x0020
-#define PNG_INFO_hIST 0x0040
-#define PNG_INFO_pHYs 0x0080
-#define PNG_INFO_oFFs 0x0100
-#define PNG_INFO_tIME 0x0200
-#define PNG_INFO_pCAL 0x0400
-#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */
-#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */
-#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
-#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
-#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
+#define PNG_INFO_gAMA 0x0001U
+#define PNG_INFO_sBIT 0x0002U
+#define PNG_INFO_cHRM 0x0004U
+#define PNG_INFO_PLTE 0x0008U
+#define PNG_INFO_tRNS 0x0010U
+#define PNG_INFO_bKGD 0x0020U
+#define PNG_INFO_hIST 0x0040U
+#define PNG_INFO_pHYs 0x0080U
+#define PNG_INFO_oFFs 0x0100U
+#define PNG_INFO_tIME 0x0200U
+#define PNG_INFO_pCAL 0x0400U
+#define PNG_INFO_sRGB 0x0800U /* GR-P, 0.96a */
+#define PNG_INFO_iCCP 0x1000U /* ESR, 1.0.6 */
+#define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */
+#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 */
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -1055,53 +752,79 @@ typedef png_info FAR * FAR * png_infopp;
*/
typedef struct png_row_info_struct
{
- png_uint_32 width; /* width of row */
- png_uint_32 rowbytes; /* number of bytes in row */
- png_byte color_type; /* color type of row */
- png_byte bit_depth; /* bit depth of row */
- png_byte channels; /* number of channels (1, 2, 3, or 4) */
+ png_uint_32 width; /* width of row */
+ size_t rowbytes; /* number of bytes in row */
+ png_byte color_type; /* color type of row */
+ png_byte bit_depth; /* bit depth of row */
+ png_byte channels; /* number of channels (1, 2, 3, or 4) */
png_byte pixel_depth; /* bits per pixel (depth * channels) */
} png_row_info;
-typedef png_row_info FAR * png_row_infop;
-typedef png_row_info FAR * FAR * png_row_infopp;
+typedef png_row_info * png_row_infop;
+typedef png_row_info * * png_row_infopp;
/* These are the function types for the I/O functions and for the functions
* that allow the user to override the default I/O functions with his or her
* own. The png_error_ptr type should match that of user-supplied warning
* and error functions, while the png_rw_ptr type should match that of the
- * user read/write data functions.
+ * user read/write data functions. Note that the 'write' function must not
+ * modify the buffer it is passed. The 'read' function, on the other hand, is
+ * expected to return the read data in the buffer.
*/
-typedef struct png_struct_def png_struct;
-typedef png_struct FAR * png_structp;
-
-typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp));
-typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
-typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp));
-typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32,
- int));
-typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32,
- int));
+typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp));
+typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, size_t));
+typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp));
+typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
+ int));
+typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
+ int));
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop));
-typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
-typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
- png_uint_32, int));
+typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
+
+/* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+ * row number is the row number within the sub-image of the interlace pass, so
+ * the value will increase to the height of the sub-image (not the full image)
+ * then reset to 0 for the next pass.
+ *
+ * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to
+ * find the output pixel (x,y) given an interlaced sub-image pixel
+ * (row,col,pass). (See below for these macros.)
+ */
+typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep,
+ png_uint_32, int));
#endif
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
-typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp,
- png_row_infop, png_bytep));
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop,
+ png_bytep));
#endif
-#if defined(PNG_USER_CHUNKS_SUPPORTED)
-typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp));
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp,
+ png_unknown_chunkp));
#endif
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp));
+#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
+/* not used anywhere */
+/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* This must match the function definition in , and the application
+ * must include this before png.h to obtain the definition of jmp_buf. The
+ * function is required to be PNG_NORETURN, but this is not checked. If the
+ * function does return the application will crash via an abort() or similar
+ * system level call.
+ *
+ * If you get a warning here while building the library you may need to make
+ * changes to ensure that pnglibconf.h records the calling convention used by
+ * your compiler. This may be very difficult - try using a different compiler
+ * to build the library!
+ */
+PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
#endif
/* Transform masks for the high-level interface */
@@ -1117,668 +840,590 @@ typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp));
#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */
#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */
#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */
-#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */
+#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */
+/* Added to libpng-1.2.34 */
+#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER
+#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */
+/* Added to libpng-1.4.0 */
+#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */
+/* Added to libpng-1.5.4 */
+#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */
+#if ~0U > 0xffffU /* or else this might break on a 16-bit machine */
+#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */
+#endif
/* Flags for MNG supported features */
#define PNG_FLAG_MNG_EMPTY_PLTE 0x01
#define PNG_FLAG_MNG_FILTER_64 0x04
#define PNG_ALL_MNG_FEATURES 0x05
-typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t));
-typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp));
-
-/* 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, except to store
- * the jmp_buf.
+/* NOTE: prior to 1.5 these functions had no 'API' style declaration,
+ * this allowed the zlib default functions to be used on Windows
+ * platforms. In 1.5 the zlib default malloc (which just calls malloc and
+ * ignores the first argument) should be completely compatible with the
+ * following.
*/
+typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp,
+ png_alloc_size_t));
+typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp));
-struct png_struct_def
-{
-#ifdef PNG_SETJMP_SUPPORTED
- jmp_buf jmpbuf; /* used in png_error */
-#endif
- png_error_ptr error_fn; /* function for printing errors and aborting */
- png_error_ptr warning_fn; /* function for printing warnings */
- png_voidp error_ptr; /* user supplied struct for error functions */
- png_rw_ptr write_data_fn; /* function for writing output data */
- png_rw_ptr read_data_fn; /* function for reading input data */
- png_voidp io_ptr; /* ptr to application struct for I/O functions */
-
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- png_user_transform_ptr read_user_transform_fn; /* user read transform */
-#endif
-
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
- png_user_transform_ptr write_user_transform_fn; /* user write transform */
-#endif
-
-/* These were added in libpng-1.0.2 */
-#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
- png_voidp user_transform_ptr; /* user supplied struct for user transform */
- png_byte user_transform_depth; /* bit depth of user transformed pixels */
- png_byte user_transform_channels; /* channels in user transformed pixels */
-#endif
-#endif
-
- png_uint_32 mode; /* tells us where we are in the PNG file */
- png_uint_32 flags; /* flags indicating various things to libpng */
- png_uint_32 transformations; /* which transformations to perform */
-
- z_stream zstream; /* pointer to decompression structure (below) */
- png_bytep zbuf; /* buffer for zlib */
- png_size_t zbuf_size; /* size of zbuf */
- int zlib_level; /* holds zlib compression level */
- int zlib_method; /* holds zlib compression method */
- int zlib_window_bits; /* holds zlib compression window bits */
- int zlib_mem_level; /* holds zlib compression memory level */
- int zlib_strategy; /* holds zlib compression strategy */
-
- 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 */
- png_uint_32 usr_width; /* width of row at start of write */
- png_uint_32 rowbytes; /* size of row in bytes */
- png_uint_32 irowbytes; /* size of current interlaced row in bytes */
- png_uint_32 iwidth; /* width of current interlaced row in pixels */
- png_uint_32 row_number; /* current row in interlace pass */
- png_bytep prev_row; /* buffer to save previous (unfiltered) row */
- png_bytep row_buf; /* buffer to save current (unfiltered) row */
-#ifndef PNG_NO_WRITE_FILTERING
- png_bytep sub_row; /* buffer to save "sub" row when filtering */
- png_bytep up_row; /* buffer to save "up" row when filtering */
- png_bytep avg_row; /* buffer to save "avg" row when filtering */
- png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
-#endif
- png_row_info row_info; /* used for transformation routines */
-
- png_uint_32 idat_size; /* current IDAT size for read */
- png_uint_32 crc; /* current chunk CRC value */
- png_colorp palette; /* palette from the input file */
- png_uint_16 num_palette; /* number of color entries in palette */
- png_uint_16 num_trans; /* number of transparency values */
- png_byte chunk_name[5]; /* null-terminated name of current chunk */
- png_byte compression; /* file compression type (always 0) */
- png_byte filter; /* file filter type (always 0) */
- png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
- png_byte pass; /* current interlace pass (0 - 6) */
- png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
- png_byte color_type; /* color type of file */
- png_byte bit_depth; /* bit depth of file */
- png_byte usr_bit_depth; /* bit depth of users row */
- png_byte pixel_depth; /* number of bits per pixel */
- png_byte channels; /* number of channels in file */
- png_byte usr_channels; /* channels at start of write */
- png_byte sig_bytes; /* magic bytes read/written from start of file */
-
-#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
-#ifdef PNG_LEGACY_SUPPORTED
- png_byte filler; /* filler byte for pixel expansion */
-#else
- png_uint_16 filler; /* filler bytes for pixel expansion */
-#endif
-#endif
-
-#if defined(PNG_bKGD_SUPPORTED)
- png_byte background_gamma_type;
-# ifdef PNG_FLOATING_POINT_SUPPORTED
- float background_gamma;
-# endif
- png_color_16 background; /* background color in screen gamma space */
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- png_color_16 background_1; /* background normalized to gamma 1.0 */
-#endif
-#endif /* PNG_bKGD_SUPPORTED */
-
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
- png_flush_ptr output_flush_fn;/* Function for flushing output */
- png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
- png_uint_32 flush_rows; /* number of rows written since last flush */
-#endif
-
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- int gamma_shift; /* number of "insignificant" bits 16-bit gamma */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float gamma; /* file gamma value */
- float screen_gamma; /* screen gamma value (display_exponent) */
-#endif
-#endif
-
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- png_bytep gamma_table; /* gamma table for 8-bit depth files */
- png_bytep gamma_from_1; /* converts from 1.0 to screen */
- png_bytep gamma_to_1; /* converts from file to 1.0 */
- png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
- 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
-
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
- png_color_8 sig_bit; /* significant bits in each available channel */
-#endif
-
-#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
- png_color_8 shift; /* shift for significant bit tranformation */
-#endif
-
-#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
- || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- png_bytep trans; /* transparency values for paletted files */
- png_color_16 trans_values; /* transparency values for non-paletted files */
-#endif
-
- png_read_status_ptr read_row_fn; /* called after each row is decoded */
- png_write_status_ptr write_row_fn; /* called after each row is encoded */
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
- png_progressive_info_ptr info_fn; /* called after header data fully read */
- png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */
- png_progressive_end_ptr end_fn; /* called after image is complete */
- png_bytep save_buffer_ptr; /* current location in save_buffer */
- png_bytep save_buffer; /* buffer for previously read data */
- png_bytep current_buffer_ptr; /* current location in current_buffer */
- png_bytep current_buffer; /* buffer for recently used data */
- png_uint_32 push_length; /* size of current input chunk */
- png_uint_32 skip_length; /* bytes to skip in input data */
- png_size_t save_buffer_size; /* amount of data now in save_buffer */
- png_size_t save_buffer_max; /* total size of save_buffer */
- png_size_t buffer_size; /* total amount of available input data */
- png_size_t current_buffer_size; /* amount of data now in current_buffer */
- int process_mode; /* what push library is currently doing */
- int cur_palette; /* current push library palette index */
-
-# if defined(PNG_TEXT_SUPPORTED)
- png_size_t current_text_size; /* current size of text input data */
- png_size_t current_text_left; /* how much text left to read in input */
- png_charp current_text; /* current text chunk buffer */
- png_charp current_text_ptr; /* current location in current_text */
-# endif /* PNG_TEXT_SUPPORTED */
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-
-#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
-/* for the Borland special 64K segment handler */
- png_bytepp offset_table_ptr;
- png_bytep offset_table;
- png_uint_16 offset_table_number;
- png_uint_16 offset_table_count;
- png_uint_16 offset_table_count_free;
-#endif
-
-#if defined(PNG_READ_DITHER_SUPPORTED)
- png_bytep palette_lookup; /* lookup table for dithering */
- png_bytep dither_index; /* index translation for palette files */
-#endif
-
-#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED)
- png_uint_16p hist; /* histogram */
-#endif
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- png_byte heuristic_method; /* heuristic for row filter selection */
- png_byte num_prev_filters; /* number of weights for previous rows */
- png_bytep prev_filters; /* filter type(s) of previous row(s) */
- png_uint_16p filter_weights; /* weight(s) for previous line(s) */
- png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
- png_uint_16p filter_costs; /* relative filter calculation cost */
- png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
-#endif
-
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- png_charp time_buffer; /* String to hold RFC 1123 time text */
-#endif
-
-/* New members added in libpng-1.0.6 */
-
-#ifdef PNG_FREE_ME_SUPPORTED
- png_uint_32 free_me; /* flags items libpng is responsible for freeing */
-#endif
-
-#if defined(PNG_USER_CHUNKS_SUPPORTED)
- png_voidp user_chunk_ptr;
- png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
-#endif
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- int num_chunk_list;
- png_bytep chunk_list;
-#endif
-
-/* New members added in libpng-1.0.3 */
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
- png_byte rgb_to_gray_status;
- /* These were changed from png_byte in libpng-1.0.6 */
- png_uint_16 rgb_to_gray_red_coeff;
- png_uint_16 rgb_to_gray_green_coeff;
- png_uint_16 rgb_to_gray_blue_coeff;
-#endif
-
-/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
-#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
- defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
- defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
-/* changed from png_byte to png_uint_32 at version 1.2.0 */
-#ifdef PNG_1_0_X
- png_byte mng_features_permitted;
-#else
- png_uint_32 mng_features_permitted;
-#endif /* PNG_1_0_X */
-#endif
-
-/* New member added in libpng-1.0.7 */
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- png_fixed_point int_gamma;
-#endif
-
-/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- png_byte filter_type;
-#endif
-
-#if defined(PNG_1_0_X)
-/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */
- png_uint_32 row_buf_size;
-#endif
-
-/* New members added in libpng-1.2.0 */
-#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
-# if !defined(PNG_1_0_X)
-# if defined(PNG_MMX_CODE_SUPPORTED)
- png_byte mmx_bitdepth_threshold;
- png_uint_32 mmx_rowbytes_threshold;
-# endif
- png_uint_32 asm_flags;
-# endif
-#endif
-
-/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
-#ifdef PNG_USER_MEM_SUPPORTED
- png_voidp mem_ptr; /* user supplied struct for mem functions */
- png_malloc_ptr malloc_fn; /* function for allocating memory */
- png_free_ptr free_fn; /* function for freeing memory */
-#endif
-
-/* New member added in libpng-1.0.13 and 1.2.0 */
- png_bytep big_row_buf; /* buffer to save current (unfiltered) row */
-
-#if defined(PNG_READ_DITHER_SUPPORTED)
-/* The following three members were added at version 1.0.14 and 1.2.4 */
- png_bytep dither_sort; /* working sort array */
- png_bytep index_to_palette; /* where the original index currently is */
- /* in the palette */
- png_bytep palette_to_index; /* which original index points to this */
- /* palette color */
-#endif
-
-/* New members added in libpng-1.0.16 and 1.2.6 */
- png_byte compression_type;
-
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- png_uint_32 user_width_max;
- png_uint_32 user_height_max;
-#endif
-
-/* New member added in libpng-1.0.25 and 1.2.17 */
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- /* storage for unknown chunk that the library doesn't recognize. */
- png_unknown_chunk unknown_chunk;
-#endif
-};
-
-
-/* This triggers a compiler error in png.c, if png.c and png.h
- * do not agree upon the version number.
- */
-typedef png_structp version_1_2_24;
-
-typedef png_struct FAR * FAR * png_structpp;
-
-/* Here are the function definitions most commonly used. This is not
- * the place to find out how to use libpng. See libpng.txt for the
+/* Section 4: exported functions
+ * Here are the function definitions most commonly used. This is not
+ * the place to find out how to use libpng. See libpng-manual.txt for the
* full explanation, see example.c for the summary. This just provides
* a simple one line description of the use of each function.
+ *
+ * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in
+ * pngconf.h and in the *.dfn files in the scripts directory.
+ *
+ * PNG_EXPORT(ordinal, type, name, (args));
+ *
+ * ordinal: ordinal that is used while building
+ * *.def files. The ordinal value is only
+ * relevant when preprocessing png.h with
+ * the *.dfn files for building symbol table
+ * entries, and are removed by pngconf.h.
+ * type: return type of the function
+ * name: function name
+ * args: function arguments, with types
+ *
+ * When we wish to append attributes to a function prototype we use
+ * the PNG_EXPORTA() macro instead.
+ *
+ * PNG_EXPORTA(ordinal, type, name, (args), attributes);
+ *
+ * ordinal, type, name, and args: same as in PNG_EXPORT().
+ * attributes: function attributes
*/
/* Returns the version number of the library */
-extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void));
+PNG_EXPORT(1, png_uint_32, png_access_version_number, (void));
/* Tell lib we have already handled the first magic bytes.
* Handling more than 8 bytes from the beginning of the file is an error.
*/
-extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
- int num_bytes));
+PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));
/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
* PNG file. Returns zero if the supplied bytes match the 8-byte PNG
* signature, and non-zero otherwise. Having num_to_check == 0 or
- * start > 7 will always fail (ie return non-zero).
+ * start > 7 will always fail (i.e. return non-zero).
*/
-extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
- png_size_t num_to_check));
+PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,
+ size_t num_to_check));
/* Simple signature checking function. This is the same as calling
- * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0).
*/
-extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
+#define png_check_sig(sig, n) (png_sig_cmp((sig), 0, (n)) == 0) /* DEPRECATED */
/* Allocate and initialize png_ptr struct for reading, and any other memory. */
-extern PNG_EXPORT(png_structp,png_create_read_struct)
- PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn));
+PNG_EXPORTA(4, png_structp, png_create_read_struct,
+ (png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn),
+ PNG_ALLOCATED);
/* Allocate and initialize png_ptr struct for writing, and any other memory */
-extern PNG_EXPORT(png_structp,png_create_write_struct)
- PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn));
+PNG_EXPORTA(5, png_structp, png_create_write_struct,
+ (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warn_fn),
+ PNG_ALLOCATED);
-#ifdef PNG_WRITE_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size)
- PNGARG((png_structp png_ptr));
-#endif
-
-#ifdef PNG_WRITE_SUPPORTED
-extern PNG_EXPORT(void,png_set_compression_buffer_size)
- PNGARG((png_structp png_ptr, png_uint_32 size));
+PNG_EXPORT(6, size_t, png_get_compression_buffer_size,
+ (png_const_structrp png_ptr));
+
+PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,
+ size_t size));
+
+/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
+ * match up.
+ */
+#ifdef PNG_SETJMP_SUPPORTED
+/* This function returns the jmp_buf built in to *png_ptr. It must be
+ * supplied with an appropriate 'longjmp' function to use on that jmp_buf
+ * unless the default error function is overridden in which case NULL is
+ * acceptable. The size of the jmp_buf is checked against the actual size
+ * allocated by the library - the call will return NULL on a mismatch
+ * indicating an ABI mismatch.
+ */
+PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,
+ png_longjmp_ptr longjmp_fn, size_t jmp_buf_size));
+# define png_jmpbuf(png_ptr) \
+ (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf))))
+#else
+# define png_jmpbuf(png_ptr) \
+ (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP)
#endif
+/* This function should be used by libpng applications in place of
+ * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it
+ * will use it; otherwise it will call PNG_ABORT(). This function was
+ * added in libpng-1.5.0.
+ */
+PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val),
+ PNG_NORETURN);
+#ifdef PNG_READ_SUPPORTED
/* Reset the compression stream */
-extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr));
+PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED);
+#endif
/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */
#ifdef PNG_USER_MEM_SUPPORTED
-extern PNG_EXPORT(png_structp,png_create_read_struct_2)
- PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
- png_malloc_ptr malloc_fn, png_free_ptr free_fn));
-extern PNG_EXPORT(png_structp,png_create_write_struct_2)
- PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
- png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+PNG_EXPORTA(11, png_structp, png_create_read_struct_2,
+ (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warn_fn,
+ png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+ PNG_ALLOCATED);
+PNG_EXPORTA(12, png_structp, png_create_write_struct_2,
+ (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warn_fn,
+ png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+ PNG_ALLOCATED);
#endif
+/* Write the PNG file signature. */
+PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr));
+
/* Write a PNG chunk - size, type, (optional) data, CRC. */
-extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr,
- png_bytep chunk_name, png_bytep data, png_size_t length));
+PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep
+ chunk_name, png_const_bytep data, size_t length));
/* Write the start of a PNG chunk - length and chunk name. */
-extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr,
- png_bytep chunk_name, png_uint_32 length));
+PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr,
+ png_const_bytep chunk_name, png_uint_32 length));
/* Write the data of a PNG chunk started with png_write_chunk_start(). */
-extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr,
- png_bytep data, png_size_t length));
+PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr,
+ png_const_bytep data, size_t length));
/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
-extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr));
+PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr));
/* Allocate and initialize the info structure */
-extern PNG_EXPORT(png_infop,png_create_info_struct)
- PNGARG((png_structp png_ptr));
+PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr),
+ PNG_ALLOCATED);
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Initialize the info structure (old interface - DEPRECATED) */
-extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr));
-#undef png_info_init
-#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\
- png_sizeof(png_info));
-#endif
-
-extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr,
- png_size_t png_info_struct_size));
+/* DEPRECATED: this function allowed init structures to be created using the
+ * default allocation method (typically malloc). Use is deprecated in 1.6.0 and
+ * the API will be removed in the future.
+ */
+PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr,
+ size_t png_info_struct_size), PNG_DEPRECATED);
/* Writes all the PNG information before the image. */
-extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
+PNG_EXPORT(20, void, png_write_info_before_PLTE,
+ (png_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(21, void, png_write_info,
+ (png_structrp png_ptr, png_const_inforp info_ptr));
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-/* read the information before the actual image data. */
-extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the information before the actual image data. */
+PNG_EXPORT(22, void, png_read_info,
+ (png_structrp png_ptr, png_inforp info_ptr));
#endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
-extern PNG_EXPORT(png_charp,png_convert_to_rfc1123)
- PNGARG((png_structp png_ptr, png_timep ptime));
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+ /* Convert to a US string format: there is no localization support in this
+ * routine. The original implementation used a 29 character buffer in
+ * png_struct, this will be removed in future versions.
+ */
+#if PNG_LIBPNG_VER < 10700
+/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */
+PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,
+ png_const_timep ptime),PNG_DEPRECATED);
+#endif
+PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29],
+ png_const_timep ptime));
#endif
-#if !defined(_WIN32_WCE)
-/* "time.h" functions are not supported on WindowsCE */
-#if defined(PNG_WRITE_tIME_SUPPORTED)
-/* convert from a struct tm to png_time */
-extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
- struct tm FAR * ttime));
+#ifdef PNG_CONVERT_tIME_SUPPORTED
+/* Convert from a struct tm to png_time */
+PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime,
+ const struct tm * ttime));
-/* convert from time_t to png_time. Uses gmtime() */
-extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
- time_t ttime));
-#endif /* PNG_WRITE_tIME_SUPPORTED */
-#endif /* _WIN32_WCE */
+/* Convert from time_t to png_time. Uses gmtime() */
+PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime));
+#endif /* CONVERT_tIME */
-#if defined(PNG_READ_EXPAND_SUPPORTED)
+#ifdef PNG_READ_EXPAND_SUPPORTED
/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */
-extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
-#if !defined(PNG_1_0_X)
-extern PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp
- png_ptr));
-#endif
-extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr));
-extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr));
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Deprecated */
-extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr));
+PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr));
+PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr));
+PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr));
+PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr));
#endif
+
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion
+ * of a tRNS chunk if present.
+ */
+PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
/* Use blue, green, red order for pixels. */
-extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
/* Expand the grayscale to 24-bit RGB if necessary. */
-extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
/* Reduce RGB to grayscale. */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr,
- int error_action, double red, double green ));
-#endif
-extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr,
- int error_action, png_fixed_point red, png_fixed_point green ));
-extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp
- png_ptr));
+#define PNG_ERROR_ACTION_NONE 1
+#define PNG_ERROR_ACTION_WARN 2
+#define PNG_ERROR_ACTION_ERROR 3
+#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/
+
+PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr,
+ int error_action, double red, double green))
+PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr,
+ int error_action, png_fixed_point red, png_fixed_point green))
+
+PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp
+ png_ptr));
#endif
-extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
- png_colorp palette));
+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
+ png_colorp palette));
+#endif
-#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
-extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+/* How the alpha channel is interpreted - this affects how the color channels
+ * of a PNG file are returned to the calling application when an alpha channel,
+ * or a tRNS chunk in a palette file, is present.
+ *
+ * This has no effect on the way pixels are written into a PNG output
+ * datastream. The color samples in a PNG datastream are never premultiplied
+ * with the alpha samples.
+ *
+ * The default is to return data according to the PNG specification: the alpha
+ * channel is a linear measure of the contribution of the pixel to the
+ * corresponding composited pixel, and the color channels are unassociated
+ * (not premultiplied). The gamma encoded color channels must be scaled
+ * according to the contribution and to do this it is necessary to undo
+ * the encoding, scale the color values, perform the composition and re-encode
+ * the values. This is the 'PNG' mode.
+ *
+ * The alternative is to 'associate' the alpha with the color information by
+ * storing color channel values that have been scaled by the alpha.
+ * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes
+ * (the latter being the two common names for associated alpha color channels).
+ *
+ * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha
+ * value is equal to the maximum value.
+ *
+ * The final choice is to gamma encode the alpha channel as well. This is
+ * broken because, in practice, no implementation that uses this choice
+ * correctly undoes the encoding before handling alpha composition. Use this
+ * choice only if other serious errors in the software or hardware you use
+ * mandate it; the typical serious error is for dark halos to appear around
+ * opaque areas of the composited PNG image because of arithmetic overflow.
+ *
+ * The API function png_set_alpha_mode specifies which of these choices to use
+ * with an enumerated 'mode' value and the gamma of the required output:
+ */
+#define PNG_ALPHA_PNG 0 /* according to the PNG standard */
+#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */
+#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */
+#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */
+#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */
+#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */
+
+PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode,
+ double output_gamma))
+PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr,
+ int mode, png_fixed_point output_gamma))
+#endif
+
+#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+/* The output_gamma value is a screen gamma in libpng terminology: it expresses
+ * how to decode the output values, not how they are encoded.
+ */
+#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */
+#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */
+#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */
+#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */
+#endif
+
+/* The following are examples of calls to png_set_alpha_mode to achieve the
+ * required overall gamma correction and, where necessary, alpha
+ * premultiplication.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ * This is the default libpng handling of the alpha channel - it is not
+ * pre-multiplied into the color components. In addition the call states
+ * that the output is for a sRGB system and causes all PNG files without gAMA
+ * chunks to be assumed to be encoded using sRGB.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ * In this case the output is assumed to be something like an sRGB conformant
+ * display preceded by a power-law lookup table of power 1.45. This is how
+ * early Mac systems behaved.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);
+ * This is the classic Jim Blinn approach and will work in academic
+ * environments where everything is done by the book. It has the shortcoming
+ * of assuming that input PNG data with no gamma information is linear - this
+ * is unlikely to be correct unless the PNG files where generated locally.
+ * Most of the time the output precision will be so low as to show
+ * significant banding in dark areas of the image.
+ *
+ * png_set_expand_16(pp);
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);
+ * This is a somewhat more realistic Jim Blinn inspired approach. PNG files
+ * are assumed to have the sRGB encoding if not marked with a gamma value and
+ * the output is always 16 bits per component. This permits accurate scaling
+ * and processing of the data. If you know that your input PNG files were
+ * generated locally you might need to replace PNG_DEFAULT_sRGB with the
+ * correct value for your system.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);
+ * If you just need to composite the PNG image onto an existing background
+ * and if you control the code that does this you can use the optimization
+ * setting. In this case you just copy completely opaque pixels to the
+ * output. For pixels that are not completely transparent (you just skip
+ * those) you do the composition math using png_composite or png_composite_16
+ * below then encode the resultant 8-bit or 16-bit values to match the output
+ * encoding.
+ *
+ * Other cases
+ * If neither the PNG nor the standard linear encoding work for you because
+ * of the software or hardware you use then you have a big problem. The PNG
+ * case will probably result in halos around the image. The linear encoding
+ * will probably result in a washed out, too bright, image (it's actually too
+ * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably
+ * substantially reduce the halos. Alternatively try:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);
+ * This option will also reduce the halos, but there will be slight dark
+ * halos round the opaque parts of the image where the background is light.
+ * In the OPTIMIZED mode the halos will be light halos where the background
+ * is dark. Take your pick - the halos are unavoidable unless you can get
+ * your hardware/software fixed! (The OPTIMIZED approach is slightly
+ * faster.)
+ *
+ * When the default gamma of PNG files doesn't match the output gamma.
+ * If you have PNG files with no gamma information png_set_alpha_mode allows
+ * you to provide a default gamma, but it also sets the output gamma to the
+ * matching value. If you know your PNG files have a gamma that doesn't
+ * match the output you can take advantage of the fact that
+ * png_set_alpha_mode always sets the output gamma but only sets the PNG
+ * default if it is not already set:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ * The first call sets both the default and the output gamma values, the
+ * second call overrides the output gamma without changing the default. This
+ * is easier than achieving the same effect with png_set_gamma. You must use
+ * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will
+ * fire if more than one call to png_set_alpha_mode and png_set_background is
+ * made in the same read operation, however multiple calls with PNG_ALPHA_PNG
+ * are ignored.
+ */
+
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
-extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
-extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr));
+PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
-/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */
-extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
- png_uint_32 filler, int flags));
+/* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */
+PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler,
+ int flags));
/* The values of the PNG_FILLER_ defines should NOT be changed */
-#define PNG_FILLER_BEFORE 0
-#define PNG_FILLER_AFTER 1
-/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */
-#if !defined(PNG_1_0_X)
-extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr,
- png_uint_32 filler, int flags));
-#endif
-#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+# define PNG_FILLER_BEFORE 0
+# define PNG_FILLER_AFTER 1
+/* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */
+PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr,
+ png_uint_32 filler, int flags));
+#endif /* READ_FILLER || WRITE_FILLER */
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
/* Swap bytes in 16-bit depth files. */
-extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
-extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
+ defined(PNG_WRITE_PACKSWAP_SUPPORTED)
/* Swap packing order of pixels in bytes. */
-extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
/* Converts files to legal bit depths. */
-extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
- png_color_8p true_bits));
+PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p
+ true_bits));
#endif
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
defined(PNG_WRITE_INTERLACING_SUPPORTED)
-/* Have the code handle the interlacing. Returns the number of passes. */
-extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+/* Have the code handle the interlacing. Returns the number of passes.
+ * MUST be called before png_read_update_info or png_start_read_image,
+ * otherwise it will not have the desired effect. Note that it is still
+ * necessary to call png_read_row or png_read_rows png_get_image_height
+ * times for each pass.
+*/
+PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr));
#endif
#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
/* Invert monochrome files */
-extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
-/* Handle alpha and tRNS by replacing with a background color. */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
- png_color_16p background_color, int background_gamma_code,
- int need_expand, double background_gamma));
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+/* Handle alpha and tRNS by replacing with a background color. Prior to
+ * libpng-1.5.4 this API must not be called before the PNG file header has been
+ * read. Doing so will result in unexpected behavior and possible warnings or
+ * errors if the PNG file contains a bKGD chunk.
+ */
+PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr,
+ png_const_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma))
+PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr,
+ png_const_color_16p background_color, int background_gamma_code,
+ int need_expand, png_fixed_point background_gamma))
#endif
-#define PNG_BACKGROUND_GAMMA_UNKNOWN 0
-#define PNG_BACKGROUND_GAMMA_SCREEN 1
-#define PNG_BACKGROUND_GAMMA_FILE 2
-#define PNG_BACKGROUND_GAMMA_UNIQUE 3
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+# define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+# define PNG_BACKGROUND_GAMMA_SCREEN 1
+# define PNG_BACKGROUND_GAMMA_FILE 2
+# define PNG_BACKGROUND_GAMMA_UNIQUE 3
#endif
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
-/* strip the second byte of information from a 16-bit depth file. */
-extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+/* Scale a 16-bit depth file down to 8-bit, accurately. */
+PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_DITHER_SUPPORTED)
-/* Turn on dithering, and reduce the palette to the number of colors available. */
-extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
- png_colorp palette, int num_palette, int maximum_colors,
- png_uint_16p histogram, int full_dither));
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+#define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */
+/* Strip the second byte of information from a 16-bit depth file. */
+PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr));
#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-/* Handle gamma correction. Screen_gamma=(display_exponent) */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
- double screen_gamma, double default_file_gamma));
-#endif
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+/* Turn on quantizing, and reduce the palette to the number of colors
+ * available.
+ */
+PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr,
+ png_colorp palette, int num_palette, int maximum_colors,
+ png_const_uint_16p histogram, int full_quantize));
#endif
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
- defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
-/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */
-/* Deprecated and will be removed. Use png_permit_mng_features() instead. */
-extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr,
- int empty_plte_permitted));
-#endif
+#ifdef PNG_READ_GAMMA_SUPPORTED
+/* The threshold on gamma processing is configurable but hard-wired into the
+ * library. The following is the floating point variant.
+ */
+#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001)
+
+/* Handle gamma correction. Screen_gamma=(display_exponent).
+ * NOTE: this API simply sets the screen and file gamma values. It will
+ * therefore override the value for gamma in a PNG file if it is called after
+ * the file header has been read - use with care - call before reading the PNG
+ * file for best results!
+ *
+ * These routines accept the same gamma values as png_set_alpha_mode (described
+ * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either
+ * API (floating point or fixed.) Notice, however, that the 'file_gamma' value
+ * is the inverse of a 'screen gamma' value.
+ */
+PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr,
+ double screen_gamma, double override_file_gamma))
+PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr,
+ png_fixed_point screen_gamma, png_fixed_point override_file_gamma))
#endif
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
/* Set how many lines between output flushes - 0 for no flushing */
-extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
+PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows));
/* Flush the current PNG output buffer */
-extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
+PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr));
#endif
-/* optional update palette with requested transformations */
-extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
+/* Optional update palette with requested transformations */
+PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr));
-/* optional call to update the users info structure */
-extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
+/* Optional call to update the users info structure */
+PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr,
+ png_inforp info_ptr));
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-/* read one or more rows of image data. */
-extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
- png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read one or more rows of image data. */
+PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows));
#endif
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-/* read a row of data. */
-extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
- png_bytep row,
- png_bytep display_row));
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read a row of data. */
+PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row,
+ png_bytep display_row));
#endif
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-/* read the whole image into memory at once. */
-extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
- png_bytepp image));
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the whole image into memory at once. */
+PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image));
#endif
-/* write a row of image data */
-extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
- png_bytep row));
+/* Write a row of image data */
+PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr,
+ png_const_bytep row));
-/* write a few rows of image data */
-extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
- png_bytepp row, png_uint_32 num_rows));
+/* Write a few rows of image data: (*row) is not written; however, the type
+ * is declared as writeable to maintain compatibility with previous versions
+ * of libpng and to allow the 'display_row' array from read_rows to be passed
+ * unchanged to write_rows.
+ */
+PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row,
+ png_uint_32 num_rows));
-/* write the image data */
-extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
- png_bytepp image));
+/* Write the image data */
+PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image));
-/* writes the end of the PNG file. */
-extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
+/* Write the end of the PNG file. */
+PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr,
+ png_inforp info_ptr));
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-/* read the end of the PNG file. */
-extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
- png_infop info_ptr));
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the end of the PNG file. */
+PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr));
#endif
-/* free any memory associated with the png_info_struct */
-extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
- png_infopp info_ptr_ptr));
+/* Free any memory associated with the png_info_struct */
+PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr,
+ png_infopp info_ptr_ptr));
-/* free any memory associated with the png_struct and the png_info_structs */
-extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
- png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+/* Free any memory associated with the png_struct and the png_info_structs */
+PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr,
+ png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
-/* free all memory used by the read (old method - NOT DLL EXPORTED) */
-extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_infop end_info_ptr));
+/* Free any memory associated with the png_struct and the png_info_structs */
+PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr,
+ png_infopp info_ptr_ptr));
-/* free any memory associated with the png_struct and the png_info_structs */
-extern PNG_EXPORT(void,png_destroy_write_struct)
- PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
+/* Set the libpng method of handling chunk CRC errors */
+PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
+ int ancil_action));
-/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
-extern void png_write_destroy PNGARG((png_structp png_ptr));
-
-/* set the libpng method of handling chunk CRC errors */
-extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
- int crit_action, int ancil_action));
-
-/* Values for png_set_crc_action() to say how to handle CRC errors in
+/* Values for png_set_crc_action() say how to handle CRC errors in
* ancillary and critical chunks, and whether to use the data contained
* therein. Note that it is impossible to "discard" data in a critical
* chunk. For versions prior to 0.90, the action was always error/quit,
@@ -1794,19 +1439,21 @@ extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */
#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */
+#ifdef PNG_WRITE_SUPPORTED
/* These functions give the user control over the scan-line filtering in
* libpng and the compression methods used by zlib. These functions are
* mainly useful for testing, as the defaults should work with most users.
* Those users who are tight on memory or want faster performance at the
* expense of compression can modify them. See the compression library
- * header file (zlib.h) for an explination of the compression functions.
+ * header file (zlib.h) for an explanation of the compression functions.
*/
-/* set the filtering method(s) used by libpng. Currently, the only valid
+/* Set the filtering method(s) used by libpng. Currently, the only valid
* value for "method" is 0.
*/
-extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
- int filters));
+PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
+ int filters));
+#endif /* WRITE */
/* Flags for png_set_filter() to say which filters to use. The flags
* are chosen so that they don't conflict with real filter types
@@ -1819,8 +1466,8 @@ extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
#define PNG_FILTER_UP 0x20
#define PNG_FILTER_AVG 0x40
#define PNG_FILTER_PAETH 0x80
-#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
- PNG_FILTER_AVG | PNG_FILTER_PAETH)
+#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP)
+#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH)
/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
* These defines should NOT be changed.
@@ -1832,45 +1479,18 @@ extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
#define PNG_FILTER_VALUE_PAETH 4
#define PNG_FILTER_VALUE_LAST 5
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
-/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
- * defines, either the default (minimum-sum-of-absolute-differences), or
- * the experimental method (weighted-minimum-sum-of-absolute-differences).
- *
- * Weights are factors >= 1.0, indicating how important it is to keep the
- * filter type consistent between rows. Larger numbers mean the current
- * filter is that many times as likely to be the same as the "num_weights"
- * previous filters. This is cumulative for each previous row with a weight.
- * There needs to be "num_weights" values in "filter_weights", or it can be
- * NULL if the weights aren't being specified. Weights have no influence on
- * the selection of the first row filter. Well chosen weights can (in theory)
- * improve the compression for a given image.
- *
- * Costs are factors >= 1.0 indicating the relative decoding costs of a
- * filter type. Higher costs indicate more decoding expense, and are
- * therefore less likely to be selected over a filter with lower computational
- * costs. There needs to be a value in "filter_costs" for each valid filter
- * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
- * setting the costs. Costs try to improve the speed of decompression without
- * unduly increasing the compressed image size.
- *
- * A negative weight or cost indicates the default value is to be used, and
- * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
- * The default values for both weights and costs are currently 1.0, but may
- * change if good general weighting/cost heuristics can be found. If both
- * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
- * to the UNWEIGHTED method, but with added encoding time/computation.
- */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
- int heuristic_method, int num_weights, png_doublep filter_weights,
- png_doublep filter_costs));
-#endif
-#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
+PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr,
+ int heuristic_method, int num_weights, png_const_doublep filter_weights,
+ png_const_doublep filter_costs))
+PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
+ (png_structrp png_ptr, int heuristic_method, int num_weights,
+ png_const_fixed_point_p filter_weights,
+ png_const_fixed_point_p filter_costs))
+#endif /* WRITE_WEIGHTED_FILTER */
-/* Heuristic used for row filter selection. These defines should NOT be
- * changed.
- */
+/* The following are no longer used and will be removed from libpng-1.7: */
#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
@@ -1880,36 +1500,63 @@ extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
* 0 - 9, corresponding directly to the zlib compression levels 0 - 9
* (0 - no compression, 9 - "maximal" compression). Note that tests have
* shown that zlib compression levels 3-6 usually perform as well as level 9
- * for PNG images, and do considerably fewer caclulations. In the future,
+ * for PNG images, and do considerably fewer calculations. In the future,
* these values may not correspond directly to the zlib compression levels.
*/
-extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
- int level));
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr,
+ int level));
-extern PNG_EXPORT(void,png_set_compression_mem_level)
- PNGARG((png_structp png_ptr, int mem_level));
+PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr,
+ int mem_level));
-extern PNG_EXPORT(void,png_set_compression_strategy)
- PNGARG((png_structp png_ptr, int strategy));
+PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr,
+ int strategy));
-extern PNG_EXPORT(void,png_set_compression_window_bits)
- PNGARG((png_structp png_ptr, int window_bits));
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr,
+ int window_bits));
-extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
- int method));
+PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr,
+ int method));
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
+
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+/* Also set zlib parameters for compressing non-IDAT chunks */
+PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr,
+ int level));
+
+PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr,
+ int mem_level));
+
+PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr,
+ int strategy));
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+PNG_EXPORT(225, void, png_set_text_compression_window_bits,
+ (png_structrp png_ptr, int window_bits));
+
+PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
+ int method));
+#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
+#endif /* WRITE */
/* These next functions are called for input/output, memory, and error
* handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
* and call standard C I/O routines such as fread(), fwrite(), and
* fprintf(). These functions can be made to use other I/O routines
* at run time for those applications that need to handle I/O in a
- * different manner by calling png_set_???_fn(). See libpng.txt for
+ * different manner by calling png_set_???_fn(). See libpng-manual.txt for
* more information.
*/
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_STDIO_SUPPORTED
/* Initialize the input/output for the PNG file to the default functions. */
-extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp));
+PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
#endif
/* Replace the (error and abort), and warning functions with user
@@ -1920,188 +1567,256 @@ extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp))
* default function will be used.
*/
-extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
- png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
/* Return the user pointer associated with the error functions */
-extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
+PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));
/* Replace the default data output functions with a user supplied one(s).
* If buffered output is not used, then output_flush_fn can be set to NULL.
* If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
* output_flush_fn will be ignored (and thus can be NULL).
+ * It is probably a mistake to use NULL for output_flush_fn if
+ * write_data_fn is not also NULL unless you have built libpng with
+ * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's
+ * default flush function, which uses the standard *FILE structure, will
+ * be used.
*/
-extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
- png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
/* Replace the default data input function with a user supplied one. */
-extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
- png_voidp io_ptr, png_rw_ptr read_data_fn));
+PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn));
/* Return the user pointer associated with the I/O functions */
-extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
+PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));
-extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr,
- png_read_status_ptr read_row_fn));
+PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr,
+ png_read_status_ptr read_row_fn));
-extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr,
- png_write_status_ptr write_row_fn));
+PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr,
+ png_write_status_ptr write_row_fn));
#ifdef PNG_USER_MEM_SUPPORTED
/* Replace the default memory allocation functions with user supplied one(s). */
-extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr,
- png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
/* Return the user pointer associated with the memory functions */
-extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr));
+PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr));
#endif
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
-extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp
- png_ptr, png_user_transform_ptr read_user_transform_fn));
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr,
+ png_user_transform_ptr read_user_transform_fn));
#endif
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
-extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp
- png_ptr, png_user_transform_ptr write_user_transform_fn));
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr,
+ png_user_transform_ptr write_user_transform_fn));
#endif
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
-extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp
- png_ptr, png_voidp user_transform_ptr, int user_transform_depth,
- int user_transform_channels));
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
+PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr,
+ png_voidp user_transform_ptr, int user_transform_depth,
+ int user_transform_channels));
/* Return the user pointer associated with the user transform functions */
-extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr)
- PNGARG((png_structp png_ptr));
+PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr,
+ (png_const_structrp png_ptr));
+#endif
+
+#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
+/* Return information about the row currently being processed. Note that these
+ * APIs do not fail but will return unexpected results if called outside a user
+ * transform callback. Also note that when transforming an interlaced image the
+ * row number is the row number within the sub-image of the interlace pass, so
+ * the value will increase to the height of the sub-image (not the full image)
+ * then reset to 0 for the next pass.
+ *
+ * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to
+ * find the output pixel (x,y) given an interlaced sub-image pixel
+ * (row,col,pass). (See below for these macros.)
+ */
+PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp));
+PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp));
+#endif
+
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+/* This callback is called only for *unknown* chunks. If
+ * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known
+ * chunks to be treated as unknown, however in this case the callback must do
+ * any processing required by the chunk (e.g. by calling the appropriate
+ * png_set_ APIs.)
+ *
+ * There is no write support - on write, by default, all the chunks in the
+ * 'unknown' list are written in the specified position.
+ *
+ * The integer return from the callback function is interpreted thus:
+ *
+ * negative: An error occurred; png_chunk_error will be called.
+ * zero: The chunk was not handled, the chunk will be saved. A critical
+ * chunk will cause an error at this point unless it is to be saved.
+ * positive: The chunk was handled, libpng will ignore/discard it.
+ *
+ * See "INTERACTION WITH USER CHUNK CALLBACKS" below for important notes about
+ * how this behavior will change in libpng 1.7
+ */
+PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr,
+ png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
#endif
#ifdef PNG_USER_CHUNKS_SUPPORTED
-extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr,
- png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
-extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp
- png_ptr));
+PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr));
#endif
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
/* Sets the function callbacks for the push reader, and a pointer to a
* user-defined structure available to the callback functions.
*/
-extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
- png_voidp progressive_ptr,
- png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
- png_progressive_end_ptr end_fn));
+PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr,
+ png_voidp progressive_ptr, png_progressive_info_ptr info_fn,
+ png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn));
-/* returns the user pointer associated with the push read functions */
-extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
- PNGARG((png_structp png_ptr));
+/* Returns the user pointer associated with the push read functions */
+PNG_EXPORT(91, png_voidp, png_get_progressive_ptr,
+ (png_const_structrp png_ptr));
-/* function to be called when data becomes available */
-extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+/* Function to be called when data becomes available */
+PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr,
+ png_inforp info_ptr, png_bytep buffer, size_t buffer_size));
-/* function that combines rows. Not very much different than the
- * png_combine_row() call. Is this even used?????
+/* A function which may be called *only* within png_process_data to stop the
+ * processing of any more data. The function returns the number of bytes
+ * remaining, excluding any that libpng has cached internally. A subsequent
+ * call to png_process_data must supply these bytes again. If the argument
+ * 'save' is set to true the routine will first save all the pending data and
+ * will always return 0.
*/
-extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
- png_bytep old_row, png_bytep new_row));
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+PNG_EXPORT(219, size_t, png_process_data_pause, (png_structrp, int save));
-extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
- png_uint_32 size));
+/* A function which may be called *only* outside (after) a call to
+ * png_process_data. It returns the number of bytes of data to skip in the
+ * input. Normally it will return 0, but if it returns a non-zero value the
+ * application must skip than number of bytes of input data and pass the
+ * following data to the next call to png_process_data.
+ */
+PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp));
+
+/* Function that combines rows. 'new_row' is a flag that should come from
+ * the callback and be non-NULL if anything needs to be done; the library
+ * stores its own version of the new data internally and ignores the passed
+ * in value.
+ */
+PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr,
+ png_bytep old_row, png_const_bytep new_row));
+#endif /* PROGRESSIVE_READ */
+
+PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr,
+ png_alloc_size_t size), PNG_ALLOCATED);
+/* Added at libpng version 1.4.0 */
+PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr,
+ png_alloc_size_t size), PNG_ALLOCATED);
-#if defined(PNG_1_0_X)
-# define png_malloc_warn png_malloc
-#else
/* Added at libpng version 1.2.4 */
-extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr,
- png_uint_32 size));
-#endif
+PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr,
+ png_alloc_size_t size), PNG_ALLOCATED);
-/* frees a pointer allocated by png_malloc() */
-extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
-
-#if defined(PNG_1_0_X)
-/* Function to allocate memory for zlib. */
-extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items,
- uInt size));
-
-/* Function to free memory for zlib */
-extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr));
-#endif
+/* Frees a pointer allocated by png_malloc() */
+PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));
/* Free data that was allocated internally */
-extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 free_me, int num));
-#ifdef PNG_FREE_ME_SUPPORTED
-/* Reassign responsibility for freeing existing data, whether allocated
- * by libpng or by the application */
-extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int freer, png_uint_32 mask));
-#endif
-/* assignments for png_data_freer */
+PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_uint_32 free_me, int num));
+
+/* Reassign the responsibility for freeing existing data, whether allocated
+ * by libpng or by the application; this works on the png_info structure passed
+ * in, without changing the state for other png_info structures.
+ */
+PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int freer, png_uint_32 mask));
+
+/* Assignments for png_data_freer */
#define PNG_DESTROY_WILL_FREE_DATA 1
#define PNG_SET_WILL_FREE_DATA 1
#define PNG_USER_WILL_FREE_DATA 2
/* Flags for png_ptr->free_me and info_ptr->free_me */
-#define PNG_FREE_HIST 0x0008
-#define PNG_FREE_ICCP 0x0010
-#define PNG_FREE_SPLT 0x0020
-#define PNG_FREE_ROWS 0x0040
-#define PNG_FREE_PCAL 0x0080
-#define PNG_FREE_SCAL 0x0100
-#define PNG_FREE_UNKN 0x0200
-#define PNG_FREE_LIST 0x0400
-#define PNG_FREE_PLTE 0x1000
-#define PNG_FREE_TRNS 0x2000
-#define PNG_FREE_TEXT 0x4000
-#define PNG_FREE_ALL 0x7fff
-#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
+#define PNG_FREE_HIST 0x0008U
+#define PNG_FREE_ICCP 0x0010U
+#define PNG_FREE_SPLT 0x0020U
+#define PNG_FREE_ROWS 0x0040U
+#define PNG_FREE_PCAL 0x0080U
+#define PNG_FREE_SCAL 0x0100U
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+# define PNG_FREE_UNKN 0x0200U
+#endif
+/* PNG_FREE_LIST 0x0400U removed in 1.6.0 because it is ignored */
+#define PNG_FREE_PLTE 0x1000U
+#define PNG_FREE_TRNS 0x2000U
+#define PNG_FREE_TEXT 0x4000U
+#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */
+#define PNG_FREE_ALL 0xffffU
+#define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
#ifdef PNG_USER_MEM_SUPPORTED
-extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr,
- png_uint_32 size));
-extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr,
- png_voidp ptr));
+PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr,
+ png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED);
+PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr,
+ png_voidp ptr), PNG_DEPRECATED);
#endif
-extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr,
- png_voidp s1, png_voidp s2, png_uint_32 size));
-
-extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr,
- png_voidp s1, int value, png_uint_32 size));
-
-#if defined(USE_FAR_KEYWORD) /* memory model conversion function */
-extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,
- int check));
-#endif /* USE_FAR_KEYWORD */
-
-#ifndef PNG_NO_ERROR_TEXT
+#ifdef PNG_ERROR_TEXT_SUPPORTED
/* Fatal error in PNG image of libpng - can't continue */
-extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
- png_const_charp error_message));
+PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr,
+ png_const_charp error_message), PNG_NORETURN);
/* The same, but the chunk name is prepended to the error string. */
-extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr,
- png_const_charp error_message));
+PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr,
+ png_const_charp error_message), PNG_NORETURN);
+
#else
/* Fatal error in PNG image of libpng - can't continue */
-extern PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr));
+PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN);
+# define png_error(s1,s2) png_err(s1)
+# define png_chunk_error(s1,s2) png_err(s1)
#endif
-#ifndef PNG_NO_WARNINGS
+#ifdef PNG_WARNINGS_SUPPORTED
/* Non-fatal error in libpng. Can continue, but may have a problem. */
-extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
- png_const_charp warning_message));
+PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr,
+ png_const_charp warning_message));
+
+/* Non-fatal error in libpng, chunk name is prepended to message. */
+PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr,
+ png_const_charp warning_message));
+#else
+# define png_warning(s1,s2) ((void)(s1))
+# define png_chunk_warning(s1,s2) ((void)(s1))
+#endif
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+/* Benign error in libpng. Can continue, but may have a problem.
+ * User can choose whether to handle as a fatal error or as a warning. */
+PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr,
+ png_const_charp warning_message));
#ifdef PNG_READ_SUPPORTED
-/* Non-fatal error in libpng, chunk name is prepended to message. */
-extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr,
- png_const_charp warning_message));
-#endif /* PNG_READ_SUPPORTED */
-#endif /* PNG_NO_WARNINGS */
+/* Same, chunk name is prepended to message (only during read) */
+PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr,
+ png_const_charp warning_message));
+#endif
+
+PNG_EXPORT(109, void, png_set_benign_errors,
+ (png_structrp png_ptr, int allowed));
+#else
+# ifdef PNG_ALLOW_BENIGN_ERRORS
+# define png_benign_error png_warning
+# define png_chunk_benign_error png_chunk_warning
+# else
+# define png_benign_error png_error
+# define png_chunk_benign_error png_chunk_error
+# endif
+#endif
/* The png_set_ functions are for storing values in the png_info_struct.
* Similarly, the png_get_ calls are used to read values from the
@@ -2116,421 +1831,510 @@ extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr,
* png_info_struct.
*/
/* Returns "flag" if chunk data is valid in info_ptr. */
-extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
-png_infop info_ptr, png_uint_32 flag));
+PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 flag));
/* Returns number of bytes needed to hold a transformed row. */
-extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
-png_infop info_ptr));
+PNG_EXPORT(111, size_t, png_get_rowbytes, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
+#ifdef PNG_INFO_IMAGE_SUPPORTED
/* Returns row_pointers, which is an array of pointers to scanlines that was
-returned from png_read_png(). */
-extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr,
-png_infop info_ptr));
+ * returned from png_read_png().
+ */
+PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
+
/* Set row_pointers, which is an array of pointers to scanlines for use
-by png_write_png(). */
-extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_bytepp row_pointers));
+ * by png_write_png().
+ */
+PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_bytepp row_pointers));
#endif
/* Returns number of color channels in image. */
-extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
-png_infop info_ptr));
+PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
#ifdef PNG_EASY_ACCESS_SUPPORTED
/* Returns image width in pixels. */
-extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image height in pixels. */
-extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image bit_depth. */
-extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image color_type. */
-extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image filter_type. */
-extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image interlace_type. */
-extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image compression_type. */
-extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
/* Returns image resolution in pixels per meter, from pHYs chunk data. */
-extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
/* Returns pixel aspect ratio, computed from pHYs chunk data. */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-#endif
+PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr))
+PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr))
/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
-extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
-extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp
-png_ptr, png_infop info_ptr));
+PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(128, png_int_32, png_get_x_offset_microns,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(129, png_int_32, png_get_y_offset_microns,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
-#endif /* PNG_EASY_ACCESS_SUPPORTED */
+#endif /* EASY_ACCESS */
+#ifdef PNG_READ_SUPPORTED
/* Returns pointer to signature string read from PNG header */
-extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-#if defined(PNG_bKGD_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_color_16p *background));
+PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr));
#endif
-#if defined(PNG_bKGD_SUPPORTED)
-extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_color_16p background));
+#ifdef PNG_bKGD_SUPPORTED
+PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_color_16p *background));
#endif
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
- png_infop 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));
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr,
- png_infop 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));
-#endif
+#ifdef PNG_bKGD_SUPPORTED
+PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_color_16p background));
#endif
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
- png_infop 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));
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr,
- png_infop 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));
-#endif
+#ifdef PNG_cHRM_SUPPORTED
+PNG_FP_EXPORT(133, png_uint_32, 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))
+PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z,
+ double *green_X, double *green_Y, double *green_Z, double *blue_X,
+ double *blue_Y, double *blue_Z))
+PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_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))
+PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+ png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+ png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+ png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+ png_fixed_point *int_blue_Z))
#endif
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
- png_infop info_ptr, double *file_gamma));
-#endif
-extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_fixed_point *int_file_gamma));
+#ifdef PNG_cHRM_SUPPORTED
+PNG_FP_EXPORT(135, void, png_set_cHRM, (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))
+PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr,
+ png_inforp info_ptr, double red_X, double red_Y, double red_Z,
+ double green_X, double green_Y, double green_Z, double blue_X,
+ double blue_Y, double blue_Z))
+PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr,
+ png_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))
+PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
+ png_fixed_point int_red_Z, png_fixed_point int_green_X,
+ png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+ png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+ png_fixed_point int_blue_Z))
#endif
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
- png_infop info_ptr, double file_gamma));
-#endif
-extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_fixed_point int_file_gamma));
+#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));
+PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_bytep exif));
+
+PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif));
+PNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_uint_32 num_exif, png_bytep exif));
#endif
-#if defined(PNG_hIST_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_16p *hist));
+#ifdef PNG_gAMA_SUPPORTED
+PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, double *file_gamma))
+PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_fixed_point *int_file_gamma))
#endif
-#if defined(PNG_hIST_SUPPORTED)
-extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_16p hist));
+#ifdef PNG_gAMA_SUPPORTED
+PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr,
+ png_inforp info_ptr, double file_gamma))
+PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_fixed_point int_file_gamma))
#endif
-extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
- int *bit_depth, int *color_type, int *interlace_method,
- int *compression_method, int *filter_method));
+#ifdef PNG_hIST_SUPPORTED
+PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_uint_16p *hist));
+PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_uint_16p hist));
+#endif
-extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
- int color_type, int interlace_method, int compression_method,
- int filter_method));
+PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height,
+ int *bit_depth, int *color_type, int *interlace_method,
+ int *compression_method, int *filter_method));
-#if defined(PNG_oFFs_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
+PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_method, int compression_method,
+ int filter_method));
+
+#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,
int *unit_type));
#endif
-#if defined(PNG_oFFs_SUPPORTED)
-extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y,
- int unit_type));
+#ifdef PNG_oFFs_SUPPORTED
+PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y,
+ int unit_type));
#endif
-#if defined(PNG_pCAL_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
- int *type, int *nparams, png_charp *units, png_charpp *params));
+#ifdef PNG_pCAL_SUPPORTED
+PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_charp *purpose, png_int_32 *X0,
+ png_int_32 *X1, int *type, int *nparams, png_charp *units,
+ png_charpp *params));
#endif
-#if defined(PNG_pCAL_SUPPORTED)
-extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
- int type, int nparams, png_charp units, png_charpp params));
+#ifdef PNG_pCAL_SUPPORTED
+PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1,
+ int type, int nparams, png_const_charp units, png_charpp params));
#endif
-#if defined(PNG_pHYs_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
+ int *unit_type));
#endif
-#if defined(PNG_pHYs_SUPPORTED)
-extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
#endif
-extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_colorp *palette, int *num_palette));
+PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_colorp *palette, int *num_palette));
-extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_colorp palette, int num_palette));
+PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr,
+ png_inforp info_ptr, png_const_colorp palette, int num_palette));
-#if defined(PNG_sBIT_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_color_8p *sig_bit));
+#ifdef PNG_sBIT_SUPPORTED
+PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_color_8p *sig_bit));
#endif
-#if defined(PNG_sBIT_SUPPORTED)
-extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_color_8p sig_bit));
+#ifdef PNG_sBIT_SUPPORTED
+PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_color_8p sig_bit));
#endif
-#if defined(PNG_sRGB_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int *intent));
+#ifdef PNG_sRGB_SUPPORTED
+PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, int *file_srgb_intent));
#endif
-#if defined(PNG_sRGB_SUPPORTED)
-extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int intent));
-extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int intent));
+#ifdef PNG_sRGB_SUPPORTED
+PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int srgb_intent));
+PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int srgb_intent));
#endif
-#if defined(PNG_iCCP_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_charpp name, int *compression_type,
- png_charpp profile, png_uint_32 *proflen));
- /* Note to maintainer: profile should be png_bytepp */
+#ifdef PNG_iCCP_SUPPORTED
+PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_charpp name, int *compression_type,
+ png_bytepp profile, png_uint_32 *proflen));
#endif
-#if defined(PNG_iCCP_SUPPORTED)
-extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_charp name, int compression_type,
- png_charp profile, png_uint_32 proflen));
- /* Note to maintainer: profile should be png_bytep */
+#ifdef PNG_iCCP_SUPPORTED
+PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_charp name, int compression_type,
+ png_const_bytep profile, png_uint_32 proflen));
#endif
-#if defined(PNG_sPLT_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_sPLT_tpp entries));
+#ifdef PNG_sPLT_SUPPORTED
+PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_sPLT_tpp entries));
#endif
-#if defined(PNG_sPLT_SUPPORTED)
-extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_sPLT_tp entries, int nentries));
+#ifdef PNG_sPLT_SUPPORTED
+PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_sPLT_tp entries, int nentries));
#endif
-#if defined(PNG_TEXT_SUPPORTED)
+#ifdef PNG_TEXT_SUPPORTED
/* png_get_text also returns the number of text chunks in *num_text */
-extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_textp *text_ptr, int *num_text));
+PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_textp *text_ptr, int *num_text));
#endif
-/*
- * Note while png_set_text() will accept a structure whose text,
- * language, and translated keywords are NULL pointers, the structure
- * returned by png_get_text will always contain regular
- * zero-terminated C strings. They might be empty strings but
- * they will never be NULL pointers.
+/* Note while png_set_text() will accept a structure whose text,
+ * language, and translated keywords are NULL pointers, the structure
+ * returned by png_get_text will always contain regular
+ * zero-terminated C strings. They might be empty strings but
+ * they will never be NULL pointers.
*/
-#if defined(PNG_TEXT_SUPPORTED)
-extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_textp text_ptr, int num_text));
+#ifdef PNG_TEXT_SUPPORTED
+PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_textp text_ptr, int num_text));
#endif
-#if defined(PNG_tIME_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_timep *mod_time));
+#ifdef PNG_tIME_SUPPORTED
+PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_timep *mod_time));
#endif
-#if defined(PNG_tIME_SUPPORTED)
-extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_timep mod_time));
+#ifdef PNG_tIME_SUPPORTED
+PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_timep mod_time));
#endif
-#if defined(PNG_tRNS_SUPPORTED)
-extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_bytep *trans, int *num_trans,
- png_color_16p *trans_values));
+#ifdef PNG_tRNS_SUPPORTED
+PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans,
+ png_color_16p *trans_color));
#endif
-#if defined(PNG_tRNS_SUPPORTED)
-extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_bytep trans, int num_trans,
- png_color_16p trans_values));
+#ifdef PNG_tRNS_SUPPORTED
+PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr,
+ png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans,
+ png_const_color_16p trans_color));
#endif
-#if defined(PNG_tRNS_SUPPORTED)
+#ifdef PNG_sCAL_SUPPORTED
+PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, int *unit, double *width, double *height))
+#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
+/* NOTE: this API is currently implemented using floating point arithmetic,
+ * consequently it can only be used on systems with floating point support.
+ * In any case the range of values supported by png_fixed_point is small and it
+ * is highly recommended that png_get_sCAL_s be used instead.
+ */
+PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
+ png_fixed_point *width, png_fixed_point *height))
#endif
+PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
+ png_charpp swidth, png_charpp sheight));
-#if defined(PNG_sCAL_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int *unit, double *width, double *height));
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight));
-#endif
-#endif
-#endif /* PNG_sCAL_SUPPORTED */
+PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int unit, double width, double height))
+PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int unit, png_fixed_point width,
+ png_fixed_point height))
+PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int unit,
+ png_const_charp swidth, png_const_charp sheight));
+#endif /* sCAL */
-#if defined(PNG_sCAL_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int unit, double width, double height));
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int unit, png_charp swidth, png_charp sheight));
-#endif
-#endif
-#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-/* provide a list of chunks and how they are to be handled, if the built-in
- handling or default unknown chunk handling is not desired. Any chunks not
- listed will be handled in the default manner. The IHDR and IEND chunks
- must not be listed.
- keep = 0: follow default behaviour
- = 1: do not keep
- = 2: keep only if safe-to-copy
- = 3: keep even if unsafe-to-copy
-*/
-extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp
- png_ptr, int keep, png_bytep chunk_list, int num_chunks));
-extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns));
-extern PNG_EXPORT(void, png_set_unknown_chunk_location)
- PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location));
-extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp
- png_ptr, png_infop info_ptr, png_unknown_chunkpp entries));
-#endif
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+/* Provide the default handling for all unknown chunks or, optionally, for
+ * specific unknown chunks.
+ *
+ * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was
+ * ignored and the default was used, the per-chunk setting only had an effect on
+ * write. If you wish to have chunk-specific handling on read in code that must
+ * work on earlier versions you must use a user chunk callback to specify the
+ * desired handling (keep or discard.)
+ *
+ * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The
+ * parameter is interpreted as follows:
+ *
+ * READ:
+ * PNG_HANDLE_CHUNK_AS_DEFAULT:
+ * Known chunks: do normal libpng processing, do not keep the chunk (but
+ * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
+ * Unknown chunks: for a specific chunk use the global default, when used
+ * as the default discard the chunk data.
+ * PNG_HANDLE_CHUNK_NEVER:
+ * Discard the chunk data.
+ * PNG_HANDLE_CHUNK_IF_SAFE:
+ * Keep the chunk data if the chunk is not critical else raise a chunk
+ * error.
+ * PNG_HANDLE_CHUNK_ALWAYS:
+ * Keep the chunk data.
+ *
+ * If the chunk data is saved it can be retrieved using png_get_unknown_chunks,
+ * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent
+ * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks
+ * it simply resets the behavior to the libpng default.
+ *
+ * INTERACTION WITH USER CHUNK CALLBACKS:
+ * The per-chunk handling is always used when there is a png_user_chunk_ptr
+ * callback and the callback returns 0; the chunk is then always stored *unless*
+ * it is critical and the per-chunk setting is other than ALWAYS. Notice that
+ * the global default is *not* used in this case. (In effect the per-chunk
+ * value is incremented to at least IF_SAFE.)
+ *
+ * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and
+ * per-chunk defaults will be honored. If you want to preserve the current
+ * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE
+ * as the default - if you don't do this libpng 1.6 will issue a warning.
+ *
+ * If you want unhandled unknown chunks to be discarded in libpng 1.6 and
+ * earlier simply return '1' (handled).
+ *
+ * PNG_HANDLE_AS_UNKNOWN_SUPPORTED:
+ * If this is *not* set known chunks will always be handled by libpng and
+ * will never be stored in the unknown chunk list. Known chunks listed to
+ * png_set_keep_unknown_chunks will have no effect. If it is set then known
+ * chunks listed with a keep other than AS_DEFAULT will *never* be processed
+ * by libpng, in addition critical chunks must either be processed by the
+ * callback or saved.
+ *
+ * The IHDR and IEND chunks must not be listed. Because this turns off the
+ * default handling for chunks that would otherwise be recognized the
+ * behavior of libpng transformations may well become incorrect!
+ *
+ * WRITE:
+ * When writing chunks the options only apply to the chunks specified by
+ * png_set_unknown_chunks (below), libpng will *always* write known chunks
+ * required by png_set_ calls and will always write the core critical chunks
+ * (as required for PLTE).
+ *
+ * Each chunk in the png_set_unknown_chunks list is looked up in the
+ * png_set_keep_unknown_chunks list to find the keep setting, this is then
+ * interpreted as follows:
+ *
+ * PNG_HANDLE_CHUNK_AS_DEFAULT:
+ * Write safe-to-copy chunks and write other chunks if the global
+ * default is set to _ALWAYS, otherwise don't write this chunk.
+ * PNG_HANDLE_CHUNK_NEVER:
+ * Do not write the chunk.
+ * PNG_HANDLE_CHUNK_IF_SAFE:
+ * Write the chunk if it is safe-to-copy, otherwise do not write it.
+ * PNG_HANDLE_CHUNK_ALWAYS:
+ * Write the chunk.
+ *
+ * Note that the default behavior is effectively the opposite of the read case -
+ * in read unknown chunks are not stored by default, in write they are written
+ * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different
+ * - on write the safe-to-copy bit is checked, on read the critical bit is
+ * checked and on read if the chunk is critical an error will be raised.
+ *
+ * num_chunks:
+ * ===========
+ * If num_chunks is positive, then the "keep" parameter specifies the manner
+ * for handling only those chunks appearing in the chunk_list array,
+ * otherwise the chunk list array is ignored.
+ *
+ * If num_chunks is 0 the "keep" parameter specifies the default behavior for
+ * unknown chunks, as described above.
+ *
+ * If num_chunks is negative, then the "keep" parameter specifies the manner
+ * for handling all unknown chunks plus all chunks recognized by libpng
+ * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to
+ * be processed by libpng.
+ */
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep
- chunk_name));
+PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr,
+ int keep, png_const_bytep chunk_list, int num_chunks));
+#endif /* HANDLE_AS_UNKNOWN */
+
+/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned;
+ * the result is therefore true (non-zero) if special handling is required,
+ * false for the default handling.
+ */
+PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr,
+ png_const_bytep chunk_name));
+#endif /* SET_UNKNOWN_CHUNKS */
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_unknown_chunkp unknowns,
+ int num_unknowns));
+ /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added
+ * unknowns to the location currently stored in the png_struct. This is
+ * invariably the wrong value on write. To fix this call the following API
+ * for each chunk in the list with the correct location. If you know your
+ * code won't be compiled on earlier versions you can rely on
+ * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing
+ * the correct thing.
+ */
+
+PNG_EXPORT(175, void, png_set_unknown_chunk_location,
+ (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location));
+
+PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_unknown_chunkpp entries));
#endif
/* Png_free_data() will turn off the "valid" flag for anything it frees.
- If you need to turn it off for a chunk that your application has freed,
- you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */
-extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr,
- png_infop info_ptr, int mask));
-
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
-/* The "params" pointer is currently not used and is for future expansion. */
-extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr,
- png_infop info_ptr,
- int transforms,
- png_voidp params));
-extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
- png_infop info_ptr,
- int transforms,
- png_voidp params));
-#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
- * libpng yet, but more support will be added as needed.
+ * If you need to turn it off for a chunk that your application has freed,
+ * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK);
*/
-#ifdef PNG_DEBUG
-#if (PNG_DEBUG > 0)
-#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)
-#include
-#if (PNG_DEBUG > 1)
-#define png_debug(l,m) _RPT0(_CRT_WARN,m)
-#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1)
-#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2)
+PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr,
+ png_inforp info_ptr, int mask));
+
+#ifdef PNG_INFO_IMAGE_SUPPORTED
+/* The "params" pointer is currently not used and is for future expansion. */
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr,
+ int transforms, png_voidp params));
#endif
-#else /* PNG_DEBUG_FILE || !_MSC_VER */
-#ifndef PNG_DEBUG_FILE
-#define PNG_DEBUG_FILE stderr
-#endif /* PNG_DEBUG_FILE */
-#if (PNG_DEBUG > 1)
-#define png_debug(l,m) \
-{ \
- int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
-}
-#define png_debug1(l,m,p1) \
-{ \
- int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
-}
-#define png_debug2(l,m,p1,p2) \
-{ \
- int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
-}
-#endif /* (PNG_DEBUG > 1) */
-#endif /* _MSC_VER */
-#endif /* (PNG_DEBUG > 0) */
-#endif /* PNG_DEBUG */
-#ifndef png_debug
-#define png_debug(l, m)
+#ifdef PNG_WRITE_SUPPORTED
+PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr,
+ int transforms, png_voidp params));
#endif
-#ifndef png_debug1
-#define png_debug1(l, m, p1)
-#endif
-#ifndef png_debug2
-#define png_debug2(l, m, p1, p2)
#endif
-extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr));
-extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr));
-extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr));
-extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr));
+PNG_EXPORT(180, png_const_charp, png_get_copyright,
+ (png_const_structrp png_ptr));
+PNG_EXPORT(181, png_const_charp, png_get_header_ver,
+ (png_const_structrp png_ptr));
+PNG_EXPORT(182, png_const_charp, png_get_header_version,
+ (png_const_structrp png_ptr));
+PNG_EXPORT(183, png_const_charp, png_get_libpng_ver,
+ (png_const_structrp png_ptr));
#ifdef PNG_MNG_FEATURES_SUPPORTED
-extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp
- png_ptr, png_uint_32 mng_features_permitted));
+PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr,
+ png_uint_32 mng_features_permitted));
#endif
/* For use in png_set_keep_unknown, added to version 1.2.6 */
@@ -2538,94 +2342,151 @@ extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp
#define PNG_HANDLE_CHUNK_NEVER 1
#define PNG_HANDLE_CHUNK_IF_SAFE 2
#define PNG_HANDLE_CHUNK_ALWAYS 3
-
-/* Added to version 1.2.0 */
-#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
-#if defined(PNG_MMX_CODE_SUPPORTED)
-#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */
-#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */
-#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04
-#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08
-#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10
-#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20
-#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40
-#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80
-#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */
-
-#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
- | PNG_ASM_FLAG_MMX_READ_INTERLACE \
- | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
- | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
- | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
- | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH )
-#define PNG_MMX_WRITE_FLAGS ( 0 )
-
-#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \
- | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \
- | PNG_MMX_READ_FLAGS \
- | PNG_MMX_WRITE_FLAGS )
-
-#define PNG_SELECT_READ 1
-#define PNG_SELECT_WRITE 2
-#endif /* PNG_MMX_CODE_SUPPORTED */
-
-#if !defined(PNG_1_0_X)
-/* pngget.c */
-extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask)
- PNGARG((int flag_select, int *compilerID));
-
-/* pngget.c */
-extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask)
- PNGARG((int flag_select));
-
-/* pngget.c */
-extern PNG_EXPORT(png_uint_32,png_get_asm_flags)
- PNGARG((png_structp png_ptr));
-
-/* pngget.c */
-extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold)
- PNGARG((png_structp png_ptr));
-
-/* pngget.c */
-extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold)
- PNGARG((png_structp png_ptr));
-
-/* pngset.c */
-extern PNG_EXPORT(void,png_set_asm_flags)
- PNGARG((png_structp png_ptr, png_uint_32 asm_flags));
-
-/* pngset.c */
-extern PNG_EXPORT(void,png_set_mmx_thresholds)
- PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold,
- png_uint_32 mmx_rowbytes_threshold));
-
-#endif /* PNG_1_0_X */
-
-#if !defined(PNG_1_0_X)
-/* png.c, pnggccrd.c, or pngvcrd.c */
-extern PNG_EXPORT(int,png_mmx_support) PNGARG((void));
-#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+#define PNG_HANDLE_CHUNK_LAST 4
/* Strip the prepended error numbers ("#nnn ") from error and warning
- * messages before passing them to the error or warning handler. */
+ * messages before passing them to the error or warning handler.
+ */
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp
- png_ptr, png_uint_32 strip_mode));
+PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr,
+ png_uint_32 strip_mode));
#endif
-#endif /* PNG_1_0_X */
-
-/* Added at libpng-1.2.6 */
+/* Added in libpng-1.2.6 */
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
-extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp
- png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max));
-extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp
- png_ptr));
-extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp
- png_ptr));
+PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr,
+ png_uint_32 user_width_max, png_uint_32 user_height_max));
+PNG_EXPORT(187, png_uint_32, png_get_user_width_max,
+ (png_const_structrp png_ptr));
+PNG_EXPORT(188, png_uint_32, png_get_user_height_max,
+ (png_const_structrp png_ptr));
+/* Added in libpng-1.4.0 */
+PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr,
+ png_uint_32 user_chunk_cache_max));
+PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max,
+ (png_const_structrp png_ptr));
+/* Added in libpng-1.4.1 */
+PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr,
+ png_alloc_size_t user_chunk_cache_max));
+PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max,
+ (png_const_structrp png_ptr));
#endif
-/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */
+#if defined(PNG_INCH_CONVERSIONS_SUPPORTED)
+PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_FP_EXPORT(196, float, png_get_x_offset_inches,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
+PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#endif
+
+PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr))
+#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
+PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,
+ (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#endif
+
+# ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
+ int *unit_type));
+# endif /* pHYs */
+#endif /* INCH_CONVERSIONS */
+
+/* Added in libpng-1.4.0 */
+#ifdef PNG_IO_STATE_SUPPORTED
+PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr));
+
+/* Removed from libpng 1.6; use png_get_io_chunk_type. */
+PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr),
+ PNG_DEPRECATED)
+
+PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
+ (png_const_structrp png_ptr));
+
+/* The flags returned by png_get_io_state() are the following: */
+# define PNG_IO_NONE 0x0000 /* no I/O at this moment */
+# define PNG_IO_READING 0x0001 /* currently reading */
+# define PNG_IO_WRITING 0x0002 /* currently writing */
+# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */
+# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */
+# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */
+# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */
+# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */
+# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */
+#endif /* IO_STATE */
+
+/* Interlace support. The following macros are always defined so that if
+ * libpng interlace handling is turned off the macros may be used to handle
+ * interlaced images within the application.
+ */
+#define PNG_INTERLACE_ADAM7_PASSES 7
+
+/* Two macros to return the first row and first column of the original,
+ * full, image which appears in a given pass. 'pass' is in the range 0
+ * to 6 and the result is in the range 0 to 7.
+ */
+#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7)
+#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7)
+
+/* A macro to return the offset between pixels in the output row for a pair of
+ * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that
+ * follows. Note that ROW_OFFSET is the offset from one row to the next whereas
+ * COL_OFFSET is from one column to the next, within a row.
+ */
+#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8)
+#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1))
+
+/* Two macros to help evaluate the number of rows or columns in each
+ * pass. This is expressed as a shift - effectively log2 of the number or
+ * rows or columns in each 8x8 tile of the original image.
+ */
+#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)
+#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)
+
+/* Hence two macros to determine the number of rows or columns in a given
+ * pass of an image given its height or width. In fact these macros may
+ * return non-zero even though the sub-image is empty, because the other
+ * dimension may be empty for a small image.
+ */
+#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass))
+#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass))
+
+/* For the reader row callbacks (both progressive and sequential) it is
+ * necessary to find the row in the output image given a row in an interlaced
+ * image, so two more macros:
+ */
+#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \
+ (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \
+ ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0))
+
+#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \
+ ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)
+#define PNG_COL_IN_INTERLACE_PASS(x, pass) \
+ ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
/* With these routines we avoid an integer divide, which will be slower on
@@ -2640,910 +2501,750 @@ extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp
* [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]
*/
- /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
+ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
-# define png_composite(composite, fg, alpha, bg) \
- { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \
- + (png_uint_16)(bg)*(png_uint_16)(255 - \
- (png_uint_16)(alpha)) + (png_uint_16)128); \
- (composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
+# define png_composite(composite, fg, alpha, bg) \
+ { \
+ png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \
+ * (png_uint_16)(alpha) \
+ + (png_uint_16)(bg)*(png_uint_16)(255 \
+ - (png_uint_16)(alpha)) + 128); \
+ (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); \
+ }
-# define png_composite_16(composite, fg, alpha, bg) \
- { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \
- + (png_uint_32)(bg)*(png_uint_32)(65535L - \
- (png_uint_32)(alpha)) + (png_uint_32)32768L); \
- (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
+# define png_composite_16(composite, fg, alpha, bg) \
+ { \
+ png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \
+ * (png_uint_32)(alpha) \
+ + (png_uint_32)(bg)*(65535 \
+ - (png_uint_32)(alpha)) + 32768); \
+ (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); \
+ }
-#else /* standard method using integer division */
+#else /* Standard method using integer division */
-# define png_composite(composite, fg, alpha, bg) \
- (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \
- (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
- (png_uint_16)127) / 255)
+# define png_composite(composite, fg, alpha, bg) \
+ (composite) = \
+ (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \
+ (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
+ 127) / 255))
-# define png_composite_16(composite, fg, alpha, bg) \
- (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
- (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \
- (png_uint_32)32767) / (png_uint_32)65535L)
+# define png_composite_16(composite, fg, alpha, bg) \
+ (composite) = \
+ (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+ (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \
+ 32767) / 65535))
+#endif /* READ_COMPOSITE_NODIV */
-#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
+#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf));
+PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf));
+PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf));
+#endif
-/* Inline macros to do direct reads of bytes from the input buffer. These
- * require that you are using an architecture that uses PNG byte ordering
- * (MSB first) and supports unaligned data storage. I think that PowerPC
- * in big-endian mode and 680x0 are the only ones that will support this.
- * The x86 line of processors definitely do not. The png_get_int_32()
- * routine also assumes we are using two's complement format for negative
- * values, which is almost certainly true.
- */
-#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
-# define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
-# define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
-# define png_get_int_32(buf) ( *((png_int_32p) (buf)))
-#else
-extern PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf));
-extern PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf));
-extern PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf));
-#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */
-extern PNG_EXPORT(png_uint_32,png_get_uint_31)
- PNGARG((png_structp png_ptr, png_bytep buf));
+PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr,
+ png_const_bytep buf));
/* No png_get_int_16 -- may be added if there's a real need for it. */
-/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
- */
-extern PNG_EXPORT(void,png_save_uint_32)
- PNGARG((png_bytep buf, png_uint_32 i));
-extern PNG_EXPORT(void,png_save_int_32)
- PNGARG((png_bytep buf, png_int_32 i));
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */
+#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i));
+#endif
+#ifdef PNG_SAVE_INT_32_SUPPORTED
+PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i));
+#endif
/* Place a 16-bit number into a buffer in PNG byte order.
* The parameter is declared unsigned int, not png_uint_16,
* just to avoid potential problems on pre-ANSI C compilers.
*/
-extern PNG_EXPORT(void,png_save_uint_16)
- PNGARG((png_bytep buf, unsigned int i));
+#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
/* No png_save_int_16 -- may be added if there's a real need for it. */
+#endif
-/* ************************************************************************* */
-
-/* These next functions are used internally in the code. They generally
- * shouldn't be used unless you are writing code to add or replace some
- * functionality in libpng. More information about most functions can
- * be found in the files where the functions are located.
+#ifdef PNG_USE_READ_MACROS
+/* Inline macros to do direct reads of bytes from the input buffer.
+ * The png_get_int_32() routine assumes we are using two's complement
+ * format for negative values, which is almost certainly true.
*/
+# define PNG_get_uint_32(buf) \
+ (((png_uint_32)(*(buf)) << 24) + \
+ ((png_uint_32)(*((buf) + 1)) << 16) + \
+ ((png_uint_32)(*((buf) + 2)) << 8) + \
+ ((png_uint_32)(*((buf) + 3))))
+ /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the
+ * function) incorrectly returned a value of type png_uint_32.
+ */
+# define PNG_get_uint_16(buf) \
+ ((png_uint_16) \
+ (((unsigned int)(*(buf)) << 8) + \
+ ((unsigned int)(*((buf) + 1)))))
-/* Various modes of operation, that are visible to applications because
- * they are used for unknown chunk location.
+# define PNG_get_int_32(buf) \
+ ((png_int_32)((*(buf) & 0x80) \
+ ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \
+ : (png_int_32)png_get_uint_32(buf)))
+
+/* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h,
+ * but defining a macro name prefixed with PNG_PREFIX.
*/
-#define PNG_HAVE_IHDR 0x01
-#define PNG_HAVE_PLTE 0x02
-#define PNG_HAVE_IDAT 0x04
-#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */
-#define PNG_HAVE_IEND 0x10
-
-#if defined(PNG_INTERNAL)
-
-/* More modes of operation. Note that after an init, mode is set to
- * zero automatically when the structure is created.
- */
-#define PNG_HAVE_gAMA 0x20
-#define PNG_HAVE_cHRM 0x40
-#define PNG_HAVE_sRGB 0x80
-#define PNG_HAVE_CHUNK_HEADER 0x100
-#define PNG_WROTE_tIME 0x200
-#define PNG_WROTE_INFO_BEFORE_PLTE 0x400
-#define PNG_BACKGROUND_IS_GRAY 0x800
-#define PNG_HAVE_PNG_SIGNATURE 0x1000
-#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
-
-/* flags for the transformations the PNG library does on the image data */
-#define PNG_BGR 0x0001
-#define PNG_INTERLACE 0x0002
-#define PNG_PACK 0x0004
-#define PNG_SHIFT 0x0008
-#define PNG_SWAP_BYTES 0x0010
-#define PNG_INVERT_MONO 0x0020
-#define PNG_DITHER 0x0040
-#define PNG_BACKGROUND 0x0080
-#define PNG_BACKGROUND_EXPAND 0x0100
- /* 0x0200 unused */
-#define PNG_16_TO_8 0x0400
-#define PNG_RGBA 0x0800
-#define PNG_EXPAND 0x1000
-#define PNG_GAMMA 0x2000
-#define PNG_GRAY_TO_RGB 0x4000
-#define PNG_FILLER 0x8000L
-#define PNG_PACKSWAP 0x10000L
-#define PNG_SWAP_ALPHA 0x20000L
-#define PNG_STRIP_ALPHA 0x40000L
-#define PNG_INVERT_ALPHA 0x80000L
-#define PNG_USER_TRANSFORM 0x100000L
-#define PNG_RGB_TO_GRAY_ERR 0x200000L
-#define PNG_RGB_TO_GRAY_WARN 0x400000L
-#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
- /* 0x800000L Unused */
-#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */
-#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */
- /* 0x4000000L unused */
- /* 0x8000000L unused */
- /* 0x10000000L unused */
- /* 0x20000000L unused */
- /* 0x40000000L unused */
-
-/* flags for png_create_struct */
-#define PNG_STRUCT_PNG 0x0001
-#define PNG_STRUCT_INFO 0x0002
-
-/* Scaling factor for filter heuristic weighting calculations */
-#define PNG_WEIGHT_SHIFT 8
-#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
-#define PNG_COST_SHIFT 3
-#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
-
-/* flags for the png_ptr->flags rather than declaring a byte for each one */
-#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
-#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
-#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
-#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
-#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
-#define PNG_FLAG_ZLIB_FINISHED 0x0020
-#define PNG_FLAG_ROW_INIT 0x0040
-#define PNG_FLAG_FILLER_AFTER 0x0080
-#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
-#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
-#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
-#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
-#define PNG_FLAG_FREE_PLTE 0x1000
-#define PNG_FLAG_FREE_TRNS 0x2000
-#define PNG_FLAG_FREE_HIST 0x4000
-#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L
-#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L
-#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L
-#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L
-#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L
-#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L
-#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */
-#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */
- /* 0x800000L unused */
- /* 0x1000000L unused */
- /* 0x2000000L unused */
- /* 0x4000000L unused */
- /* 0x8000000L unused */
- /* 0x10000000L unused */
- /* 0x20000000L unused */
- /* 0x40000000L unused */
-
-#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
- PNG_FLAG_CRC_ANCILLARY_NOWARN)
-
-#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
- PNG_FLAG_CRC_CRITICAL_IGNORE)
-
-#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
- PNG_FLAG_CRC_CRITICAL_MASK)
-
-/* save typing and make code easier to understand */
-
-#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
- abs((int)((c1).green) - (int)((c2).green)) + \
- abs((int)((c1).blue) - (int)((c2).blue)))
-
-/* Added to libpng-1.2.6 JB */
-#define PNG_ROWBYTES(pixel_bits, width) \
- ((pixel_bits) >= 8 ? \
- ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \
- (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) )
-
-/* PNG_OUT_OF_RANGE returns true if value is outside the range
- ideal-delta..ideal+delta. Each argument is evaluated twice.
- "ideal" and "delta" should be constants, normally simple
- integers, "value" a variable. Added to libpng-1.2.6 JB */
-#define PNG_OUT_OF_RANGE(value, ideal, delta) \
- ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )
-
-/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
-#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
-/* place to hold the signature string for a PNG file. */
-#ifdef PNG_USE_GLOBAL_ARRAYS
- PNG_EXPORT_VAR (PNG_CONST png_byte FARDATA) png_sig[8];
+# ifndef PNG_PREFIX
+# define png_get_uint_32(buf) PNG_get_uint_32(buf)
+# define png_get_uint_16(buf) PNG_get_uint_16(buf)
+# define png_get_int_32(buf) PNG_get_int_32(buf)
+# endif
#else
-#endif
-#endif /* PNG_NO_EXTERN */
-
-/* Constant strings for known chunk types. If you need to add a chunk,
- * define the name here, and add an invocation of the macro in png.c and
- * wherever it's needed.
- */
-#define PNG_IHDR png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'}
-#define PNG_IDAT png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'}
-#define PNG_IEND png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'}
-#define PNG_PLTE png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'}
-#define PNG_bKGD png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'}
-#define PNG_cHRM png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'}
-#define PNG_gAMA png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'}
-#define PNG_hIST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'}
-#define PNG_iCCP png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'}
-#define PNG_iTXt png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'}
-#define PNG_oFFs png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'}
-#define PNG_pCAL png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'}
-#define PNG_sCAL png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'}
-#define PNG_pHYs png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'}
-#define PNG_sBIT png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'}
-#define PNG_sPLT png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'}
-#define PNG_sRGB png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'}
-#define PNG_tEXt png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'}
-#define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'}
-#define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'}
-#define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'}
-
-#ifdef PNG_USE_GLOBAL_ARRAYS
-PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_IDAT[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_IEND[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_PLTE[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_bKGD[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_cHRM[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_gAMA[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_hIST[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_iCCP[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_iTXt[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_oFFs[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_pCAL[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_sCAL[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_pHYs[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_sBIT[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_sPLT[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_sRGB[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_tEXt[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5];
-PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5];
-#endif /* PNG_USE_GLOBAL_ARRAYS */
-
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Initialize png_ptr struct for reading, and allocate any other memory.
- * (old interface - DEPRECATED - use png_create_read_struct instead).
- */
-extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr));
-#undef png_read_init
-#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \
- PNG_LIBPNG_VER_STRING, png_sizeof(png_struct));
-#endif
-
-extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr,
- png_const_charp user_png_ver, png_size_t png_struct_size));
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr,
- png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
- png_info_size));
-#endif
-
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Initialize png_ptr struct for writing, and allocate any other memory.
- * (old interface - DEPRECATED - use png_create_write_struct instead).
- */
-extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr));
-#undef png_write_init
-#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \
- PNG_LIBPNG_VER_STRING, png_sizeof(png_struct));
-#endif
-
-extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr,
- png_const_charp user_png_ver, png_size_t png_struct_size));
-extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr,
- png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
- png_info_size));
-
-/* Allocate memory for an internal libpng struct */
-PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
-
-/* Free memory from internal libpng struct */
-PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
-
-PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr
- malloc_fn, png_voidp mem_ptr));
-PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr,
- png_free_ptr free_fn, png_voidp mem_ptr));
-
-/* Free any memory that info_ptr points to and reset struct. */
-PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-
-#ifndef PNG_1_0_X
-/* Function to allocate memory for zlib. */
-PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
-
-/* Function to free memory for zlib */
-PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
-
-#ifdef PNG_SIZE_T
-/* Function to convert a sizeof an item to png_sizeof item */
- PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
-#endif
-
-/* Next four functions are used internally as callbacks. PNGAPI is required
- * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */
-
-PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr,
- png_bytep data, png_size_t length));
-
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr,
- png_bytep buffer, png_size_t length));
-#endif
-
-PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr,
- png_bytep data, png_size_t length));
-
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
-#if !defined(PNG_NO_STDIO)
-PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr));
-#endif
-#endif
-#else /* PNG_1_0_X */
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
- png_bytep buffer, png_size_t length));
-#endif
-#endif /* PNG_1_0_X */
-
-/* Reset the CRC variable */
-PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
-
-/* Write the "data" buffer to whatever output you are using. */
-PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
- png_size_t length));
-
-/* Read data from whatever input you are using into the "data" buffer */
-PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
- png_size_t length));
-
-/* Read bytes into buf, and update png_ptr->crc */
-PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
- png_size_t length));
-
-/* Decompress data in a chunk that uses compression */
-#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \
- defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
-PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr,
- int comp_type, png_charp chunkdata, png_size_t chunklength,
- png_size_t prefix_length, png_size_t *data_length));
-#endif
-
-/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
-PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
-
-/* Read the CRC from the file and compare it to the libpng calculated CRC */
-PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
-
-/* 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.
- */
-PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
- png_size_t length));
-
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
-PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
-#endif
-
-/* simple function to write the signature */
-PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
-
-/* write various chunks */
-
-/* Write the IHDR chunk, and update the png_struct with the necessary
- * information.
- */
-PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
- png_uint_32 height,
- int bit_depth, int color_type, int compression_method, int filter_method,
- int interlace_method));
-
-PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
- png_uint_32 num_pal));
-
-PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
- png_size_t length));
-
-PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
-
-#if defined(PNG_WRITE_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point
- file_gamma));
-#endif
-#endif
-
-#if defined(PNG_WRITE_sBIT_SUPPORTED)
-PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
- int color_type));
-#endif
-
-#if defined(PNG_WRITE_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_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));
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_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));
-#endif
-#endif
-
-#if defined(PNG_WRITE_sRGB_SUPPORTED)
-PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr,
- int intent));
-#endif
-
-#if defined(PNG_WRITE_iCCP_SUPPORTED)
-PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr,
- png_charp name, int compression_type,
- png_charp profile, int proflen));
- /* Note to maintainer: profile should be png_bytep */
-#endif
-
-#if defined(PNG_WRITE_sPLT_SUPPORTED)
-PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr,
- png_sPLT_tp palette));
-#endif
-
-#if defined(PNG_WRITE_tRNS_SUPPORTED)
-PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
- png_color_16p values, int number, int color_type));
-#endif
-
-#if defined(PNG_WRITE_bKGD_SUPPORTED)
-PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
- png_color_16p values, int color_type));
-#endif
-
-#if defined(PNG_WRITE_hIST_SUPPORTED)
-PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
- int num_hist));
-#endif
-
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
- defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
- png_charp key, png_charpp new_key));
-#endif
-
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
-PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
- png_charp text, png_size_t text_len));
-#endif
-
-#if defined(PNG_WRITE_zTXt_SUPPORTED)
-PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
- png_charp text, png_size_t text_len, int compression));
-#endif
-
-#if defined(PNG_WRITE_iTXt_SUPPORTED)
-PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr,
- int compression, png_charp key, png_charp lang, png_charp lang_key,
- png_charp text));
-#endif
-
-#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */
-PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_textp text_ptr, int num_text));
-#endif
-
-#if defined(PNG_WRITE_oFFs_SUPPORTED)
-PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
- png_int_32 x_offset, png_int_32 y_offset, int unit_type));
-#endif
-
-#if defined(PNG_WRITE_pCAL_SUPPORTED)
-PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
- png_int_32 X0, png_int_32 X1, int type, int nparams,
- png_charp units, png_charpp params));
-#endif
-
-#if defined(PNG_WRITE_pHYs_SUPPORTED)
-PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
- png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
- int unit_type));
-#endif
-
-#if defined(PNG_WRITE_tIME_SUPPORTED)
-PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
- png_timep mod_time));
-#endif
-
-#if defined(PNG_WRITE_sCAL_SUPPORTED)
-#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
-PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr,
- int unit, double width, double height));
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr,
- int unit, png_charp width, png_charp height));
-#endif
-#endif
-#endif
-
-/* Called when finished processing a row of data */
-PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
-
-/* Internal use only. Called before first row of data */
-PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
-
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
-#endif
-
-/* combine a row of data, dealing with alpha, etc. if requested */
-PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
- int mask));
-
-#if defined(PNG_READ_INTERLACING_SUPPORTED)
-/* expand an interlaced row */
-/* OLD pre-1.0.9 interface:
-PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
- png_bytep row, int pass, png_uint_32 transformations));
- */
-PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr));
-#endif
-
-/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */
-
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
-/* grab pixels out of a row for an interlaced pass */
-PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
- png_bytep row, int pass));
-#endif
-
-/* unfilter a row */
-PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
- png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
-
-/* Choose the best filter to use and filter the row data */
-PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
- png_row_infop row_info));
-
-/* Write out the filtered row. */
-PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
- png_bytep filtered_row));
-/* finish a row while reading, dealing with interlacing passes, etc. */
-PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
-
-/* initialize the row buffers, etc. */
-PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
-/* optional call to update the users info structure */
-PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-
-/* these are the functions that do the transformations */
-#if defined(PNG_READ_FILLER_SUPPORTED)
-PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
- png_bytep row, png_uint_32 filler, png_uint_32 flags));
-#endif
-
-#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
-PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
-PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
-PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
-PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
- defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
-PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
- png_bytep row, png_uint_32 flags));
-#endif
-
-#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
-PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
-PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop
- row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
-PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_READ_PACK_SUPPORTED)
-PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_SHIFT_SUPPORTED)
-PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
- png_color_8p sig_bits));
-#endif
-
-#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
-PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
-PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
-#endif
-
-#if defined(PNG_READ_DITHER_SUPPORTED)
-PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
- png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
-
-# if defined(PNG_CORRECT_PALETTE_SUPPORTED)
-PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
- png_colorp palette, int num_palette));
+# ifdef PNG_PREFIX
+ /* No macros; revert to the (redefined) function */
+# define PNG_get_uint_32 (png_get_uint_32)
+# define PNG_get_uint_16 (png_get_uint_16)
+# define PNG_get_int_32 (png_get_int_32)
# endif
#endif
-#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
-#endif
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+PNG_EXPORT(242, void, png_set_check_for_invalid_index,
+ (png_structrp png_ptr, int allowed));
+# ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr,
+ png_const_infop info_ptr));
+# endif
+#endif /* CHECK_FOR_INVALID_INDEX */
-#if defined(PNG_WRITE_PACK_SUPPORTED)
-PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
- png_bytep row, png_uint_32 bit_depth));
-#endif
+/*******************************************************************************
+ * Section 5: SIMPLIFIED API
+ *******************************************************************************
+ *
+ * Please read the documentation in libpng-manual.txt (TODO: write said
+ * documentation) if you don't understand what follows.
+ *
+ * The simplified API hides the details of both libpng and the PNG file format
+ * itself. It allows PNG files to be read into a very limited number of
+ * in-memory bitmap formats or to be written from the same formats. If these
+ * formats do not accommodate your needs then you can, and should, use the more
+ * sophisticated APIs above - these support a wide variety of in-memory formats
+ * and a wide variety of sophisticated transformations to those formats as well
+ * as a wide variety of APIs to manipulate ancillary information.
+ *
+ * To read a PNG file using the simplified API:
+ *
+ * 1) Declare a 'png_image' structure (see below) on the stack, set the
+ * version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL
+ * (this is REQUIRED, your program may crash if you don't do it.)
+ * 2) Call the appropriate png_image_begin_read... function.
+ * 3) Set the png_image 'format' member to the required sample format.
+ * 4) Allocate a buffer for the image and, if required, the color-map.
+ * 5) Call png_image_finish_read to read the image and, if required, the
+ * color-map into your buffers.
+ *
+ * There are no restrictions on the format of the PNG input itself; all valid
+ * color types, bit depths, and interlace methods are acceptable, and the
+ * input image is transformed as necessary to the requested in-memory format
+ * during the png_image_finish_read() step. The only caveat is that if you
+ * request a color-mapped image from a PNG that is full-color or makes
+ * complex use of an alpha channel the transformation is extremely lossy and the
+ * result may look terrible.
+ *
+ * To write a PNG file using the simplified API:
+ *
+ * 1) Declare a 'png_image' structure on the stack and memset() it to all zero.
+ * 2) Initialize the members of the structure that describe the image, setting
+ * the 'format' member to the format of the image samples.
+ * 3) Call the appropriate png_image_write... function with a pointer to the
+ * image and, if necessary, the color-map to write the PNG data.
+ *
+ * png_image is a structure that describes the in-memory format of an image
+ * when it is being read or defines the in-memory format of an image that you
+ * need to write:
+ */
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
-#if defined(PNG_WRITE_SHIFT_SUPPORTED)
-PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
- png_color_8p bit_depth));
-#endif
+#define PNG_IMAGE_VERSION 1
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
- png_color_16p trans_values, png_color_16p background,
- png_color_16p background_1,
- png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
- png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
- png_uint_16pp gamma_16_to_1, int gamma_shift));
-#else
-PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
- png_color_16p trans_values, png_color_16p background));
-#endif
-#endif
+typedef struct png_control *png_controlp;
+typedef struct
+{
+ png_controlp opaque; /* Initialize to NULL, free with png_image_free */
+ png_uint_32 version; /* Set to PNG_IMAGE_VERSION */
+ png_uint_32 width; /* Image width in pixels (columns) */
+ png_uint_32 height; /* Image height in pixels (rows) */
+ png_uint_32 format; /* Image format as defined below */
+ png_uint_32 flags; /* A bit mask containing informational flags */
+ png_uint_32 colormap_entries;
+ /* Number of entries in the color-map */
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
- png_bytep gamma_table, png_uint_16pp gamma_16_table,
- int gamma_shift));
-#endif
+ /* In the event of an error or warning the following field will be set to a
+ * non-zero value and the 'message' field will contain a '\0' terminated
+ * string with the libpng error or warning message. If both warnings and
+ * an error were encountered, only the error is recorded. If there
+ * are multiple warnings, only the first one is recorded.
+ *
+ * The upper 30 bits of this value are reserved, the low two bits contain
+ * a value as follows:
+ */
+# define PNG_IMAGE_WARNING 1
+# define PNG_IMAGE_ERROR 2
+ /*
+ * The result is a two-bit code such that a value more than 1 indicates
+ * a failure in the API just called:
+ *
+ * 0 - no warning or error
+ * 1 - warning
+ * 2 - error
+ * 3 - error preceded by warning
+ */
+# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1)
-#if defined(PNG_READ_EXPAND_SUPPORTED)
-PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
- png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
-PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
- png_bytep row, png_color_16p trans_value));
-#endif
+ png_uint_32 warning_or_error;
-/* The following decodes the appropriate chunks, and does error correction,
- * then calls the appropriate callback for the chunk if it is valid.
+ char message[64];
+} png_image, *png_imagep;
+
+/* The samples of the image have one to four channels whose components have
+ * original values in the range 0 to 1.0:
+ *
+ * 1: A single gray or luminance channel (G).
+ * 2: A gray/luminance channel and an alpha channel (GA).
+ * 3: Three red, green, blue color channels (RGB).
+ * 4: Three color channels and an alpha channel (RGBA).
+ *
+ * The components are encoded in one of two ways:
+ *
+ * a) As a small integer, value 0..255, contained in a single byte. For the
+ * alpha channel the original value is simply value/255. For the color or
+ * luminance channels the value is encoded according to the sRGB specification
+ * and matches the 8-bit format expected by typical display devices.
+ *
+ * The color/gray channels are not scaled (pre-multiplied) by the alpha
+ * channel and are suitable for passing to color management software.
+ *
+ * b) As a value in the range 0..65535, contained in a 2-byte integer. All
+ * channels can be converted to the original value by dividing by 65535; all
+ * channels are linear. Color channels use the RGB encoding (RGB end-points) of
+ * the sRGB specification. This encoding is identified by the
+ * PNG_FORMAT_FLAG_LINEAR flag below.
+ *
+ * When the simplified API needs to convert between sRGB and linear colorspaces,
+ * the actual sRGB transfer curve defined in the sRGB specification (see the
+ * article at ) is used, not the gamma=1/2.2
+ * approximation used elsewhere in libpng.
+ *
+ * When an alpha channel is present it is expected to denote pixel coverage
+ * of the color or luminance channels and is returned as an associated alpha
+ * channel: the color/gray channels are scaled (pre-multiplied) by the alpha
+ * value.
+ *
+ * The samples are either contained directly in the image data, between 1 and 8
+ * bytes per pixel according to the encoding, or are held in a color-map indexed
+ * by bytes in the image data. In the case of a color-map the color-map entries
+ * are individual samples, encoded as above, and the image data has one byte per
+ * pixel to select the relevant sample from the color-map.
*/
-/* decode the IHDR chunk */
-PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+/* PNG_FORMAT_*
+ *
+ * #defines to be used in png_image::format. Each #define identifies a
+ * particular layout of sample data and, if present, alpha values. There are
+ * separate defines for each of the two component encodings.
+ *
+ * A format is built up using single bit flag values. All combinations are
+ * valid. Formats can be built up from the flag values or you can use one of
+ * the predefined values below. When testing formats always use the FORMAT_FLAG
+ * macros to test for individual features - future versions of the library may
+ * add new flags.
+ *
+ * When reading or writing color-mapped images the format should be set to the
+ * format of the entries in the color-map then png_image_{read,write}_colormap
+ * called to read or write the color-map and set the format correctly for the
+ * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly!
+ *
+ * NOTE: libpng can be built with particular features disabled. If you see
+ * compiler errors because the definition of one of the following flags has been
+ * compiled out it is because libpng does not have the required support. It is
+ * possible, however, for the libpng configuration to enable the format on just
+ * read or just write; in that case you may see an error at run time. You can
+ * guard against this by checking for the definition of the appropriate
+ * "_SUPPORTED" macro, one of:
+ *
+ * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED
+ */
+#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */
+#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */
+#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2-byte channels else 1-byte */
+#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */
-#if defined(PNG_READ_bKGD_SUPPORTED)
-PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+#ifdef PNG_FORMAT_BGR_SUPPORTED
+# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
-PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+#ifdef PNG_FORMAT_AFIRST_SUPPORTED
+# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */
#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
-PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */
+
+/* Commonly used formats have predefined macros.
+ *
+ * First the single byte (sRGB) formats:
+ */
+#define PNG_FORMAT_GRAY 0
+#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA
+#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST)
+#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR
+#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR)
+#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST)
+#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST)
+
+/* Then the linear 2-byte formats. When naming these "Y" is used to
+ * indicate a luminance (gray) channel.
+ */
+#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR
+#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR)
+#define PNG_FORMAT_LINEAR_RGB_ALPHA \
+ (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA)
+
+/* With color-mapped formats the image data is one byte for each pixel, the byte
+ * is an index into the color-map which is formatted as above. To obtain a
+ * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP
+ * to one of the above definitions, or you can use one of the definitions below.
+ */
+#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP)
+
+/* PNG_IMAGE macros
+ *
+ * These are convenience macros to derive information from a png_image
+ * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the
+ * actual image sample values - either the entries in the color-map or the
+ * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values
+ * for the pixels and will always return 1 for color-mapped formats. The
+ * remaining macros return information about the rows in the image and the
+ * complete image.
+ *
+ * NOTE: All the macros that take a png_image::format parameter are compile time
+ * constants if the format parameter is, itself, a constant. Therefore these
+ * macros can be used in array declarations and case labels where required.
+ * Similarly the macros are also pre-processor constants (sizeof is not used) so
+ * they can be used in #if tests.
+ *
+ * First the information about the samples.
+ */
+#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\
+ (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1)
+ /* Return the total number of channels in a given format: 1..4 */
+
+#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\
+ ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1)
+ /* Return the size in bytes of a single component of a pixel or color-map
+ * entry (as appropriate) in the image: 1 or 2.
+ */
+
+#define PNG_IMAGE_SAMPLE_SIZE(fmt)\
+ (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt))
+ /* This is the size of the sample data for one sample. If the image is
+ * color-mapped it is the size of one color-map entry (and image pixels are
+ * one byte in size), otherwise it is the size of one image pixel.
+ */
+
+#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\
+ (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256)
+ /* The maximum size of the color-map required by the format expressed in a
+ * count of components. This can be used to compile-time allocate a
+ * color-map:
+ *
+ * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)];
+ *
+ * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)];
+ *
+ * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the
+ * information from one of the png_image_begin_read_ APIs and dynamically
+ * allocate the required memory.
+ */
+
+/* Corresponding information about the pixels */
+#define PNG_IMAGE_PIXEL_(test,fmt)\
+ (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt))
+
+#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\
+ PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt)
+ /* The number of separate channels (components) in a pixel; 1 for a
+ * color-mapped image.
+ */
+
+#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\
+ PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt)
+ /* The size, in bytes, of each component in a pixel; 1 for a color-mapped
+ * image.
+ */
+
+#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt)
+ /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */
+
+/* Information about the whole row, or whole image */
+#define PNG_IMAGE_ROW_STRIDE(image)\
+ (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width)
+ /* Return the total number of components in a single row of the image; this
+ * is the minimum 'row stride', the minimum count of components between each
+ * row. For a color-mapped image this is the minimum number of bytes in a
+ * row.
+ *
+ * WARNING: this macro overflows for some images with more than one component
+ * and very large image widths. libpng will refuse to process an image where
+ * this macro would overflow.
+ */
+
+#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\
+ (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride))
+ /* Return the size, in bytes, of an image buffer given a png_image and a row
+ * stride - the number of components to leave space for in each row.
+ *
+ * WARNING: this macro overflows a 32-bit integer for some large PNG images,
+ * libpng will refuse to process an image where such an overflow would occur.
+ */
+
+#define PNG_IMAGE_SIZE(image)\
+ PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image))
+ /* Return the size, in bytes, of the image in memory given just a png_image;
+ * the row stride is the minimum stride required for the image.
+ */
+
+#define PNG_IMAGE_COLORMAP_SIZE(image)\
+ (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries)
+ /* Return the size, in bytes, of the color-map of this image. If the image
+ * format is not a color-map format this will return a size sufficient for
+ * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if
+ * you don't want to allocate a color-map in this case.
+ */
+
+/* PNG_IMAGE_FLAG_*
+ *
+ * Flags containing additional information about the image are held in the
+ * 'flags' field of png_image.
+ */
+#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01
+ /* This indicates that the RGB values of the in-memory bitmap do not
+ * correspond to the red, green and blue end-points defined by sRGB.
+ */
+
+#define PNG_IMAGE_FLAG_FAST 0x02
+ /* On write emphasise speed over compression; the resultant PNG file will be
+ * larger but will be produced significantly faster, particular for large
+ * images. Do not use this option for images which will be distributed, only
+ * used it when producing intermediate files that will be read back in
+ * repeatedly. For a typical 24-bit image the option will double the read
+ * speed at the cost of increasing the image size by 25%, however for many
+ * more compressible images the PNG file can be 10 times larger with only a
+ * slight speed gain.
+ */
+
+#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04
+ /* On read if the image is a 16-bit per component image and there is no gAMA
+ * or sRGB chunk assume that the components are sRGB encoded. Notice that
+ * images output by the simplified API always have gamma information; setting
+ * this flag only affects the interpretation of 16-bit images from an
+ * external source. It is recommended that the application expose this flag
+ * to the user; the user can normally easily recognize the difference between
+ * linear and sRGB encoding. This flag has no effect on write - the data
+ * passed to the write APIs must have the correct encoding (as defined
+ * above.)
+ *
+ * If the flag is not set (the default) input 16-bit per component data is
+ * assumed to be linear.
+ *
+ * NOTE: the flag can only be set after the png_image_begin_read_ call,
+ * because that call initializes the 'flags' field.
+ */
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+/* READ APIs
+ * ---------
+ *
+ * The png_image passed to the read APIs must have been initialized by setting
+ * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
+ */
+#ifdef PNG_STDIO_SUPPORTED
+PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
+ const char *file_name));
+ /* The named file is opened for read and the image header is filled in
+ * from the PNG header in the file.
+ */
+
+PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
+ FILE* file));
+ /* The PNG header is read from the stdio FILE object. */
+#endif /* STDIO */
+
+PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image,
+ png_const_voidp memory, size_t size));
+ /* The PNG header is read from the given memory buffer. */
+
+PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image,
+ png_const_colorp background, void *buffer, png_int_32 row_stride,
+ void *colormap));
+ /* Finish reading the image into the supplied buffer and clean up the
+ * png_image structure.
+ *
+ * row_stride is the step, in byte or 2-byte units as appropriate,
+ * between adjacent rows. A positive stride indicates that the top-most row
+ * is first in the buffer - the normal top-down arrangement. A negative
+ * stride indicates that the bottom-most row is first in the buffer.
+ *
+ * background need only be supplied if an alpha channel must be removed from
+ * a png_byte format and the removal is to be done by compositing on a solid
+ * color; otherwise it may be NULL and any composition will be done directly
+ * onto the buffer. The value is an sRGB color to use for the background,
+ * for grayscale output the green channel is used.
+ *
+ * background must be supplied when an alpha channel must be removed from a
+ * single byte color-mapped output format, in other words if:
+ *
+ * 1) The original format from png_image_begin_read_from_* had
+ * PNG_FORMAT_FLAG_ALPHA set.
+ * 2) The format set by the application does not.
+ * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and
+ * PNG_FORMAT_FLAG_LINEAR *not* set.
+ *
+ * For linear output removing the alpha channel is always done by compositing
+ * on black and background is ignored.
+ *
+ * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must
+ * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE.
+ * image->colormap_entries will be updated to the actual number of entries
+ * written to the colormap; this may be less than the original value.
+ */
+
+PNG_EXPORT(238, void, png_image_free, (png_imagep image));
+ /* Free any data allocated by libpng in image->opaque, setting the pointer to
+ * NULL. May be called at any time after the structure is initialized.
+ */
+#endif /* SIMPLIFIED_READ */
+
+#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+/* WRITE APIS
+ * ----------
+ * For write you must initialize a png_image structure to describe the image to
+ * be written. To do this use memset to set the whole structure to 0 then
+ * initialize fields describing your image.
+ *
+ * version: must be set to PNG_IMAGE_VERSION
+ * opaque: must be initialized to NULL
+ * width: image width in pixels
+ * height: image height in rows
+ * format: the format of the data (image and color-map) you wish to write
+ * flags: set to 0 unless one of the defined flags applies; set
+ * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB
+ * values do not correspond to the colors in sRGB.
+ * colormap_entries: set to the number of entries in the color-map (0 to 256)
+ */
+#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
+PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
+ const char *file, int convert_to_8bit, const void *buffer,
+ png_int_32 row_stride, const void *colormap));
+ /* Write the image to the named file. */
+
+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*). */
+#endif /* SIMPLIFIED_WRITE_STDIO */
+
+/* With all write APIs if image is in one of the linear formats with 16-bit
+ * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG
+ * gamma encoded according to the sRGB specification, otherwise a 16-bit linear
+ * encoded PNG file is written.
+ *
+ * With color-mapped data formats the colormap parameter point to a color-map
+ * with at least image->colormap_entries encoded in the specified format. If
+ * the format is linear the written PNG color-map will be converted to sRGB
+ * regardless of the convert_to_8_bit flag.
+ *
+ * With all APIs row_stride is handled as in the read APIs - it is the spacing
+ * from one row to the next in component sized units (1 or 2 bytes) and if
+ * negative indicates a bottom-up row layout in the buffer. If row_stride is
+ * zero, libpng will calculate it for you from the image width and number of
+ * channels.
+ *
+ * Note that the write API does not support interlacing, sub-8-bit pixels or
+ * most ancillary chunks. If you need to write text chunks (e.g. for copyright
+ * notices) you need to use one of the other APIs.
+ */
+
+PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
+ png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit,
+ const void *buffer, png_int_32 row_stride, const void *colormap));
+ /* Write the image to the given memory buffer. The function both writes the
+ * whole PNG data stream to *memory and updates *memory_bytes with the count
+ * of bytes written.
+ *
+ * 'memory' may be NULL. In this case *memory_bytes is not read however on
+ * success the number of bytes which would have been written will still be
+ * stored in *memory_bytes. On failure *memory_bytes will contain 0.
+ *
+ * If 'memory' is not NULL it must point to memory[*memory_bytes] of
+ * writeable memory.
+ *
+ * If the function returns success memory[*memory_bytes] (if 'memory' is not
+ * NULL) contains the written PNG data. *memory_bytes will always be less
+ * than or equal to the original value.
+ *
+ * If the function returns false and *memory_bytes was not changed an error
+ * occurred during write. If *memory_bytes was changed, or is not 0 if
+ * 'memory' was NULL, the write would have succeeded but for the memory
+ * buffer being too small. *memory_bytes contains the required number of
+ * bytes and will be bigger that the original value.
+ */
+
+#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\
+ row_stride, colormap)\
+ png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\
+ row_stride, colormap)
+ /* Return the amount of memory in 'size' required to compress this image.
+ * The png_image structure 'image' must be filled in as in the above
+ * function and must not be changed before the actual write call, the buffer
+ * and all other parameters must also be identical to that in the final
+ * write call. The 'size' variable need not be initialized.
+ *
+ * NOTE: the macro returns true/false, if false is returned 'size' will be
+ * set to zero and the write failed and probably will fail if tried again.
+ */
+
+/* You can pre-allocate the buffer by making sure it is of sufficient size
+ * regardless of the amount of compression achieved. The buffer size will
+ * always be bigger than the original image and it will never be filled. The
+ * following macros are provided to assist in allocating the buffer.
+ */
+#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height)
+ /* The number of uncompressed bytes in the PNG byte encoding of the image;
+ * uncompressing the PNG IDAT data will give this number of bytes.
+ *
+ * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this
+ * macro can because of the extra bytes used in the PNG byte encoding. You
+ * need to avoid this macro if your image size approaches 2^30 in width or
+ * height. The same goes for the remainder of these macros; they all produce
+ * bigger numbers than the actual in-memory image size.
+ */
+#ifndef PNG_ZLIB_MAX_SIZE
+# define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U)
+ /* An upper bound on the number of compressed bytes given 'b' uncompressed
+ * bytes. This is based on deflateBounds() in zlib; different
+ * implementations of zlib compression may conceivably produce more data so
+ * if your zlib implementation is not zlib itself redefine this macro
+ * appropriately.
+ */
#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
-PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\
+ PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image))
+ /* An upper bound on the size of the data in the PNG IDAT chunks. */
+
+#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\
+ ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\
+ (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\
+ 12U+3U*(image).colormap_entries/*PLTE data*/+\
+ (((image).format&PNG_FORMAT_FLAG_ALPHA)?\
+ 12U/*tRNS*/+(image).colormap_entries:0U):0U)+\
+ 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size))
+ /* A helper for the following macro; if your compiler cannot handle the
+ * following macro use this one with the result of
+ * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most
+ * compilers should handle this just fine.)
+ */
+
+#define PNG_IMAGE_PNG_SIZE_MAX(image)\
+ PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image))
+ /* An upper bound on the total length of the PNG data stream for 'image'.
+ * The result is of type png_alloc_size_t, on 32-bit systems this may
+ * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will
+ * run out of buffer space but return a corrected size which should work.
+ */
+#endif /* SIMPLIFIED_WRITE */
+/*******************************************************************************
+ * END OF SIMPLIFIED API
+ ******************************************************************************/
+#endif /* SIMPLIFIED_{READ|WRITE} */
+
+/*******************************************************************************
+ * Section 6: IMPLEMENTATION OPTIONS
+ *******************************************************************************
+ *
+ * Support for arbitrary implementation-specific optimizations. The API allows
+ * particular options to be turned on or off. 'Option' is the number of the
+ * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given
+ * by the PNG_OPTION_ defines below.
+ *
+ * HARDWARE: normally hardware capabilities, such as the Intel SSE instructions,
+ * are detected at run time, however sometimes it may be impossible
+ * to do this in user mode, in which case it is necessary to discover
+ * the capabilities in an OS specific way. Such capabilities are
+ * listed here when libpng has support for them and must be turned
+ * ON by the application if present.
+ *
+ * SOFTWARE: sometimes software optimizations actually result in performance
+ * decrease on some architectures or systems, or with some sets of
+ * PNG images. 'Software' options allow such optimizations to be
+ * selected at run time.
+ */
+#ifdef PNG_SET_OPTION_SUPPORTED
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */
+#endif
+#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
+#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
+#ifdef PNG_MIPS_MSA_API_SUPPORTED
+# define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */
+#endif
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
+# define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
+#endif
+#ifdef PNG_POWERPC_VSX_API_SUPPORTED
+# define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions
+ * supported */
+#endif
+#ifdef PNG_MIPS_MMI_API_SUPPORTED
+# define PNG_MIPS_MMI 12 /* HARDWARE: MIPS MMI SIMD instructions supported */
#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
-extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif /* PNG_READ_iCCP_SUPPORTED */
+#define PNG_OPTION_NEXT 14 /* Next option - numbers must be even */
-#if defined(PNG_READ_iTXt_SUPPORTED)
-PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
+/* Return values: NOTE: there are four values and 'off' is *not* zero */
+#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
+#define PNG_OPTION_INVALID 1 /* Option number out of range */
+#define PNG_OPTION_OFF 2
+#define PNG_OPTION_ON 3
+
+PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
+ int onoff));
+#endif /* SET_OPTION */
+
+/*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
+
+/* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+ */
+
+/* The last ordinal number (this is the *last* one already used; the next
+ * one to use is one more than this.)
+ */
+#ifdef PNG_EXPORT_LAST_ORDINAL
+ PNG_EXPORT_LAST_ORDINAL(249);
#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
-PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_pCAL_SUPPORTED)
-PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_pHYs_SUPPORTED)
-PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_sBIT_SUPPORTED)
-PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_sCAL_SUPPORTED)
-PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_sPLT_SUPPORTED)
-extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif /* PNG_READ_sPLT_SUPPORTED */
-
-#if defined(PNG_READ_sRGB_SUPPORTED)
-PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_tEXt_SUPPORTED)
-PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_tIME_SUPPORTED)
-PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_tRNS_SUPPORTED)
-PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_zTXt_SUPPORTED)
-PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length));
-#endif
-
-PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 length));
-
-PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
- png_bytep chunk_name));
-
-/* handle the transformations for reading and writing */
-PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
-
-PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
-
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
- png_uint_32 length));
-PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
- png_bytep buffer, png_size_t buffer_length));
-PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
- png_bytep buffer, png_size_t buffer_length));
-PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 length));
-PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
-PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
-#if defined(PNG_READ_tEXt_SUPPORTED)
-PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 length));
-PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
-PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 length));
-PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
-PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr,
- png_infop info_ptr, png_uint_32 length));
-PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr,
- png_infop info_ptr));
-#endif
-
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-
-#ifdef PNG_MNG_FEATURES_SUPPORTED
-PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info,
- png_bytep row));
-PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info,
- png_bytep row));
-#endif
-
-#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
-#if defined(PNG_MMX_CODE_SUPPORTED)
-/* png.c */ /* PRIVATE */
-PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr));
-#endif
-#endif
-
-#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
-PNG_EXTERN png_uint_32 png_get_pixels_per_inch PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-PNG_EXTERN png_uint_32 png_get_x_pixels_per_inch PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-PNG_EXTERN png_uint_32 png_get_y_pixels_per_inch PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-PNG_EXTERN float png_get_x_offset_inches PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-PNG_EXTERN float png_get_y_offset_inches PNGARG((png_structp png_ptr,
-png_infop info_ptr));
-
-#if defined(PNG_pHYs_SUPPORTED)
-PNG_EXTERN png_uint_32 png_get_pHYs_dpi PNGARG((png_structp png_ptr,
-png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
-#endif /* PNG_pHYs_SUPPORTED */
-#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
-
-/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */
-
-#endif /* PNG_INTERNAL */
-
#ifdef __cplusplus
}
#endif
#endif /* PNG_VERSION_INFO_ONLY */
-/* do not put anything past this line */
+/* Do not put anything past this line */
#endif /* PNG_H */
diff --git a/PDF/include/Poco/PDF/pngconf.h b/PDF/include/Poco/PDF/pngconf.h
index b4bf1ba17..000d7b1a8 100644
--- a/PDF/include/Poco/PDF/pngconf.h
+++ b/PDF/include/Poco/PDF/pngconf.h
@@ -1,14 +1,18 @@
-/* pngconf.h - machine configurable file for libpng
+/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.2.24 - December 14, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
- */
-
-/* Any machine specific code is near the front of this file, so if you
+ * libpng version 1.6.43
+ *
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * Any machine specific code is near the front of this file, so if you
* are configuring libpng for a machine, you may want to read the section
* starting here down to where it starts to typedef png_color, png_text,
* and png_info.
@@ -17,1465 +21,603 @@
#ifndef PNGCONF_H
#define PNGCONF_H
-#define PNG_1_2_X
+#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */
-/*
- * PNG_USER_CONFIG has to be defined on the compiler command line. This
- * includes the resource compiler for Windows DLL configurations.
+/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C
+ * compiler for correct compilation. The following header files are required by
+ * the standard. If your compiler doesn't provide these header files, or they
+ * do not match the standard, you will need to provide/improve them.
*/
-#ifdef PNG_USER_CONFIG
-# ifndef PNG_USER_PRIVATEBUILD
-# define PNG_USER_PRIVATEBUILD
-# endif
-#include "pngusr.h"
-#endif
+#include
+#include
-/* PNG_CONFIGURE_LIBPNG is set by the "configure" script. */
-#ifdef PNG_CONFIGURE_LIBPNG
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#endif
-
-/*
- * Added at libpng-1.2.8
+/* Library header files. These header files are all defined by ISOC90; libpng
+ * expects conformant implementations, however, an ISOC90 conformant system need
+ * not provide these header files if the functionality cannot be implemented.
+ * In this case it will be necessary to disable the relevant parts of libpng in
+ * the build of pnglibconf.h.
*
- * If you create a private DLL you need to define in "pngusr.h" the followings:
- * #define PNG_USER_PRIVATEBUILD
- * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons."
- * #define PNG_USER_DLLFNAME_POSTFIX
- * e.g. // private DLL "libpng13gx.dll"
- * #define PNG_USER_DLLFNAME_POSTFIX "gx"
- *
- * The following macros are also at your disposal if you want to complete the
- * DLL VERSIONINFO structure.
- * - PNG_USER_VERSIONINFO_COMMENTS
- * - PNG_USER_VERSIONINFO_COMPANYNAME
- * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS
+ * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not
+ * include this unnecessary header file.
*/
-#ifdef __STDC__
-#ifdef SPECIALBUILD
-# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\
- are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.")
-#endif
-
-#ifdef PRIVATEBUILD
-# pragma message("PRIVATEBUILD is deprecated.\
- Use PNG_USER_PRIVATEBUILD instead.")
-# define PNG_USER_PRIVATEBUILD PRIVATEBUILD
-#endif
-#endif /* __STDC__ */
-
-#ifndef PNG_VERSION_INFO_ONLY
-
-/* End of material added to libpng-1.2.8 */
-
-/* Added at libpng-1.2.19, removed at libpng-1.2.20 because it caused trouble
- Restored at libpng-1.2.21 */
-#if !defined(PNG_NO_WARN_UNINITIALIZED_ROW) && \
- !defined(PNG_WARN_UNINITIALIZED_ROW)
-# define PNG_WARN_UNINITIALIZED_ROW 1
-#endif
-/* End of material added at libpng-1.2.19/1.2.21 */
-
-/* This is the size of the compression buffer, and thus the size of
- * an IDAT chunk. Make this whatever size you feel is best for your
- * machine. One of these will be allocated per png_struct. When this
- * is full, it writes the data to the disk, and does some other
- * calculations. Making this an extremely small size will slow
- * the library down, but you may want to experiment to determine
- * where it becomes significant, if you are concerned with memory
- * usage. Note that zlib allocates at least 32Kb also. For readers,
- * this describes the size of the buffer available to read the data in.
- * Unless this gets smaller than the size of a row (compressed),
- * it should not make much difference how big this is.
- */
-
-#ifndef PNG_ZBUF_SIZE
-# define PNG_ZBUF_SIZE 8192
-#endif
-
-/* Enable if you want a write-only libpng */
-
-#ifndef PNG_NO_READ_SUPPORTED
-# define PNG_READ_SUPPORTED
-#endif
-
-/* Enable if you want a read-only libpng */
-
-#ifndef PNG_NO_WRITE_SUPPORTED
-# define PNG_WRITE_SUPPORTED
-#endif
-
-/* Enabled by default in 1.2.0. You can disable this if you don't need to
- support PNGs that are embedded in MNG datastreams */
-#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES)
-# ifndef PNG_MNG_FEATURES_SUPPORTED
-# define PNG_MNG_FEATURES_SUPPORTED
-# endif
-#endif
-
-#ifndef PNG_NO_FLOATING_POINT_SUPPORTED
-# ifndef PNG_FLOATING_POINT_SUPPORTED
-# define PNG_FLOATING_POINT_SUPPORTED
-# endif
-#endif
-
-/* If you are running on a machine where you cannot allocate more
- * than 64K of memory at once, uncomment this. While libpng will not
- * normally need that much memory in a chunk (unless you load up a very
- * large file), zlib needs to know how big of a chunk it can use, and
- * libpng thus makes sure to check any memory allocation to verify it
- * will fit into memory.
-#define PNG_MAX_MALLOC_64K
- */
-#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
-# define PNG_MAX_MALLOC_64K
-#endif
-
-/* Special munging to support doing things the 'cygwin' way:
- * 'Normal' png-on-win32 defines/defaults:
- * PNG_BUILD_DLL -- building dll
- * PNG_USE_DLL -- building an application, linking to dll
- * (no define) -- building static library, or building an
- * application and linking to the static lib
- * 'Cygwin' defines/defaults:
- * PNG_BUILD_DLL -- (ignored) building the dll
- * (no define) -- (ignored) building an application, linking to the dll
- * PNG_STATIC -- (ignored) building the static lib, or building an
- * application that links to the static lib.
- * ALL_STATIC -- (ignored) building various static libs, or building an
- * application that links to the static libs.
- * Thus,
- * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and
- * this bit of #ifdefs will define the 'correct' config variables based on
- * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but
- * unnecessary.
- *
- * Also, the precedence order is:
- * ALL_STATIC (since we can't #undef something outside our namespace)
- * PNG_BUILD_DLL
- * PNG_STATIC
- * (nothing) == PNG_USE_DLL
- *
- * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent
- * of auto-import in binutils, we no longer need to worry about
- * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore,
- * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes
- * to __declspec() stuff. However, we DO need to worry about
- * PNG_BUILD_DLL and PNG_STATIC because those change some defaults
- * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed.
- */
-#if defined(__CYGWIN__)
-# if defined(ALL_STATIC)
-# if defined(PNG_BUILD_DLL)
-# undef PNG_BUILD_DLL
-# endif
-# if defined(PNG_USE_DLL)
-# undef PNG_USE_DLL
-# endif
-# if defined(PNG_DLL)
-# undef PNG_DLL
-# endif
-# if !defined(PNG_STATIC)
-# define PNG_STATIC
-# endif
-# else
-# if defined (PNG_BUILD_DLL)
-# if defined(PNG_STATIC)
-# undef PNG_STATIC
-# endif
-# if defined(PNG_USE_DLL)
-# undef PNG_USE_DLL
-# endif
-# if !defined(PNG_DLL)
-# define PNG_DLL
-# endif
-# else
-# if defined(PNG_STATIC)
-# if defined(PNG_USE_DLL)
-# undef PNG_USE_DLL
-# endif
-# if defined(PNG_DLL)
-# undef PNG_DLL
-# endif
-# else
-# if !defined(PNG_USE_DLL)
-# define PNG_USE_DLL
-# endif
-# if !defined(PNG_DLL)
-# define PNG_DLL
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* This protects us against compilers that run on a windowing system
- * and thus don't have or would rather us not use the stdio types:
- * stdin, stdout, and stderr. The only one currently used is stderr
- * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will
- * prevent these from being compiled and used. #defining PNG_NO_STDIO
- * will also prevent these, plus will prevent the entire set of stdio
- * macros and functions (FILE *, printf, etc.) from being compiled and used,
- * unless (PNG_DEBUG > 0) has been #defined.
- *
- * #define PNG_NO_CONSOLE_IO
- * #define PNG_NO_STDIO
- */
-
-#if defined(_WIN32_WCE)
-# include
- /* Console I/O functions are not supported on WindowsCE */
-# define PNG_NO_CONSOLE_IO
-# ifdef PNG_DEBUG
-# undef PNG_DEBUG
-# endif
-#endif
-
-#ifdef PNG_BUILD_DLL
-# ifndef PNG_CONSOLE_IO_SUPPORTED
-# ifndef PNG_NO_CONSOLE_IO
-# define PNG_NO_CONSOLE_IO
-# endif
-# endif
-#endif
-
-# ifdef PNG_NO_STDIO
-# ifndef PNG_NO_CONSOLE_IO
-# define PNG_NO_CONSOLE_IO
-# endif
-# ifdef PNG_DEBUG
-# if (PNG_DEBUG > 0)
-# include
-# endif
-# endif
-# else
-# if !defined(_WIN32_WCE)
-/* "stdio.h" functions are not supported on WindowsCE */
-# include
-# endif
-# endif
-
-/* This macro protects us against machines that don't have function
- * prototypes (ie K&R style headers). If your compiler does not handle
- * function prototypes, define this macro and use the included ansi2knr.
- * I've always been able to use _NO_PROTO as the indicator, but you may
- * need to drag the empty declaration out in front of here, or change the
- * ifdef to suit your own needs.
- */
-#ifndef PNGARG
-
-#ifdef OF /* zlib prototype munger */
-# define PNGARG(arglist) OF(arglist)
-#else
-
-#ifdef _NO_PROTO
-# define PNGARG(arglist) ()
-# ifndef PNG_TYPECAST_NULL
-# define PNG_TYPECAST_NULL
-# endif
-#else
-# define PNGARG(arglist) arglist
-#endif /* _NO_PROTO */
-
-
-#endif /* OF */
-
-#endif /* PNGARG */
-
-/* Try to determine if we are compiling on a Mac. Note that testing for
- * just __MWERKS__ is not good enough, because the Codewarrior is now used
- * on non-Mac platforms.
- */
-#ifndef MACOS
-# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
- defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
-# define MACOS
-# endif
-#endif
-
-/* enough people need this for various reasons to include it here */
-#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE)
-# include
-#endif
-
-#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED)
-# define PNG_SETJMP_SUPPORTED
+#ifdef PNG_STDIO_SUPPORTED
+ /* Required for the definition of FILE: */
+# include
#endif
#ifdef PNG_SETJMP_SUPPORTED
-/* This is an attempt to force a single setjmp behaviour on Linux. If
- * the X config stuff didn't define _BSD_SOURCE we wouldn't need this.
- */
-
-# ifdef __linux__
-# ifdef _BSD_SOURCE
-# define PNG_SAVE_BSD_SOURCE
-# undef _BSD_SOURCE
-# endif
-# ifdef _SETJMP_H
- /* If you encounter a compiler error here, see the explanation
- * near the end of INSTALL.
- */
- __pngconf.h__ already includes setjmp.h;
- __dont__ include it again.;
-# endif
-# endif /* __linux__ */
-
- /* include setjmp.h for error handling */
+ /* Required for the definition of jmp_buf and the declaration of longjmp: */
# include
-
-# ifdef __linux__
-# ifdef PNG_SAVE_BSD_SOURCE
-# ifndef _BSD_SOURCE
-# define _BSD_SOURCE
-# endif
-# undef PNG_SAVE_BSD_SOURCE
-# endif
-# endif /* __linux__ */
-#endif /* PNG_SETJMP_SUPPORTED */
-
-#ifdef BSD
-# include
-#else
-# include
#endif
-/* Other defines for things like memory and the like can go here. */
-#ifdef PNG_INTERNAL
+#ifdef PNG_CONVERT_tIME_SUPPORTED
+ /* Required for struct tm: */
+# include
+#endif
-#include
+#endif /* PNG_BUILDING_SYMBOL_TABLE */
-/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
- * aren't usually used outside the library (as far as I know), so it is
- * debatable if they should be exported at all. In the future, when it is
- * possible to have run-time registry of chunk-handling functions, some of
- * these will be made available again.
-#define PNG_EXTERN extern
+/* Prior to 1.6.0, it was possible to turn off 'const' in declarations,
+ * using PNG_NO_CONST. This is no longer supported.
*/
-#define PNG_EXTERN
+#define PNG_CONST const /* backward compatibility only */
-/* Other defines specific to compilers can go here. Try to keep
- * them inside an appropriate ifdef/endif pair for portability.
+/* This controls optimization of the reading of 16-bit and 32-bit
+ * values from PNG files. It can be set on a per-app-file basis: it
+ * just changes whether a macro is used when the function is called.
+ * The library builder sets the default; if read functions are not
+ * built into the library the macro implementation is forced on.
+ */
+#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED
+# define PNG_USE_READ_MACROS
+#endif
+#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS)
+# if PNG_DEFAULT_READ_MACROS
+# define PNG_USE_READ_MACROS
+# endif
+#endif
+
+/* COMPILER SPECIFIC OPTIONS.
+ *
+ * These options are provided so that a variety of difficult compilers
+ * can be used. Some are fixed at build time (e.g. PNG_API_RULE
+ * below) but still have compiler specific implementations, others
+ * may be changed on a per-file basis when compiling against libpng.
*/
-#if defined(PNG_FLOATING_POINT_SUPPORTED)
-# if defined(MACOS)
- /* We need to check that hasn't already been included earlier
- * as it seems it doesn't agree with , yet we should really use
- * if possible.
- */
-# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
-# include
+/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect
+ * against legacy (pre ISOC90) compilers that did not understand function
+ * prototypes. It is not required for modern C compilers.
+ */
+#ifndef PNGARG
+# define PNGARG(arglist) arglist
+#endif
+
+/* Function calling conventions.
+ * =============================
+ * Normally it is not necessary to specify to the compiler how to call
+ * a function - it just does it - however on x86 systems derived from
+ * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems
+ * and some others) there are multiple ways to call a function and the
+ * default can be changed on the compiler command line. For this reason
+ * libpng specifies the calling convention of every exported function and
+ * every function called via a user supplied function pointer. This is
+ * done in this file by defining the following macros:
+ *
+ * PNGAPI Calling convention for exported functions.
+ * PNGCBAPI Calling convention for user provided (callback) functions.
+ * PNGCAPI Calling convention used by the ANSI-C library (required
+ * for longjmp callbacks and sometimes used internally to
+ * specify the calling convention for zlib).
+ *
+ * These macros should never be overridden. If it is necessary to
+ * change calling convention in a private build this can be done
+ * by setting PNG_API_RULE (which defaults to 0) to one of the values
+ * below to select the correct 'API' variants.
+ *
+ * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout.
+ * This is correct in every known environment.
+ * PNG_API_RULE=1 Use the operating system convention for PNGAPI and
+ * the 'C' calling convention (from PNGCAPI) for
+ * callbacks (PNGCBAPI). This is no longer required
+ * in any known environment - if it has to be used
+ * please post an explanation of the problem to the
+ * libpng mailing list.
+ *
+ * These cases only differ if the operating system does not use the C
+ * calling convention, at present this just means the above cases
+ * (x86 DOS/Windows systems) and, even then, this does not apply to
+ * Cygwin running on those systems.
+ *
+ * Note that the value must be defined in pnglibconf.h so that what
+ * the application uses to call the library matches the conventions
+ * set when building the library.
+ */
+
+/* Symbol export
+ * =============
+ * When building a shared library it is almost always necessary to tell
+ * the compiler which symbols to export. The png.h macro 'PNG_EXPORT'
+ * is used to mark the symbols. On some systems these symbols can be
+ * extracted at link time and need no special processing by the compiler,
+ * on other systems the symbols are flagged by the compiler and just
+ * the declaration requires a special tag applied (unfortunately) in a
+ * compiler dependent way. Some systems can do either.
+ *
+ * A small number of older systems also require a symbol from a DLL to
+ * be flagged to the program that calls it. This is a problem because
+ * we do not know in the header file included by application code that
+ * the symbol will come from a shared library, as opposed to a statically
+ * linked one. For this reason the application must tell us by setting
+ * the magic flag PNG_USE_DLL to turn on the special processing before
+ * it includes png.h.
+ *
+ * Four additional macros are used to make this happen:
+ *
+ * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from
+ * the build or imported if PNG_USE_DLL is set - compiler
+ * and system specific.
+ *
+ * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to
+ * 'type', compiler specific.
+ *
+ * PNG_DLL_EXPORT Set to the magic to use during a libpng build to
+ * make a symbol exported from the DLL. Not used in the
+ * public header files; see pngpriv.h for how it is used
+ * in the libpng build.
+ *
+ * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come
+ * from a DLL - used to define PNG_IMPEXP when
+ * PNG_USE_DLL is set.
+ */
+
+/* System specific discovery.
+ * ==========================
+ * This code is used at build time to find PNG_IMPEXP, the API settings
+ * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL
+ * import processing is possible. On Windows systems it also sets
+ * compiler-specific macros to the values required to change the calling
+ * conventions of the various functions.
+ */
+#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
+ defined(__CYGWIN__)
+ /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or
+ * MinGW on any architecture currently supported by Windows. Also includes
+ * Watcom builds but these need special treatment because they are not
+ * compatible with GCC or Visual C because of different calling conventions.
+ */
+# if PNG_API_RULE == 2
+ /* If this line results in an error, either because __watcall is not
+ * understood or because of a redefine just below you cannot use *this*
+ * build of the library with the compiler you are using. *This* build was
+ * build using Watcom and applications must also be built using Watcom!
+ */
+# define PNGCAPI __watcall
+# endif
+
+# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800))
+# define PNGCAPI __cdecl
+# if PNG_API_RULE == 1
+ /* If this line results in an error __stdcall is not understood and
+ * PNG_API_RULE should not have been set to '1'.
+ */
+# define PNGAPI __stdcall
# endif
# else
-# include
-# endif
-# if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
- /* Amiga SAS/C: We must include builtin FPU functions when compiling using
- * MATH=68881
- */
-# include
-# endif
-#endif
-
-/* Codewarrior on NT has linking problems without this. */
-#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__)
-# define PNG_ALWAYS_EXTERN
-#endif
-
-/* This provides the non-ANSI (far) memory allocation routines. */
-#if defined(__TURBOC__) && defined(__MSDOS__)
-# include
-# include
-#endif
-
-/* I have no idea why is this necessary... */
-#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \
- defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__))
-# include
-#endif
-
-/* This controls how fine the dithering gets. As this allocates
- * a largish chunk of memory (32K), those who are not as concerned
- * with dithering quality can decrease some or all of these.
- */
-#ifndef PNG_DITHER_RED_BITS
-# define PNG_DITHER_RED_BITS 5
-#endif
-#ifndef PNG_DITHER_GREEN_BITS
-# define PNG_DITHER_GREEN_BITS 5
-#endif
-#ifndef PNG_DITHER_BLUE_BITS
-# define PNG_DITHER_BLUE_BITS 5
-#endif
-
-/* This controls how fine the gamma correction becomes when you
- * are only interested in 8 bits anyway. Increasing this value
- * results in more memory being used, and more pow() functions
- * being called to fill in the gamma tables. Don't set this value
- * less then 8, and even that may not work (I haven't tested it).
- */
-
-#ifndef PNG_MAX_GAMMA_8
-# define PNG_MAX_GAMMA_8 11
-#endif
-
-/* This controls how much a difference in gamma we can tolerate before
- * we actually start doing gamma conversion.
- */
-#ifndef PNG_GAMMA_THRESHOLD
-# define PNG_GAMMA_THRESHOLD 0.05
-#endif
-
-#endif /* PNG_INTERNAL */
-
-/* The following uses const char * instead of char * for error
- * and warning message functions, so some compilers won't complain.
- * If you do not want to use const, define PNG_NO_CONST here.
- */
-
-#ifndef PNG_NO_CONST
-# define PNG_CONST const
-#else
-# define PNG_CONST
-#endif
-
-/* The following defines give you the ability to remove code from the
- * library that you will not be using. I wish I could figure out how to
- * automate this, but I can't do that without making it seriously hard
- * on the users. So if you are not using an ability, change the #define
- * to and #undef, and that part of the library will not be compiled. If
- * your linker can't find a function, you may want to make sure the
- * ability is defined here. Some of these depend upon some others being
- * defined. I haven't figured out all the interactions here, so you may
- * have to experiment awhile to get everything to compile. If you are
- * creating or using a shared library, you probably shouldn't touch this,
- * as it will affect the size of the structures, and this will cause bad
- * things to happen if the library and/or application ever change.
- */
-
-/* Any features you will not be using can be undef'ed here */
-
-/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user
- * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS
- * on the compile line, then pick and choose which ones to define without
- * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED
- * if you only want to have a png-compliant reader/writer but don't need
- * any of the extra transformations. This saves about 80 kbytes in a
- * typical installation of the library. (PNG_NO_* form added in version
- * 1.0.1c, for consistency)
- */
-
-/* The size of the png_text structure changed in libpng-1.0.6 when
- * iTXt support was added. iTXt support was turned off by default through
- * libpng-1.2.x, to support old apps that malloc the png_text structure
- * instead of calling png_set_text() and letting libpng malloc it. It
- * was turned on by default in libpng-1.3.0.
- */
-
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-# ifndef PNG_NO_iTXt_SUPPORTED
-# define PNG_NO_iTXt_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_iTXt
-# define PNG_NO_READ_iTXt
-# endif
-# ifndef PNG_NO_WRITE_iTXt
-# define PNG_NO_WRITE_iTXt
-# endif
-#endif
-
-#if !defined(PNG_NO_iTXt_SUPPORTED)
-# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt)
-# define PNG_READ_iTXt
-# endif
-# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt)
-# define PNG_WRITE_iTXt
-# endif
-#endif
-
-/* The following support, added after version 1.0.0, can be turned off here en
- * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility
- * with old applications that require the length of png_struct and png_info
- * to remain unchanged.
- */
-
-#ifdef PNG_LEGACY_SUPPORTED
-# define PNG_NO_FREE_ME
-# define PNG_NO_READ_UNKNOWN_CHUNKS
-# define PNG_NO_WRITE_UNKNOWN_CHUNKS
-# define PNG_NO_READ_USER_CHUNKS
-# define PNG_NO_READ_iCCP
-# define PNG_NO_WRITE_iCCP
-# define PNG_NO_READ_iTXt
-# define PNG_NO_WRITE_iTXt
-# define PNG_NO_READ_sCAL
-# define PNG_NO_WRITE_sCAL
-# define PNG_NO_READ_sPLT
-# define PNG_NO_WRITE_sPLT
-# define PNG_NO_INFO_IMAGE
-# define PNG_NO_READ_RGB_TO_GRAY
-# define PNG_NO_READ_USER_TRANSFORM
-# define PNG_NO_WRITE_USER_TRANSFORM
-# define PNG_NO_USER_MEM
-# define PNG_NO_READ_EMPTY_PLTE
-# define PNG_NO_MNG_FEATURES
-# define PNG_NO_FIXED_POINT_SUPPORTED
-#endif
-
-/* Ignore attempt to turn off both floating and fixed point support */
-#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \
- !defined(PNG_NO_FIXED_POINT_SUPPORTED)
-# define PNG_FIXED_POINT_SUPPORTED
-#endif
-
-#ifndef PNG_NO_FREE_ME
-# define PNG_FREE_ME_SUPPORTED
-#endif
-
-#if defined(PNG_READ_SUPPORTED)
-
-#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \
- !defined(PNG_NO_READ_TRANSFORMS)
-# define PNG_READ_TRANSFORMS_SUPPORTED
-#endif
-
-#ifdef PNG_READ_TRANSFORMS_SUPPORTED
-# ifndef PNG_NO_READ_EXPAND
-# define PNG_READ_EXPAND_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_SHIFT
-# define PNG_READ_SHIFT_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_PACK
-# define PNG_READ_PACK_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_BGR
-# define PNG_READ_BGR_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_SWAP
-# define PNG_READ_SWAP_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_PACKSWAP
-# define PNG_READ_PACKSWAP_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_INVERT
-# define PNG_READ_INVERT_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_DITHER
-# define PNG_READ_DITHER_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_BACKGROUND
-# define PNG_READ_BACKGROUND_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_16_TO_8
-# define PNG_READ_16_TO_8_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_FILLER
-# define PNG_READ_FILLER_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_GAMMA
-# define PNG_READ_GAMMA_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_GRAY_TO_RGB
-# define PNG_READ_GRAY_TO_RGB_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_SWAP_ALPHA
-# define PNG_READ_SWAP_ALPHA_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_INVERT_ALPHA
-# define PNG_READ_INVERT_ALPHA_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_STRIP_ALPHA
-# define PNG_READ_STRIP_ALPHA_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_USER_TRANSFORM
-# define PNG_READ_USER_TRANSFORM_SUPPORTED
-# endif
-# ifndef PNG_NO_READ_RGB_TO_GRAY
-# define PNG_READ_RGB_TO_GRAY_SUPPORTED
-# endif
-#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
-
-#if !defined(PNG_NO_PROGRESSIVE_READ) && \
- !defined(PNG_PROGRESSIVE_READ_SUPPORTED) /* if you don't do progressive */
-# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */
-#endif /* about interlacing capability! You'll */
- /* still have interlacing unless you change the following line: */
-
-#define PNG_READ_INTERLACING_SUPPORTED /* required in PNG-compliant decoders */
-
-#ifndef PNG_NO_READ_COMPOSITE_NODIV
-# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */
-# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */
-# endif
-#endif
-
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Deprecated, will be removed from version 2.0.0.
- Use PNG_MNG_FEATURES_SUPPORTED instead. */
-#ifndef PNG_NO_READ_EMPTY_PLTE
-# define PNG_READ_EMPTY_PLTE_SUPPORTED
-#endif
-#endif
-
-#endif /* PNG_READ_SUPPORTED */
-
-#if defined(PNG_WRITE_SUPPORTED)
-
-# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \
- !defined(PNG_NO_WRITE_TRANSFORMS)
-# define PNG_WRITE_TRANSFORMS_SUPPORTED
-#endif
-
-#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
-# ifndef PNG_NO_WRITE_SHIFT
-# define PNG_WRITE_SHIFT_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_PACK
-# define PNG_WRITE_PACK_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_BGR
-# define PNG_WRITE_BGR_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_SWAP
-# define PNG_WRITE_SWAP_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_PACKSWAP
-# define PNG_WRITE_PACKSWAP_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_INVERT
-# define PNG_WRITE_INVERT_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_FILLER
-# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */
-# endif
-# ifndef PNG_NO_WRITE_SWAP_ALPHA
-# define PNG_WRITE_SWAP_ALPHA_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_INVERT_ALPHA
-# define PNG_WRITE_INVERT_ALPHA_SUPPORTED
-# endif
-# ifndef PNG_NO_WRITE_USER_TRANSFORM
-# define PNG_WRITE_USER_TRANSFORM_SUPPORTED
-# endif
-#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
-
-#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \
- !defined(PNG_WRITE_INTERLACING_SUPPORTED)
-#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant
- encoders, but can cause trouble
- if left undefined */
-#endif
-
-#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \
- !defined(PNG_WRITE_WEIGHTED_FILTER) && \
- defined(PNG_FLOATING_POINT_SUPPORTED)
-# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-#endif
-
-#ifndef PNG_NO_WRITE_FLUSH
-# define PNG_WRITE_FLUSH_SUPPORTED
-#endif
-
-#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
-/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */
-#ifndef PNG_NO_WRITE_EMPTY_PLTE
-# define PNG_WRITE_EMPTY_PLTE_SUPPORTED
-#endif
-#endif
-
-#endif /* PNG_WRITE_SUPPORTED */
-
-#ifndef PNG_1_0_X
-# ifndef PNG_NO_ERROR_NUMBERS
-# define PNG_ERROR_NUMBERS_SUPPORTED
-# endif
-#endif /* PNG_1_0_X */
-
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
-# ifndef PNG_NO_USER_TRANSFORM_PTR
-# define PNG_USER_TRANSFORM_PTR_SUPPORTED
-# endif
-#endif
-
-#ifndef PNG_NO_STDIO
-# define PNG_TIME_RFC1123_SUPPORTED
-#endif
-
-/* This adds extra functions in pngget.c for accessing data from the
- * info pointer (added in version 0.99)
- * png_get_image_width()
- * png_get_image_height()
- * png_get_bit_depth()
- * png_get_color_type()
- * png_get_compression_type()
- * png_get_filter_type()
- * png_get_interlace_type()
- * png_get_pixel_aspect_ratio()
- * png_get_pixels_per_meter()
- * png_get_x_offset_pixels()
- * png_get_y_offset_pixels()
- * png_get_x_offset_microns()
- * png_get_y_offset_microns()
- */
-#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED)
-# define PNG_EASY_ACCESS_SUPPORTED
-#endif
-
-/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0
- * and removed from version 1.2.20. The following will be removed
- * from libpng-1.4.0
-*/
-
-#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_OPTIMIZED_CODE)
-# ifndef PNG_OPTIMIZED_CODE_SUPPORTED
-# define PNG_OPTIMIZED_CODE_SUPPORTED
-# endif
-#endif
-
-#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE)
-# ifndef PNG_ASSEMBLER_CODE_SUPPORTED
-# define PNG_ASSEMBLER_CODE_SUPPORTED
-# endif
-
-# if defined(__GNUC__) && defined(__x86_64__) && (__GNUC__ < 4)
- /* work around 64-bit gcc compiler bugs in gcc-3.x */
-# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
-# define PNG_NO_MMX_CODE
+ /* An older compiler, or one not detected (erroneously) above,
+ * if necessary override on the command line to get the correct
+ * variants for the compiler.
+ */
+# ifndef PNGCAPI
+# define PNGCAPI _cdecl
# endif
-# endif
-
-# if defined(__APPLE__)
-# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
-# define PNG_NO_MMX_CODE
+# if PNG_API_RULE == 1 && !defined(PNGAPI)
+# define PNGAPI _stdcall
# endif
+# endif /* compiler/api */
+
+ /* NOTE: PNGCBAPI always defaults to PNGCAPI. */
+
+# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
+# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
# endif
-# if (defined(__MWERKS__) && ((__MWERKS__ < 0x0900) || macintosh))
-# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
-# define PNG_NO_MMX_CODE
+# 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
-# 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 */
-# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
-# define PNG_MMX_CODE_SUPPORTED
-# endif
+#else /* !Windows */
+# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
+# define PNGAPI _System
+# else /* !Windows/x86 && !OS/2 */
+ /* Use the defaults, or define PNG*API on the command line (but
+ * this will have to be done for every compile!)
+ */
+# endif /* other system, !OS/2 */
+#endif /* !Windows/x86 */
+/* Now do all the defaulting . */
+#ifndef PNGCAPI
+# define PNGCAPI
#endif
-/* end of obsolete code to be removed from libpng-1.4.0 */
-
-#if !defined(PNG_1_0_X)
-#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED)
-# define PNG_USER_MEM_SUPPORTED
+#ifndef PNGCBAPI
+# define PNGCBAPI PNGCAPI
#endif
-#endif /* PNG_1_0_X */
-
-/* Added at libpng-1.2.6 */
-#if !defined(PNG_1_0_X)
-#ifndef PNG_SET_USER_LIMITS_SUPPORTED
-#if !defined(PNG_NO_SET_USER_LIMITS) && !defined(PNG_SET_USER_LIMITS_SUPPORTED)
-# define PNG_SET_USER_LIMITS_SUPPORTED
+#ifndef PNGAPI
+# define PNGAPI PNGCAPI
#endif
-#endif
-#endif /* PNG_1_0_X */
-/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter
- * how large, set these limits to 0x7fffffffL
+/* PNG_IMPEXP may be set on the compilation system command line or (if not set)
+ * then in an internal header file when building the library, otherwise (when
+ * using the library) it is set here.
*/
-#ifndef PNG_USER_WIDTH_MAX
-# define PNG_USER_WIDTH_MAX 1000000L
-#endif
-#ifndef PNG_USER_HEIGHT_MAX
-# define PNG_USER_HEIGHT_MAX 1000000L
-#endif
+#ifndef PNG_IMPEXP
+# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)
+ /* This forces use of a DLL, disallowing static linking */
+# define PNG_IMPEXP PNG_DLL_IMPORT
+# endif
-/* These are currently experimental features, define them if you want */
-
-/* very little testing */
-/*
-#ifdef PNG_READ_SUPPORTED
-# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
-# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+# ifndef PNG_IMPEXP
+# define PNG_IMPEXP
# endif
#endif
-*/
-/* This is only for PowerPC big-endian and 680x0 systems */
-/* some testing */
-/*
-#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
-# define PNG_READ_BIG_ENDIAN_SUPPORTED
+/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat
+ * 'attributes' as a storage class - the attributes go at the start of the
+ * function definition, and attributes are always appended regardless of the
+ * compiler. This considerably simplifies these macros but may cause problems
+ * if any compilers both need function attributes and fail to handle them as
+ * a storage class (this is unlikely.)
+ */
+#ifndef PNG_FUNCTION
+# define PNG_FUNCTION(type, name, args, attributes) attributes type name args
#endif
-*/
-/* Buggy compilers (e.g., gcc 2.7.2.2) need this */
-/*
-#define PNG_NO_POINTER_INDEXING
-*/
+#ifndef PNG_EXPORT_TYPE
+# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type
+#endif
-/* These functions are turned off by default, as they will be phased out. */
-/*
-#define PNG_USELESS_TESTS_SUPPORTED
-#define PNG_CORRECT_PALETTE_SUPPORTED
-*/
+ /* The ordinal value is only relevant when preprocessing png.h for symbol
+ * table entries, so we discard it here. See the .dfn files in the
+ * scripts directory.
+ */
-/* Any chunks you are not interested in, you can undef here. The
- * ones that allocate memory may be expecially important (hIST,
- * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info
- * a bit smaller.
+#ifndef PNG_EXPORTA
+# define PNG_EXPORTA(ordinal, type, name, args, attributes) \
+ PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \
+ PNG_LINKAGE_API attributes)
+#endif
+
+/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument,
+ * so make something non-empty to satisfy the requirement:
+ */
+#define PNG_EMPTY /*empty list*/
+
+#define PNG_EXPORT(ordinal, type, name, args) \
+ PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY)
+
+/* Use PNG_REMOVED to comment out a removed interface. */
+#ifndef PNG_REMOVED
+# define PNG_REMOVED(ordinal, type, name, args, attributes)
+#endif
+
+#ifndef PNG_CALLBACK
+# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args)
+#endif
+
+/* Support for compiler specific function attributes. These are used
+ * so that where compiler support is available incorrect use of API
+ * functions in png.h will generate compiler warnings.
+ *
+ * Added at libpng-1.2.41.
*/
-#if defined(PNG_READ_SUPPORTED) && \
- !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
- !defined(PNG_NO_READ_ANCILLARY_CHUNKS)
-# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
-#endif
-
-#if defined(PNG_WRITE_SUPPORTED) && \
- !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
- !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS)
-# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
-#endif
-
-#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
-
-#ifdef PNG_NO_READ_TEXT
-# define PNG_NO_READ_iTXt
-# define PNG_NO_READ_tEXt
-# define PNG_NO_READ_zTXt
-#endif
-#ifndef PNG_NO_READ_bKGD
-# define PNG_READ_bKGD_SUPPORTED
-# define PNG_bKGD_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_cHRM
-# define PNG_READ_cHRM_SUPPORTED
-# define PNG_cHRM_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_gAMA
-# define PNG_READ_gAMA_SUPPORTED
-# define PNG_gAMA_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_hIST
-# define PNG_READ_hIST_SUPPORTED
-# define PNG_hIST_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_iCCP
-# define PNG_READ_iCCP_SUPPORTED
-# define PNG_iCCP_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_iTXt
-# ifndef PNG_READ_iTXt_SUPPORTED
-# define PNG_READ_iTXt_SUPPORTED
-# endif
-# ifndef PNG_iTXt_SUPPORTED
-# define PNG_iTXt_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_READ_oFFs
-# define PNG_READ_oFFs_SUPPORTED
-# define PNG_oFFs_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_pCAL
-# define PNG_READ_pCAL_SUPPORTED
-# define PNG_pCAL_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_sCAL
-# define PNG_READ_sCAL_SUPPORTED
-# define PNG_sCAL_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_pHYs
-# define PNG_READ_pHYs_SUPPORTED
-# define PNG_pHYs_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_sBIT
-# define PNG_READ_sBIT_SUPPORTED
-# define PNG_sBIT_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_sPLT
-# define PNG_READ_sPLT_SUPPORTED
-# define PNG_sPLT_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_sRGB
-# define PNG_READ_sRGB_SUPPORTED
-# define PNG_sRGB_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_tEXt
-# define PNG_READ_tEXt_SUPPORTED
-# define PNG_tEXt_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_tIME
-# define PNG_READ_tIME_SUPPORTED
-# define PNG_tIME_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_tRNS
-# define PNG_READ_tRNS_SUPPORTED
-# define PNG_tRNS_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_zTXt
-# define PNG_READ_zTXt_SUPPORTED
-# define PNG_zTXt_SUPPORTED
-#endif
-#ifndef PNG_NO_READ_UNKNOWN_CHUNKS
-# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
-# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
-# define PNG_UNKNOWN_CHUNKS_SUPPORTED
-# endif
-# ifndef PNG_NO_HANDLE_AS_UNKNOWN
-# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-# endif
-#endif
-#if !defined(PNG_NO_READ_USER_CHUNKS) && \
- defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
-# define PNG_READ_USER_CHUNKS_SUPPORTED
-# define PNG_USER_CHUNKS_SUPPORTED
-# ifdef PNG_NO_READ_UNKNOWN_CHUNKS
-# undef PNG_NO_READ_UNKNOWN_CHUNKS
-# endif
-# ifdef PNG_NO_HANDLE_AS_UNKNOWN
-# undef PNG_NO_HANDLE_AS_UNKNOWN
-# endif
-#endif
-#ifndef PNG_NO_READ_OPT_PLTE
-# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */
-#endif /* optional PLTE chunk in RGB and RGBA images */
-#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \
- defined(PNG_READ_zTXt_SUPPORTED)
-# define PNG_READ_TEXT_SUPPORTED
-# define PNG_TEXT_SUPPORTED
-#endif
-
-#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */
-
-#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
-
-#ifdef PNG_NO_WRITE_TEXT
-# define PNG_NO_WRITE_iTXt
-# define PNG_NO_WRITE_tEXt
-# define PNG_NO_WRITE_zTXt
-#endif
-#ifndef PNG_NO_WRITE_bKGD
-# define PNG_WRITE_bKGD_SUPPORTED
-# ifndef PNG_bKGD_SUPPORTED
-# define PNG_bKGD_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_cHRM
-# define PNG_WRITE_cHRM_SUPPORTED
-# ifndef PNG_cHRM_SUPPORTED
-# define PNG_cHRM_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_gAMA
-# define PNG_WRITE_gAMA_SUPPORTED
-# ifndef PNG_gAMA_SUPPORTED
-# define PNG_gAMA_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_hIST
-# define PNG_WRITE_hIST_SUPPORTED
-# ifndef PNG_hIST_SUPPORTED
-# define PNG_hIST_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_iCCP
-# define PNG_WRITE_iCCP_SUPPORTED
-# ifndef PNG_iCCP_SUPPORTED
-# define PNG_iCCP_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_iTXt
-# ifndef PNG_WRITE_iTXt_SUPPORTED
-# define PNG_WRITE_iTXt_SUPPORTED
-# endif
-# ifndef PNG_iTXt_SUPPORTED
-# define PNG_iTXt_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_oFFs
-# define PNG_WRITE_oFFs_SUPPORTED
-# ifndef PNG_oFFs_SUPPORTED
-# define PNG_oFFs_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_pCAL
-# define PNG_WRITE_pCAL_SUPPORTED
-# ifndef PNG_pCAL_SUPPORTED
-# define PNG_pCAL_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_sCAL
-# define PNG_WRITE_sCAL_SUPPORTED
-# ifndef PNG_sCAL_SUPPORTED
-# define PNG_sCAL_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_pHYs
-# define PNG_WRITE_pHYs_SUPPORTED
-# ifndef PNG_pHYs_SUPPORTED
-# define PNG_pHYs_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_sBIT
-# define PNG_WRITE_sBIT_SUPPORTED
-# ifndef PNG_sBIT_SUPPORTED
-# define PNG_sBIT_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_sPLT
-# define PNG_WRITE_sPLT_SUPPORTED
-# ifndef PNG_sPLT_SUPPORTED
-# define PNG_sPLT_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_sRGB
-# define PNG_WRITE_sRGB_SUPPORTED
-# ifndef PNG_sRGB_SUPPORTED
-# define PNG_sRGB_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_tEXt
-# define PNG_WRITE_tEXt_SUPPORTED
-# ifndef PNG_tEXt_SUPPORTED
-# define PNG_tEXt_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_tIME
-# define PNG_WRITE_tIME_SUPPORTED
-# ifndef PNG_tIME_SUPPORTED
-# define PNG_tIME_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_tRNS
-# define PNG_WRITE_tRNS_SUPPORTED
-# ifndef PNG_tRNS_SUPPORTED
-# define PNG_tRNS_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_zTXt
-# define PNG_WRITE_zTXt_SUPPORTED
-# ifndef PNG_zTXt_SUPPORTED
-# define PNG_zTXt_SUPPORTED
-# endif
-#endif
-#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
-# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
-# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
-# define PNG_UNKNOWN_CHUNKS_SUPPORTED
-# endif
-# ifndef PNG_NO_HANDLE_AS_UNKNOWN
-# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-# endif
-# endif
-#endif
-#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
- defined(PNG_WRITE_zTXt_SUPPORTED)
-# define PNG_WRITE_TEXT_SUPPORTED
-# ifndef PNG_TEXT_SUPPORTED
-# define PNG_TEXT_SUPPORTED
+#ifndef PNG_NO_PEDANTIC_WARNINGS
+# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED
+# define PNG_PEDANTIC_WARNINGS_SUPPORTED
# endif
#endif
-#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */
-
-/* Turn this off to disable png_read_png() and
- * png_write_png() and leave the row_pointers member
- * out of the info structure.
- */
-#ifndef PNG_NO_INFO_IMAGE
-# define PNG_INFO_IMAGE_SUPPORTED
-#endif
-
-/* need the time information for reading tIME chunks */
-#if defined(PNG_tIME_SUPPORTED)
-# if !defined(_WIN32_WCE)
- /* "time.h" functions are not supported on WindowsCE */
-# include
-# endif
-#endif
-
-/* Some typedefs to get us started. These should be safe on most of the
- * common platforms. The typedefs should be at least as large as the
- * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
- * don't have to be exactly that size. Some compilers dislike passing
- * unsigned shorts as function parameters, so you may be better off using
- * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may
- * want to have unsigned int for png_uint_32 instead of unsigned long.
- */
-
-typedef unsigned long png_uint_32;
-typedef long png_int_32;
-typedef unsigned short png_uint_16;
-typedef short png_int_16;
-typedef unsigned char png_byte;
-
-/* This is usually size_t. It is typedef'ed just in case you need it to
- change (I'm not sure if you will or not, so I thought I'd be safe) */
-#ifdef PNG_SIZE_T
- typedef PNG_SIZE_T png_size_t;
-# define png_sizeof(x) png_convert_size(sizeof (x))
-#else
- typedef size_t png_size_t;
-# define png_sizeof(x) sizeof (x)
-#endif
-
-/* The following is needed for medium model support. It cannot be in the
- * PNG_INTERNAL section. Needs modification for other compilers besides
- * MSC. Model independent support declares all arrays and pointers to be
- * large using the far keyword. The zlib version used must also support
- * model independent data. As of version zlib 1.0.4, the necessary changes
- * have been made in zlib. The USE_FAR_KEYWORD define triggers other
- * changes that are needed. (Tim Wegner)
- */
-
-/* Separate compiler dependencies (problem here is that zlib.h always
- defines FAR. (SJT) */
-#ifdef __BORLANDC__
-# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
-# define LDATA 1
-# else
-# define LDATA 0
-# endif
- /* GRR: why is Cygwin in here? Cygwin is not Borland C... */
-# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__)
-# define PNG_MAX_MALLOC_64K
-# if (LDATA != 1)
-# ifndef FAR
-# define FAR __far
+#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED
+ /* Support for compiler specific function attributes. These are used
+ * so that where compiler support is available, incorrect use of API
+ * functions in png.h will generate compiler warnings. Added at libpng
+ * version 1.2.41. Disabling these removes the warnings but may also produce
+ * less efficient code.
+ */
+# if defined(__clang__) && defined(__has_attribute)
+ /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */
+# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__)
+# define PNG_USE_RESULT __attribute__((__warn_unused_result__))
+# endif
+# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__)
+# define PNG_NORETURN __attribute__((__noreturn__))
+# endif
+# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__)
+# define PNG_ALLOCATED __attribute__((__malloc__))
+# endif
+# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__)
+# define PNG_DEPRECATED __attribute__((__deprecated__))
+# endif
+# if !defined(PNG_PRIVATE)
+# ifdef __has_extension
+# if __has_extension(attribute_unavailable_with_message)
+# define PNG_PRIVATE __attribute__((__unavailable__(\
+ "This function is not exported by libpng.")))
+# endif
# endif
-# define USE_FAR_KEYWORD
-# endif /* LDATA != 1 */
- /* Possibly useful for moving data out of default segment.
- * Uncomment it if you want. Could also define FARDATA as
- * const if your compiler supports it. (SJT)
-# define FARDATA FAR
- */
-# endif /* __WIN32__, __FLAT__, __CYGWIN__ */
-#endif /* __BORLANDC__ */
+# endif
+# ifndef PNG_RESTRICT
+# define PNG_RESTRICT __restrict
+# endif
+# elif defined(__GNUC__)
+# ifndef PNG_USE_RESULT
+# define PNG_USE_RESULT __attribute__((__warn_unused_result__))
+# endif
+# ifndef PNG_NORETURN
+# define PNG_NORETURN __attribute__((__noreturn__))
+# endif
+# if __GNUC__ >= 3
+# ifndef PNG_ALLOCATED
+# define PNG_ALLOCATED __attribute__((__malloc__))
+# endif
+# ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED __attribute__((__deprecated__))
+# endif
+# ifndef PNG_PRIVATE
+# if 0 /* Doesn't work so we use deprecated instead*/
+# define PNG_PRIVATE \
+ __attribute__((warning("This function is not exported by libpng.")))
+# else
+# define PNG_PRIVATE \
+ __attribute__((__deprecated__))
+# endif
+# endif
+# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1))
+# ifndef PNG_RESTRICT
+# define PNG_RESTRICT __restrict
+# endif
+# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */
+# endif /* __GNUC__ >= 3 */
-/* Suggest testing for specific compiler first before testing for
- * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM,
- * making reliance oncertain keywords suspect. (SJT)
- */
+# elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+# ifndef PNG_USE_RESULT
+# define PNG_USE_RESULT /* not supported */
+# endif
+# ifndef PNG_NORETURN
+# define PNG_NORETURN __declspec(noreturn)
+# endif
+# ifndef PNG_ALLOCATED
+# if (_MSC_VER >= 1400)
+# define PNG_ALLOCATED __declspec(restrict)
+# endif
+# endif
+# ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED __declspec(deprecated)
+# endif
+# ifndef PNG_PRIVATE
+# define PNG_PRIVATE __declspec(deprecated)
+# endif
+# ifndef PNG_RESTRICT
+# if (_MSC_VER >= 1400)
+# define PNG_RESTRICT __restrict
+# endif
+# endif
-/* MSC Medium model */
-#if defined(FAR)
-# if defined(M_I86MM)
-# define USE_FAR_KEYWORD
-# define FARDATA FAR
-# include
+# elif defined(__WATCOMC__)
+# ifndef PNG_RESTRICT
+# define PNG_RESTRICT __restrict
+# endif
+# endif
+#endif /* PNG_PEDANTIC_WARNINGS */
+
+#ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED /* Use of this function is deprecated */
+#endif
+#ifndef PNG_USE_RESULT
+# define PNG_USE_RESULT /* The result of this function must be checked */
+#endif
+#ifndef PNG_NORETURN
+# define PNG_NORETURN /* This function does not return */
+#endif
+#ifndef PNG_ALLOCATED
+# define PNG_ALLOCATED /* The result of the function is new memory */
+#endif
+#ifndef PNG_PRIVATE
+# define PNG_PRIVATE /* This is a private libpng function */
+#endif
+#ifndef PNG_RESTRICT
+# define PNG_RESTRICT /* The C99 "restrict" feature */
+#endif
+
+#ifndef PNG_FP_EXPORT /* A floating point API. */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+# define PNG_FP_EXPORT(ordinal, type, name, args)\
+ PNG_EXPORT(ordinal, type, name, args);
+# else /* No floating point APIs */
+# define PNG_FP_EXPORT(ordinal, type, name, args)
+# endif
+#endif
+#ifndef PNG_FIXED_EXPORT /* A fixed point API. */
+# ifdef PNG_FIXED_POINT_SUPPORTED
+# define PNG_FIXED_EXPORT(ordinal, type, name, args)\
+ PNG_EXPORT(ordinal, type, name, args);
+# else /* No fixed point APIs */
+# define PNG_FIXED_EXPORT(ordinal, type, name, args)
# endif
#endif
-/* SJT: default case */
-#ifndef FAR
-# define FAR
+#ifndef PNG_BUILDING_SYMBOL_TABLE
+/* Some typedefs to get us started. These should be safe on most of the common
+ * platforms.
+ *
+ * png_uint_32 and png_int_32 may, currently, be larger than required to hold a
+ * 32-bit value however this is not normally advisable.
+ *
+ * png_uint_16 and png_int_16 should always be two bytes in size - this is
+ * verified at library build time.
+ *
+ * png_byte must always be one byte in size.
+ *
+ * The checks below use constants from limits.h, as defined by the ISOC90
+ * standard.
+ */
+#if CHAR_BIT == 8 && UCHAR_MAX == 255
+ typedef unsigned char png_byte;
+#else
+# error "libpng requires 8-bit bytes"
#endif
-/* At this point FAR is always defined */
-#ifndef FARDATA
-# define FARDATA
+#if INT_MIN == -32768 && INT_MAX == 32767
+ typedef int png_int_16;
+#elif SHRT_MIN == -32768 && SHRT_MAX == 32767
+ typedef short png_int_16;
+#else
+# error "libpng requires a signed 16-bit type"
#endif
-/* Typedef for floating-point numbers that are converted
- to fixed-point with a multiple of 100,000, e.g., int_gamma */
+#if UINT_MAX == 65535
+ typedef unsigned int png_uint_16;
+#elif USHRT_MAX == 65535
+ typedef unsigned short png_uint_16;
+#else
+# error "libpng requires an unsigned 16-bit type"
+#endif
+
+#if INT_MIN < -2147483646 && INT_MAX > 2147483646
+ typedef int png_int_32;
+#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
+ typedef long int png_int_32;
+#else
+# error "libpng requires a signed 32-bit (or more) type"
+#endif
+
+#if UINT_MAX > 4294967294U
+ typedef unsigned int png_uint_32;
+#elif ULONG_MAX > 4294967294U
+ typedef unsigned long int png_uint_32;
+#else
+# error "libpng requires an unsigned 32-bit (or more) type"
+#endif
+
+/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
+ * From 1.6.0 onwards, an ISO C90 compiler, as well as a standard-compliant
+ * behavior of sizeof and ptrdiff_t are required.
+ * The legacy typedefs are provided here for backwards compatibility.
+ */
+typedef size_t png_size_t;
+typedef ptrdiff_t png_ptrdiff_t;
+
+/* libpng needs to know the maximum value of 'size_t' and this controls the
+ * definition of png_alloc_size_t, below. This maximum value of size_t limits
+ * but does not control the maximum allocations the library makes - there is
+ * direct application control of this through png_set_user_limits().
+ */
+#ifndef PNG_SMALL_SIZE_T
+ /* Compiler specific tests for systems where size_t is known to be less than
+ * 32 bits (some of these systems may no longer work because of the lack of
+ * 'far' support; see above.)
+ */
+# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\
+ (defined(_MSC_VER) && defined(MAXSEG_64K))
+# define PNG_SMALL_SIZE_T
+# endif
+#endif
+
+/* png_alloc_size_t is guaranteed to be no smaller than size_t, and no smaller
+ * than png_uint_32. Casts from size_t or png_uint_32 to png_alloc_size_t are
+ * not necessary; in fact, it is recommended not to use them at all, so that
+ * the compiler can complain when something turns out to be problematic.
+ *
+ * Casts in the other direction (from png_alloc_size_t to size_t or
+ * png_uint_32) should be explicitly applied; however, we do not expect to
+ * encounter practical situations that require such conversions.
+ *
+ * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than
+ * 4294967295 - i.e. less than the maximum value of png_uint_32.
+ */
+#ifdef PNG_SMALL_SIZE_T
+ typedef png_uint_32 png_alloc_size_t;
+#else
+ typedef size_t png_alloc_size_t;
+#endif
+
+/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler
+ * implementations of Intel CPU specific support of user-mode segmented address
+ * spaces, where 16-bit pointers address more than 65536 bytes of memory using
+ * separate 'segment' registers. The implementation requires two different
+ * types of pointer (only one of which includes the segment value.)
+ *
+ * If required this support is available in version 1.2 of libpng and may be
+ * available in versions through 1.5, although the correctness of the code has
+ * not been verified recently.
+ */
+
+/* Typedef for floating-point numbers that are converted to fixed-point with a
+ * multiple of 100,000, e.g., gamma
+ */
typedef png_int_32 png_fixed_point;
/* Add typedefs for pointers */
-typedef void FAR * png_voidp;
-typedef png_byte FAR * png_bytep;
-typedef png_uint_32 FAR * png_uint_32p;
-typedef png_int_32 FAR * png_int_32p;
-typedef png_uint_16 FAR * png_uint_16p;
-typedef png_int_16 FAR * png_int_16p;
-typedef PNG_CONST char FAR * png_const_charp;
-typedef char FAR * png_charp;
-typedef png_fixed_point FAR * png_fixed_point_p;
+typedef void * png_voidp;
+typedef const void * png_const_voidp;
+typedef png_byte * png_bytep;
+typedef const png_byte * png_const_bytep;
+typedef png_uint_32 * png_uint_32p;
+typedef const png_uint_32 * png_const_uint_32p;
+typedef png_int_32 * png_int_32p;
+typedef const png_int_32 * png_const_int_32p;
+typedef png_uint_16 * png_uint_16p;
+typedef const png_uint_16 * png_const_uint_16p;
+typedef png_int_16 * png_int_16p;
+typedef const png_int_16 * png_const_int_16p;
+typedef char * png_charp;
+typedef const char * png_const_charp;
+typedef png_fixed_point * png_fixed_point_p;
+typedef const png_fixed_point * png_const_fixed_point_p;
+typedef size_t * png_size_tp;
+typedef const size_t * png_const_size_tp;
-#ifndef PNG_NO_STDIO
-#if defined(_WIN32_WCE)
-typedef HANDLE png_FILE_p;
-#else
-typedef FILE * png_FILE_p;
-#endif
+#ifdef PNG_STDIO_SUPPORTED
+typedef FILE * png_FILE_p;
#endif
#ifdef PNG_FLOATING_POINT_SUPPORTED
-typedef double FAR * png_doublep;
+typedef double * png_doublep;
+typedef const double * png_const_doublep;
#endif
/* Pointers to pointers; i.e. arrays */
-typedef png_byte FAR * FAR * png_bytepp;
-typedef png_uint_32 FAR * FAR * png_uint_32pp;
-typedef png_int_32 FAR * FAR * png_int_32pp;
-typedef png_uint_16 FAR * FAR * png_uint_16pp;
-typedef png_int_16 FAR * FAR * png_int_16pp;
-typedef PNG_CONST char FAR * FAR * png_const_charpp;
-typedef char FAR * FAR * png_charpp;
-typedef png_fixed_point FAR * FAR * png_fixed_point_pp;
+typedef png_byte * * png_bytepp;
+typedef png_uint_32 * * png_uint_32pp;
+typedef png_int_32 * * png_int_32pp;
+typedef png_uint_16 * * png_uint_16pp;
+typedef png_int_16 * * png_int_16pp;
+typedef const char * * png_const_charpp;
+typedef char * * png_charpp;
+typedef png_fixed_point * * png_fixed_point_pp;
#ifdef PNG_FLOATING_POINT_SUPPORTED
-typedef double FAR * FAR * png_doublepp;
+typedef double * * png_doublepp;
#endif
/* Pointers to pointers to pointers; i.e., pointer to array */
-typedef char FAR * FAR * FAR * png_charppp;
+typedef char * * * png_charppp;
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-/* SPC - Is this stuff deprecated? */
-/* It'll be removed as of libpng-1.3.0 - GR-P */
-/* libpng typedefs for types in zlib. If zlib changes
- * or another compression library is used, then change these.
- * Eliminates need to change all the source files.
- */
-typedef charf * png_zcharp;
-typedef charf * FAR * png_zcharpp;
-typedef z_stream FAR * png_zstreamp;
-#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */
-
-/*
- * Define PNG_BUILD_DLL if the module being built is a Windows
- * LIBPNG DLL.
- *
- * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL.
- * It is equivalent to Microsoft predefined macro _DLL that is
- * automatically defined when you compile using the share
- * version of the CRT (C Run-Time library)
- *
- * The cygwin mods make this behavior a little different:
- * Define PNG_BUILD_DLL if you are building a dll for use with cygwin
- * Define PNG_STATIC if you are building a static library for use with cygwin,
- * -or- if you are building an application that you want to link to the
- * static library.
- * PNG_USE_DLL is defined by default (no user action needed) unless one of
- * the other flags is defined.
- */
-
-#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL))
-# define PNG_DLL
-#endif
-/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib.
- * When building a static lib, default to no GLOBAL ARRAYS, but allow
- * command-line override
- */
-#if defined(__CYGWIN__)
-# if !defined(PNG_STATIC)
-# if defined(PNG_USE_GLOBAL_ARRAYS)
-# undef PNG_USE_GLOBAL_ARRAYS
-# endif
-# if !defined(PNG_USE_LOCAL_ARRAYS)
-# define PNG_USE_LOCAL_ARRAYS
-# endif
-# else
-# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS)
-# if defined(PNG_USE_GLOBAL_ARRAYS)
-# undef PNG_USE_GLOBAL_ARRAYS
-# endif
-# endif
-# endif
-# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
-# define PNG_USE_LOCAL_ARRAYS
-# endif
-#endif
-
-/* Do not use global arrays (helps with building DLL's)
- * They are no longer used in libpng itself, since version 1.0.5c,
- * but might be required for some pre-1.0.5c applications.
- */
-#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
-# if defined(PNG_NO_GLOBAL_ARRAYS) || \
- (defined(__GNUC__) && defined(PNG_DLL)) || defined(_MSC_VER)
-# define PNG_USE_LOCAL_ARRAYS
-# else
-# define PNG_USE_GLOBAL_ARRAYS
-# endif
-#endif
-
-#if defined(__CYGWIN__)
-# undef PNGAPI
-# define PNGAPI __cdecl
-# undef PNG_IMPEXP
-# define PNG_IMPEXP
-#endif
-
-/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall",
- * you may get warnings regarding the linkage of png_zalloc and png_zfree.
- * Don't ignore those warnings; you must also reset the default calling
- * convention in your compiler to match your PNGAPI, and you must build
- * zlib and your applications the same way you build libpng.
- */
-
-#if defined(__MINGW32__) && !defined(PNG_MODULEDEF)
-# ifndef PNG_NO_MODULEDEF
-# define PNG_NO_MODULEDEF
-# endif
-#endif
-
-#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF)
-# define PNG_IMPEXP
-#endif
-
-#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \
- (( defined(_Windows) || defined(_WINDOWS) || \
- defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ))
-
-# ifndef PNGAPI
-# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
-# define PNGAPI __cdecl
-# else
-# define PNGAPI _cdecl
-# endif
-# endif
-
-# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \
- 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */)
-# define PNG_IMPEXP
-# endif
-
-# if !defined(PNG_IMPEXP)
-
-# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol
-# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol
-
- /* Borland/Microsoft */
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500)
-# define PNG_EXPORT PNG_EXPORT_TYPE1
-# else
-# define PNG_EXPORT PNG_EXPORT_TYPE2
-# if defined(PNG_BUILD_DLL)
-# define PNG_IMPEXP __export
-# else
-# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in
- VC++ */
-# endif /* Exists in Borland C++ for
- C++ classes (== huge) */
-# endif
-# endif
-
-# if !defined(PNG_IMPEXP)
-# if defined(PNG_BUILD_DLL)
-# define PNG_IMPEXP __declspec(dllexport)
-# else
-# define PNG_IMPEXP __declspec(dllimport)
-# endif
-# endif
-# endif /* PNG_IMPEXP */
-#else /* !(DLL || non-cygwin WINDOWS) */
-# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
-# ifndef PNGAPI
-# define PNGAPI _System
-# endif
-# else
-# if 0 /* ... other platforms, with other meanings */
-# endif
-# endif
-#endif
-
-#ifndef PNGAPI
-# define PNGAPI
-#endif
-#ifndef PNG_IMPEXP
-# define PNG_IMPEXP
-#endif
-
-#ifdef PNG_BUILDSYMS
-# ifndef PNG_EXPORT
-# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END
-# endif
-# ifdef PNG_USE_GLOBAL_ARRAYS
-# ifndef PNG_EXPORT_VAR
-# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT
-# endif
-# endif
-#endif
-
-#ifndef PNG_EXPORT
-# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol
-#endif
-
-#ifdef PNG_USE_GLOBAL_ARRAYS
-# ifndef PNG_EXPORT_VAR
-# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type
-# endif
-#endif
-
-/* User may want to use these so they are not in PNG_INTERNAL. Any library
- * functions that are passed far data must be model independent.
- */
-
-#ifndef PNG_ABORT
-# define PNG_ABORT() abort()
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
-# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
-#else
-# define png_jmpbuf(png_ptr) \
- (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED)
-#endif
-
-#if defined(USE_FAR_KEYWORD) /* memory model independent fns */
-/* use this to make far-to-near assignments */
-# define CHECK 1
-# define NOCHECK 0
-# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK))
-# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK))
-# define png_snprintf _fsnprintf /* Added to v 1.2.19 */
-# define png_strlen _fstrlen
-# define png_memcmp _fmemcmp /* SJT: added */
-# define png_memcpy _fmemcpy
-# define png_memset _fmemset
-#else /* use the usual functions */
-# define CVT_PTR(ptr) (ptr)
-# define CVT_PTR_NOCHECK(ptr) (ptr)
-# ifndef PNG_NO_SNPRINTF
-# ifdef _MSC_VER
-# define png_snprintf _snprintf /* Added to v 1.2.19 */
-# define png_snprintf2 _snprintf
-# define png_snprintf6 _snprintf
-# else
-# define png_snprintf snprintf /* Added to v 1.2.19 */
-# define png_snprintf2 snprintf
-# define png_snprintf6 snprintf
-# endif
-# else
- /* You don't have or don't want to use snprintf(). Caution: Using
- * sprintf instead of snprintf exposes your application to accidental
- * or malevolent buffer overflows. If you don't have snprintf()
- * as a general rule you should provide one (you can get one from
- * Portable OpenSSH). */
-# define png_snprintf(s1,n,fmt,x1) sprintf(s1,fmt,x1)
-# define png_snprintf2(s1,n,fmt,x1,x2) sprintf(s1,fmt,x1,x2)
-# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \
- sprintf(s1,fmt,x1,x2,x3,x4,x5,x6)
-# endif
-# define png_strlen strlen
-# define png_memcmp memcmp /* SJT: added */
-# define png_memcpy memcpy
-# define png_memset memset
-#endif
-/* End of memory model independent support */
-
-/* Just a little check that someone hasn't tried to define something
- * contradictory.
- */
-#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K)
-# undef PNG_ZBUF_SIZE
-# define PNG_ZBUF_SIZE 65536L
-#endif
-
-/* Added at libpng-1.2.8 */
-#endif /* PNG_VERSION_INFO_ONLY */
+#endif /* PNG_BUILDING_SYMBOL_TABLE */
#endif /* PNGCONF_H */
diff --git a/PDF/include/Poco/PDF/pngdebug.h b/PDF/include/Poco/PDF/pngdebug.h
new file mode 100644
index 000000000..00d5a4569
--- /dev/null
+++ b/PDF/include/Poco/PDF/pngdebug.h
@@ -0,0 +1,153 @@
+
+/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+
+/* 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
+ * libpng yet, but more support will be added as needed.
+ *
+ * png_debug[1-2]?(level, message ,arg{0-2})
+ * Expands to a statement (either a simple expression or a compound
+ * do..while(0) statement) that outputs a message with parameter
+ * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG
+ * is undefined, 0 or 1 every png_debug expands to a simple expression
+ * (actually ((void)0)).
+ *
+ * level: level of detail of message, starting at 0. A level 'n'
+ * message is preceded by 'n' 3-space indentations (not implemented
+ * on Microsoft compilers unless PNG_DEBUG_FILE is also
+ * defined, to allow debug DLL compilation with no standard IO).
+ * message: a printf(3) style text string. A trailing '\n' is added
+ * to the message.
+ * arg: 0 to 2 arguments for printf(3) style substitution in message.
+ */
+#ifndef PNGDEBUG_H
+#define PNGDEBUG_H
+/* These settings control the formatting of messages in png.c and pngerror.c */
+/* Moved to pngdebug.h at 1.5.0 */
+# ifndef PNG_LITERAL_SHARP
+# define PNG_LITERAL_SHARP 0x23
+# endif
+# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET
+# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
+# endif
+# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET
+# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d
+# endif
+# ifndef PNG_STRING_NEWLINE
+# define PNG_STRING_NEWLINE "\n"
+# endif
+
+#ifdef PNG_DEBUG
+# if (PNG_DEBUG > 0)
+# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)
+# include
+# if (PNG_DEBUG > 1)
+# ifndef _DEBUG
+# define _DEBUG
+# endif
+# ifndef png_debug
+# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE)
+# endif
+# ifndef png_debug1
+# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1)
+# endif
+# ifndef png_debug2
+# define png_debug2(l,m,p1,p2) \
+ _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2)
+# endif
+# endif
+# else /* PNG_DEBUG_FILE || !_MSC_VER */
+# ifndef PNG_STDIO_SUPPORTED
+# include /* not included yet */
+# endif
+# ifndef PNG_DEBUG_FILE
+# define PNG_DEBUG_FILE stderr
+# endif /* PNG_DEBUG_FILE */
+
+# if (PNG_DEBUG > 1)
+# ifdef __STDC__
+# ifndef png_debug
+# define png_debug(l,m) \
+ do { \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \
+ } while (0)
+# endif
+# ifndef png_debug1
+# define png_debug1(l,m,p1) \
+ do { \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \
+ } while (0)
+# endif
+# ifndef png_debug2
+# define png_debug2(l,m,p1,p2) \
+ do { \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\
+ } while (0)
+# endif
+# else /* __STDC __ */
+# ifndef png_debug
+# define png_debug(l,m) \
+ do { \
+ int num_tabs=l; \
+ char format[256]; \
+ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \
+ m,PNG_STRING_NEWLINE); \
+ fprintf(PNG_DEBUG_FILE,format); \
+ } while (0)
+# endif
+# ifndef png_debug1
+# define png_debug1(l,m,p1) \
+ do { \
+ int num_tabs=l; \
+ char format[256]; \
+ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \
+ m,PNG_STRING_NEWLINE); \
+ fprintf(PNG_DEBUG_FILE,format,p1); \
+ } while (0)
+# endif
+# ifndef png_debug2
+# define png_debug2(l,m,p1,p2) \
+ do { \
+ int num_tabs=l; \
+ char format[256]; \
+ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \
+ m,PNG_STRING_NEWLINE); \
+ fprintf(PNG_DEBUG_FILE,format,p1,p2); \
+ } while (0)
+# endif
+# endif /* __STDC __ */
+# endif /* (PNG_DEBUG > 1) */
+
+# endif /* _MSC_VER */
+# endif /* (PNG_DEBUG > 0) */
+#endif /* PNG_DEBUG */
+#ifndef png_debug
+# define png_debug(l, m) ((void)0)
+#endif
+#ifndef png_debug1
+# define png_debug1(l, m, p1) ((void)0)
+#endif
+#ifndef png_debug2
+# define png_debug2(l, m, p1, p2) ((void)0)
+#endif
+#endif /* PNGDEBUG_H */
diff --git a/PDF/include/Poco/PDF/pnginfo.h b/PDF/include/Poco/PDF/pnginfo.h
new file mode 100644
index 000000000..1f98dedc4
--- /dev/null
+++ b/PDF/include/Poco/PDF/pnginfo.h
@@ -0,0 +1,267 @@
+
+/* pnginfo.h - header file for PNG reference library
+ *
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ */
+#ifndef PNGINFO_H
+#define PNGINFO_H
+
+struct png_info_def
+{
+ /* The following are necessary for every PNG file */
+ png_uint_32 width; /* width of image in pixels (from IHDR) */
+ png_uint_32 height; /* height of image in pixels (from IHDR) */
+ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
+ size_t rowbytes; /* bytes needed to hold an untransformed row */
+ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
+ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
+ /* The following three should have been named *_method not *_type */
+ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+
+ /* The following are set by png_set_IHDR, called from the application on
+ * write, but the are never actually used by the write code.
+ */
+ png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte spare_byte; /* to align the data, and for future use */
+
+#ifdef PNG_READ_SUPPORTED
+ /* This is never set during write */
+ png_byte signature[8]; /* magic bytes read by libpng from start of file */
+#endif
+
+ /* The rest of the data is optional. If you are reading, check the
+ * valid field to see if the information in these are valid. If you
+ * are writing, set the valid field to those chunks you want written,
+ * and initialize the appropriate fields below.
+ */
+
+#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
+ /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are
+ * defined. When COLORSPACE is switched on all the colorspace-defining
+ * chunks should be enabled, when GAMMA is switched on all the gamma-defining
+ * chunks should be enabled. If this is not done it becomes possible to read
+ * inconsistent PNG files and assign a probably incorrect interpretation to
+ * the information. (In other words, by carefully choosing which chunks to
+ * recognize the system configuration can select an interpretation for PNG
+ * files containing ambiguous data and this will result in inconsistent
+ * behavior between different libpng builds!)
+ */
+ png_colorspace colorspace;
+#endif
+
+#ifdef PNG_iCCP_SUPPORTED
+ /* iCCP chunk data. */
+ png_charp iccp_name; /* profile name */
+ png_bytep iccp_profile; /* International Color Consortium profile data */
+ png_uint_32 iccp_proflen; /* ICC profile data length */
+#endif
+
+#ifdef PNG_TEXT_SUPPORTED
+ /* The tEXt, and zTXt chunks contain human-readable textual data in
+ * uncompressed, compressed, and optionally compressed forms, respectively.
+ * The data in "text" is an array of pointers to uncompressed,
+ * null-terminated C strings. Each chunk has a keyword that describes the
+ * textual data contained in that chunk. Keywords are not required to be
+ * unique, and the text string may be empty. Any number of text chunks may
+ * be in an image.
+ */
+ int num_text; /* number of comments read or comments to write */
+ int max_text; /* current size of text array */
+ png_textp text; /* array of comments read or comments to write */
+#endif /* TEXT */
+
+#ifdef PNG_tIME_SUPPORTED
+ /* The tIME chunk holds the last time the displayed image data was
+ * modified. See the png_time struct for the contents of this struct.
+ */
+ png_time mod_time;
+#endif
+
+#ifdef PNG_sBIT_SUPPORTED
+ /* The sBIT chunk specifies the number of significant high-order bits
+ * in the pixel data. Values are in the range [1, bit_depth], and are
+ * only specified for the channels in the pixel data. The contents of
+ * the low-order bits is not specified. Data is valid if
+ * (valid & PNG_INFO_sBIT) is non-zero.
+ */
+ png_color_8 sig_bit; /* significant bits in color channels */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \
+defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The tRNS chunk supplies transparency data for paletted images and
+ * other image types that don't need a full alpha channel. There are
+ * "num_trans" transparency values for a paletted image, stored in the
+ * same order as the palette colors, starting from index 0. Values
+ * for the data are in the range [0, 255], ranging from fully transparent
+ * to fully opaque, respectively. For non-paletted images, there is a
+ * single color specified that should be treated as fully transparent.
+ * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+ */
+ png_bytep trans_alpha; /* alpha values for paletted image */
+ png_color_16 trans_color; /* transparent color for non-palette image */
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The bKGD chunk gives the suggested image background color if the
+ * display program does not have its own background color and the image
+ * is needs to composited onto a background before display. The colors
+ * in "background" are normally in the same color space/depth as the
+ * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+ */
+ png_color_16 background;
+#endif
+
+#ifdef PNG_oFFs_SUPPORTED
+ /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+ * and downwards from the top-left corner of the display, page, or other
+ * application-specific co-ordinate space. See the PNG_OFFSET_ defines
+ * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
+ */
+ png_int_32 x_offset; /* x offset on page */
+ png_int_32 y_offset; /* y offset on page */
+ png_byte offset_unit_type; /* offset units type */
+#endif
+
+#ifdef PNG_pHYs_SUPPORTED
+ /* The pHYs chunk gives the physical pixel density of the image for
+ * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+ */
+ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+ png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif
+
+#ifdef PNG_eXIf_SUPPORTED
+ int 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
+ /* The hIST chunk contains the relative frequency or importance of the
+ * various palette entries, so that a viewer can intelligently select a
+ * reduced-color palette, if required. Data is an array of "num_palette"
+ * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+ * is non-zero.
+ */
+ png_uint_16p hist;
+#endif
+
+#ifdef PNG_pCAL_SUPPORTED
+ /* The pCAL chunk describes a transformation between the stored pixel
+ * values and original physical data values used to create the image.
+ * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+ * range given by [pcal_X0, pcal_X1], and are further transformed by a
+ * (possibly non-linear) transformation function given by "pcal_type"
+ * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
+ * defines below, and the PNG-Group's PNG extensions document for a
+ * complete description of the transformations and how they should be
+ * implemented, and for a description of the ASCII parameter strings.
+ * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+ */
+ png_charp pcal_purpose; /* pCAL chunk description string */
+ png_int_32 pcal_X0; /* minimum value */
+ png_int_32 pcal_X1; /* maximum value */
+ png_charp pcal_units; /* Latin-1 string giving physical units */
+ png_charpp pcal_params; /* ASCII strings containing parameter values */
+ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
+ png_byte pcal_nparams; /* number of parameters given in pcal_params */
+#endif
+
+/* New members added in libpng-1.0.6 */
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ /* Storage for unknown chunks that the library doesn't recognize. */
+ png_unknown_chunkp unknown_chunks;
+
+ /* The type of this field is limited by the type of
+ * png_struct::user_chunk_cache_max, else overflow can occur.
+ */
+ int unknown_chunks_num;
+#endif
+
+#ifdef PNG_sPLT_SUPPORTED
+ /* Data on sPLT chunks (there may be more than one). */
+ png_sPLT_tp splt_palettes;
+ int splt_palettes_num; /* Match type returned by png_get API */
+#endif
+
+#ifdef PNG_sCAL_SUPPORTED
+ /* The sCAL chunk describes the actual physical dimensions of the
+ * subject matter of the graphic. The chunk contains a unit specification
+ * a byte value, and two ASCII strings representing floating-point
+ * values. The values are width and height corresponding to one pixel
+ * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is
+ * non-zero.
+ */
+ png_byte scal_unit; /* unit of physical scale */
+ png_charp scal_s_width; /* string containing height */
+ png_charp scal_s_height; /* string containing width */
+#endif
+
+#ifdef PNG_INFO_IMAGE_SUPPORTED
+ /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS)
+ non-zero */
+ /* Data valid if (valid & PNG_INFO_IDAT) non-zero */
+ png_bytepp row_pointers; /* the image bits */
+#endif
+
+};
+#endif /* PNGINFO_H */
diff --git a/PDF/include/Poco/PDF/pnglibconf.h b/PDF/include/Poco/PDF/pnglibconf.h
new file mode 100644
index 000000000..83f09fbe7
--- /dev/null
+++ b/PDF/include/Poco/PDF/pnglibconf.h
@@ -0,0 +1,224 @@
+/* pnglibconf.h - library build configuration */
+
+/* libpng version 1.6.43 */
+
+/* Copyright (c) 2018-2024 Cosmin Truta */
+/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
+
+/* This code is released under the libpng license. */
+/* For conditions of distribution and use, see the disclaimer */
+/* and license in png.h */
+
+/* pnglibconf.h */
+/* Machine generated file: DO NOT EDIT */
+/* Derived from: scripts/pnglibconf.dfa */
+#ifndef PNGLCONF_H
+#define PNGLCONF_H
+/* options */
+#define PNG_16BIT_SUPPORTED
+#define PNG_ALIGNED_MEMORY_SUPPORTED
+/*#undef PNG_ARM_NEON_API_SUPPORTED*/
+/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
+#define PNG_BENIGN_ERRORS_SUPPORTED
+#define PNG_BENIGN_READ_ERRORS_SUPPORTED
+/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/
+#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_COLORSPACE_SUPPORTED
+#define PNG_CONSOLE_IO_SUPPORTED
+#define PNG_CONVERT_tIME_SUPPORTED
+/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/
+#define PNG_EASY_ACCESS_SUPPORTED
+/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
+#define PNG_ERROR_TEXT_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_GAMMA_SUPPORTED
+#define PNG_GET_PALETTE_MAX_SUPPORTED
+#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+#define PNG_INCH_CONVERSIONS_SUPPORTED
+#define PNG_INFO_IMAGE_SUPPORTED
+#define PNG_IO_STATE_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_POINTER_INDEXING_SUPPORTED
+/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
+/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/
+#define PNG_PROGRESSIVE_READ_SUPPORTED
+#define PNG_READ_16BIT_SUPPORTED
+#define PNG_READ_ALPHA_MODE_SUPPORTED
+#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#define PNG_READ_BACKGROUND_SUPPORTED
+#define PNG_READ_BGR_SUPPORTED
+#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
+#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
+#define PNG_READ_EXPAND_16_SUPPORTED
+#define PNG_READ_EXPAND_SUPPORTED
+#define PNG_READ_FILLER_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_INT_FUNCTIONS_SUPPORTED
+#define PNG_READ_INVERT_ALPHA_SUPPORTED
+#define PNG_READ_INVERT_SUPPORTED
+#define PNG_READ_OPT_PLTE_SUPPORTED
+#define PNG_READ_PACKSWAP_SUPPORTED
+#define PNG_READ_PACK_SUPPORTED
+#define PNG_READ_QUANTIZE_SUPPORTED
+#define PNG_READ_RGB_TO_GRAY_SUPPORTED
+#define PNG_READ_SCALE_16_TO_8_SUPPORTED
+#define PNG_READ_SHIFT_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_TRANSFORMS_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_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_SIMPLIFIED_READ_AFIRST_SUPPORTED
+#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED
+#define PNG_SIMPLIFIED_READ_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_SUPPORTED
+#define PNG_STDIO_SUPPORTED
+#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_TEXT_SUPPORTED
+#define PNG_TIME_RFC1123_SUPPORTED
+#define PNG_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_USER_CHUNKS_SUPPORTED
+#define PNG_USER_LIMITS_SUPPORTED
+#define PNG_USER_MEM_SUPPORTED
+#define PNG_USER_TRANSFORM_INFO_SUPPORTED
+#define PNG_USER_TRANSFORM_PTR_SUPPORTED
+#define PNG_WARNINGS_SUPPORTED
+#define PNG_WRITE_16BIT_SUPPORTED
+#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#define PNG_WRITE_BGR_SUPPORTED
+#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+#define PNG_WRITE_FILLER_SUPPORTED
+#define PNG_WRITE_FILTER_SUPPORTED
+#define PNG_WRITE_FLUSH_SUPPORTED
+#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
+#define PNG_WRITE_INTERLACING_SUPPORTED
+#define PNG_WRITE_INT_FUNCTIONS_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_oFFs_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
+#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_sPLT_SUPPORTED
+#define PNG_WRITE_sRGB_SUPPORTED
+#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_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 */
+#define PNG_API_RULE 0
+#define PNG_DEFAULT_READ_MACROS 1
+#define PNG_GAMMA_THRESHOLD_FIXED 5000
+#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE
+#define PNG_INFLATE_BUF_SIZE 1024
+#define PNG_LINKAGE_API extern
+#define PNG_LINKAGE_CALLBACK extern
+#define PNG_LINKAGE_DATA extern
+#define PNG_LINKAGE_FUNCTION extern
+#define PNG_MAX_GAMMA_8 11
+#define PNG_QUANTIZE_BLUE_BITS 5
+#define PNG_QUANTIZE_GREEN_BITS 5
+#define PNG_QUANTIZE_RED_BITS 5
+#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 0 /* unknown */
+#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
+/* end of settings */
+#endif /* PNGLCONF_H */
diff --git a/PDF/include/Poco/PDF/pngpriv.h b/PDF/include/Poco/PDF/pngpriv.h
new file mode 100644
index 000000000..9bfdb7134
--- /dev/null
+++ b/PDF/include/Poco/PDF/pngpriv.h
@@ -0,0 +1,2221 @@
+
+/* pngpriv.h - private declarations for use inside libpng
+ *
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+
+/* The symbols declared in this file (including the functions declared
+ * as extern) are PRIVATE. They are not part of the libpng public
+ * interface, and are not recommended for use by regular applications.
+ * Some of them may become public in the future; others may stay private,
+ * change in an incompatible way, or even disappear.
+ * Although the libpng users are not forbidden to include this header,
+ * they should be well aware of the issues that may arise from doing so.
+ */
+
+#ifndef PNGPRIV_H
+#define PNGPRIV_H
+
+/* Feature Test Macros. The following are defined here to ensure that correctly
+ * implemented libraries reveal the APIs libpng needs to build and hide those
+ * that are not needed and potentially damaging to the compilation.
+ *
+ * Feature Test Macros must be defined before any system header is included (see
+ * POSIX 1003.1 2.8.2 "POSIX Symbols."
+ *
+ * These macros only have an effect if the operating system supports either
+ * POSIX 1003.1 or C99, or both. On other operating systems (particularly
+ * Windows/Visual Studio) there is no effect; the OS specific tests below are
+ * still required (as of 2011-05-02.)
+ */
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+/* Standard library headers not required by png.h: */
+# include
+# include
+#endif
+
+#define PNGLIB_BUILD /*libpng is being built, not used*/
+
+/* If HAVE_CONFIG_H is defined during the build then the build system must
+ * provide an appropriate "config.h" file on the include path. The header file
+ * must provide definitions as required below (search for "HAVE_CONFIG_H");
+ * see configure.ac for more details of the requirements. The macro
+ * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on
+ * 'configure'; define this macro to prevent the configure build including the
+ * configure generated config.h. Libpng is expected to compile without *any*
+ * special build system support on a reasonably ANSI-C compliant system.
+ */
+#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
+# include
+
+ /* Pick up the definition of 'restrict' from config.h if it was read: */
+# define PNG_RESTRICT restrict
+#endif
+
+/* To support symbol prefixing it is necessary to know *before* including png.h
+ * whether the fixed point (and maybe other) APIs are exported, because if they
+ * 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
+
+/* Local renames may change non-exported API functions from png.h */
+#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
+# include "pngprefix.h"
+#endif
+
+#ifdef PNG_USER_CONFIG
+# include "pngusr.h"
+ /* These should have been defined in pngusr.h */
+# ifndef PNG_USER_PRIVATEBUILD
+# define PNG_USER_PRIVATEBUILD "Custom libpng build"
+# endif
+# ifndef PNG_USER_DLLFNAME_POSTFIX
+# define PNG_USER_DLLFNAME_POSTFIX "Cb"
+# endif
+#endif
+
+/* Compile time options.
+ * =====================
+ * In a multi-arch build the compiler may compile the code several times for the
+ * same object module, producing different binaries for different architectures.
+ * When this happens configure-time setting of the target host options cannot be
+ * done and this interferes with the handling of the ARM NEON optimizations, and
+ * possibly other similar optimizations. Put additional tests here; in general
+ * this is needed when the same option can be changed at both compile time and
+ * run time depending on the target OS (i.e. iOS vs Android.)
+ *
+ * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because
+ * this is not possible with certain compilers (Oracle SUN OS CC), as a result
+ * it is necessary to ensure that all extern functions that *might* be used
+ * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__
+ * below is one example of this behavior because it is controlled by the
+ * presence or not of -mfpu=neon on the GCC command line, it is possible to do
+ * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely
+ * do this.
+ */
+#ifndef PNG_ARM_NEON_OPT
+ /* ARM NEON optimizations are being controlled by the compiler settings,
+ * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon
+ * with GCC) then the compiler will define __ARM_NEON__ and we can rely
+ * unconditionally on NEON instructions not crashing, otherwise we must
+ * disable use of NEON instructions.
+ *
+ * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they
+ * can only be turned on automatically if that is supported too. If
+ * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail
+ * to compile with an appropriate #error if ALIGNED_MEMORY has been turned
+ * off.
+ *
+ * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated
+ * __ARM_NEON__, so we check both variants.
+ *
+ * To disable ARM_NEON optimizations entirely, and skip compiling the
+ * associated assembler code, pass --enable-arm-neon=no to configure
+ * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS.
+ */
+# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \
+ defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# define PNG_ARM_NEON_OPT 2
+# else
+# define PNG_ARM_NEON_OPT 0
+# endif
+#endif
+
+#if PNG_ARM_NEON_OPT > 0
+ /* NEON optimizations are to be at least considered by libpng, so enable the
+ * callbacks to do this.
+ */
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon
+
+ /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used
+ * if possible - if __ARM_NEON__ is set and the compiler version is not known
+ * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can
+ * be:
+ *
+ * 1 The intrinsics code (the default with __ARM_NEON__)
+ * 2 The hand coded assembler (the default without __ARM_NEON__)
+ *
+ * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however
+ * this is *NOT* supported and may cease to work even after a minor revision
+ * to libpng. It *is* valid to do this for testing purposes, e.g. speed
+ * testing or a new compiler, but the results should be communicated to the
+ * libpng implementation list for incorporation in the next minor release.
+ */
+# ifndef PNG_ARM_NEON_IMPLEMENTATION
+# if defined(__ARM_NEON__) || defined(__ARM_NEON)
+# if defined(__clang__)
+ /* At present it is unknown by the libpng developers which versions
+ * of clang support the intrinsics, however some or perhaps all
+ * versions do not work with the assembler so this may be
+ * irrelevant, so just use the default (do nothing here.)
+ */
+# elif defined(__GNUC__)
+ /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to
+ * work, so if this *is* GCC, or G++, look for a version >4.5
+ */
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
+# define PNG_ARM_NEON_IMPLEMENTATION 2
+# endif /* no GNUC support */
+# endif /* __GNUC__ */
+# else /* !defined __ARM_NEON__ */
+ /* The 'intrinsics' code simply won't compile without this -mfpu=neon:
+ */
+# if !defined(__aarch64__) && !defined(_M_ARM64)
+ /* The assembler code currently does not work on ARM64 */
+# define PNG_ARM_NEON_IMPLEMENTATION 2
+# endif /* __aarch64__ */
+# endif /* __ARM_NEON__ */
+# endif /* !PNG_ARM_NEON_IMPLEMENTATION */
+
+# ifndef PNG_ARM_NEON_IMPLEMENTATION
+ /* Use the intrinsics code by default. */
+# define PNG_ARM_NEON_IMPLEMENTATION 1
+# endif
+#else /* PNG_ARM_NEON_OPT == 0 */
+# define PNG_ARM_NEON_IMPLEMENTATION 0
+#endif /* PNG_ARM_NEON_OPT > 0 */
+
+#ifndef PNG_MIPS_MSA_OPT
+# if defined(__mips_msa) && (__mips_isa_rev >= 5) && \
+ defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# define PNG_MIPS_MSA_OPT 2
+# else
+# define PNG_MIPS_MSA_OPT 0
+# endif
+#endif
+
+#ifndef PNG_MIPS_MMI_OPT
+# ifdef PNG_MIPS_MMI
+# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) && \
+ defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# define PNG_MIPS_MMI_OPT 1
+# else
+# define PNG_MIPS_MMI_OPT 0
+# endif
+# else
+# define PNG_MIPS_MMI_OPT 0
+# endif
+#endif
+
+#ifndef PNG_POWERPC_VSX_OPT
+# if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)
+# define PNG_POWERPC_VSX_OPT 2
+# else
+# define PNG_POWERPC_VSX_OPT 0
+# endif
+#endif
+
+#ifndef PNG_LOONGARCH_LSX_OPT
+# if defined(__loongarch_sx)
+# define PNG_LOONGARCH_LSX_OPT 1
+# else
+# define PNG_LOONGARCH_LSX_OPT 0
+# endif
+#endif
+
+#ifndef PNG_INTEL_SSE_OPT
+# ifdef PNG_INTEL_SSE
+ /* Only check for SSE if the build configuration has been modified to
+ * enable SSE optimizations. This means that these optimizations will
+ * be off by default. See contrib/intel for more details.
+ */
+# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
+ defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
+ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+# define PNG_INTEL_SSE_OPT 1
+# else
+# define PNG_INTEL_SSE_OPT 0
+# endif
+# else
+# define PNG_INTEL_SSE_OPT 0
+# endif
+#endif
+
+#if PNG_INTEL_SSE_OPT > 0
+# ifndef PNG_INTEL_SSE_IMPLEMENTATION
+# if defined(__SSE4_1__) || defined(__AVX__)
+ /* We are not actually using AVX, but checking for AVX is the best
+ way we can detect SSE4.1 and SSSE3 on MSVC.
+ */
+# define PNG_INTEL_SSE_IMPLEMENTATION 3
+# elif defined(__SSSE3__)
+# define PNG_INTEL_SSE_IMPLEMENTATION 2
+# elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
+ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+# define PNG_INTEL_SSE_IMPLEMENTATION 1
+# else
+# define PNG_INTEL_SSE_IMPLEMENTATION 0
+# endif
+# endif
+
+# if PNG_INTEL_SSE_IMPLEMENTATION > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2
+# endif
+#else
+# define PNG_INTEL_SSE_IMPLEMENTATION 0
+#endif
+
+#if PNG_MIPS_MSA_OPT > 0
+# ifndef PNG_MIPS_MSA_IMPLEMENTATION
+# if defined(__mips_msa)
+# if defined(__clang__)
+# elif defined(__GNUC__)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
+# define PNG_MIPS_MSA_IMPLEMENTATION 2
+# endif /* no GNUC support */
+# endif /* __GNUC__ */
+# else /* !defined __mips_msa */
+# define PNG_MIPS_MSA_IMPLEMENTATION 2
+# endif /* __mips_msa */
+# endif /* !PNG_MIPS_MSA_IMPLEMENTATION */
+
+# ifndef PNG_MIPS_MSA_IMPLEMENTATION
+# define PNG_MIPS_MSA_IMPLEMENTATION 1
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
+# endif
+#else
+# define PNG_MIPS_MSA_IMPLEMENTATION 0
+#endif /* PNG_MIPS_MSA_OPT > 0 */
+
+#if PNG_MIPS_MMI_OPT > 0
+# ifndef PNG_MIPS_MMI_IMPLEMENTATION
+# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64)
+# define PNG_MIPS_MMI_IMPLEMENTATION 2
+# else /* !defined __mips_loongson_mmi || _MIPS_SIM != _ABI64 */
+# define PNG_MIPS_MMI_IMPLEMENTATION 0
+# endif /* __mips_loongson_mmi && _MIPS_SIM == _ABI64 */
+# endif /* !PNG_MIPS_MMI_IMPLEMENTATION */
+
+# if PNG_MIPS_MMI_IMPLEMENTATION > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
+# endif
+#else
+# define PNG_MIPS_MMI_IMPLEMENTATION 0
+#endif /* PNG_MIPS_MMI_OPT > 0 */
+
+#if PNG_POWERPC_VSX_OPT > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx
+# define PNG_POWERPC_VSX_IMPLEMENTATION 1
+#else
+# define PNG_POWERPC_VSX_IMPLEMENTATION 0
+#endif
+
+#if PNG_LOONGARCH_LSX_OPT > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_lsx
+# define PNG_LOONGARCH_LSX_IMPLEMENTATION 1
+#else
+# define PNG_LOONGARCH_LSX_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.
+ *
+ * If libpng is used inside a DLL but that DLL does not export the libpng APIs
+ * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a
+ * static library of libpng then link the DLL against that.
+ */
+#ifndef PNG_BUILD_DLL
+# ifdef DLL_EXPORT
+ /* This is set by libtool when files are compiled for a DLL; libtool
+ * always compiles twice, even on systems where it isn't necessary. Set
+ * PNG_BUILD_DLL in case it is necessary:
+ */
+# define PNG_BUILD_DLL
+# else
+# ifdef _WINDLL
+ /* This is set by the Microsoft Visual Studio IDE in projects that
+ * build a DLL. It can't easily be removed from those projects (it
+ * isn't visible in the Visual Studio UI) so it is a fairly reliable
+ * indication that PNG_IMPEXP needs to be set to the DLL export
+ * attributes.
+ */
+# define PNG_BUILD_DLL
+# else
+# ifdef __DLL__
+ /* This is set by the Borland C system when compiling for a DLL
+ * (as above.)
+ */
+# define PNG_BUILD_DLL
+# else
+ /* Add additional compiler cases here. */
+# endif
+# endif
+# endif
+#endif /* Setting PNG_BUILD_DLL if required */
+
+/* See pngconf.h for more details: the builder of the library may set this on
+ * the command line to the right thing for the specific compilation system or it
+ * may be automagically set above (at present we know of no system where it does
+ * need to be set on the command line.)
+ *
+ * PNG_IMPEXP must be set here when building the library to prevent pngconf.h
+ * setting it to the "import" setting for a DLL build.
+ */
+#ifndef PNG_IMPEXP
+# ifdef PNG_BUILD_DLL
+# define PNG_IMPEXP PNG_DLL_EXPORT
+# else
+ /* Not building a DLL, or the DLL doesn't require specific export
+ * definitions.
+ */
+# define PNG_IMPEXP
+# endif
+#endif
+
+/* No warnings for private or deprecated functions in the build: */
+#ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED
+#endif
+#ifndef PNG_PRIVATE
+# define PNG_PRIVATE
+#endif
+
+/* Symbol preprocessing support.
+ *
+ * To enable listing global, but internal, symbols the following macros should
+ * always be used to declare an extern data or function object in this file.
+ */
+#ifndef PNG_INTERNAL_DATA
+# define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array
+#endif
+
+#ifndef PNG_INTERNAL_FUNCTION
+# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\
+ PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes)
+#endif
+
+#ifndef PNG_INTERNAL_CALLBACK
+# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\
+ PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\
+ PNG_EMPTY attributes)
+#endif
+
+/* If floating or fixed point APIs are disabled they may still be compiled
+ * internally. To handle this make sure they are declared as the appropriate
+ * internal extern function (otherwise the symbol prefixing stuff won't work and
+ * the functions will be used without definitions.)
+ *
+ * NOTE: although all the API functions are declared here they are not all
+ * actually built! Because the declarations are still made it is necessary to
+ * fake out types that they depend on.
+ */
+#ifndef PNG_FP_EXPORT
+# ifndef PNG_FLOATING_POINT_SUPPORTED
+# define PNG_FP_EXPORT(ordinal, type, name, args)\
+ PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);
+# ifndef PNG_VERSION_INFO_ONLY
+ typedef struct png_incomplete png_double;
+ typedef png_double* png_doublep;
+ typedef const png_double* png_const_doublep;
+ typedef png_double** png_doublepp;
+# endif
+# endif
+#endif
+#ifndef PNG_FIXED_EXPORT
+# ifndef PNG_FIXED_POINT_SUPPORTED
+# define PNG_FIXED_EXPORT(ordinal, type, name, args)\
+ PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);
+# endif
+#endif
+
+#include "png.h"
+
+/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */
+#ifndef PNG_DLL_EXPORT
+# define PNG_DLL_EXPORT
+#endif
+
+/* This is a global switch to set the compilation for an installed system
+ * (a release build). It can be set for testing debug builds to ensure that
+ * they will compile when the build type is switched to RC or STABLE, the
+ * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE. Set this in CPPFLAGS
+ * with either:
+ *
+ * -DPNG_RELEASE_BUILD Turns on the release compile path
+ * -DPNG_RELEASE_BUILD=0 Turns it off
+ * or in your pngusr.h with
+ * #define PNG_RELEASE_BUILD=1 Turns on the release compile path
+ * #define PNG_RELEASE_BUILD=0 Turns it off
+ */
+#ifndef PNG_RELEASE_BUILD
+# define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC)
+#endif
+
+/* SECURITY and SAFETY:
+ *
+ * libpng is built with support for internal limits on image dimensions and
+ * memory usage. These are documented in scripts/pnglibconf.dfa of the
+ * source and recorded in the machine generated header file pnglibconf.h.
+ */
+
+/* If you are running on a machine where you cannot allocate more
+ * than 64K of memory at once, uncomment this. While libpng will not
+ * normally need that much memory in a chunk (unless you load up a very
+ * large file), zlib needs to know how big of a chunk it can use, and
+ * libpng thus makes sure to check any memory allocation to verify it
+ * will fit into memory.
+ *
+ * zlib provides 'MAXSEG_64K' which, if defined, indicates the
+ * same limit and pngconf.h (already included) sets the limit
+ * if certain operating systems are detected.
+ */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+# define PNG_MAX_MALLOC_64K
+#endif
+
+#ifndef PNG_UNUSED
+/* Unused formal parameter warnings are silenced using the following macro
+ * which is expected to have no bad effects on performance (optimizing
+ * compilers will probably remove it entirely). Note that if you replace
+ * it with something other than whitespace, you must include the terminating
+ * semicolon.
+ */
+# define PNG_UNUSED(param) (void)param;
+#endif
+
+/* Just a little check that someone hasn't tried to define something
+ * contradictory.
+ */
+#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K)
+# undef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 65536L
+#endif
+
+/* If warnings or errors are turned off the code is disabled or redirected here.
+ * From 1.5.4 functions have been added to allow very limited formatting of
+ * error and warning messages - this code will also be disabled here.
+ */
+#ifdef PNG_WARNINGS_SUPPORTED
+# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;
+#else
+# define png_warning_parameter(p,number,string) ((void)0)
+# define png_warning_parameter_unsigned(p,number,format,value) ((void)0)
+# define png_warning_parameter_signed(p,number,format,value) ((void)0)
+# define png_formatted_warning(pp,p,message) ((void)(pp))
+# define PNG_WARNING_PARAMETERS(p)
+#endif
+#ifndef PNG_ERROR_TEXT_SUPPORTED
+# define png_fixed_error(s1,s2) png_err(s1)
+#endif
+
+/* Some fixed point APIs are still required even if not exported because
+ * they get used by the corresponding floating point APIs. This magic
+ * deals with this:
+ */
+#ifdef PNG_FIXED_POINT_SUPPORTED
+# define PNGFAPI PNGAPI
+#else
+# define PNGFAPI /* PRIVATE */
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+/* Other defines specific to compilers can go here. Try to keep
+ * them inside an appropriate ifdef/endif pair for portability.
+ */
+
+/* C allows up-casts from (void*) to any pointer and (const void*) to any
+ * pointer to a const object. C++ regards this as a type error and requires an
+ * explicit, static, cast and provides the static_cast<> rune to ensure that
+ * const is not cast away.
+ */
+#ifdef __cplusplus
+# define png_voidcast(type, value) static_cast(value)
+# define png_constcast(type, value) const_cast(value)
+# define png_aligncast(type, value) \
+ static_cast(static_cast(value))
+# define png_aligncastconst(type, value) \
+ static_cast(static_cast(value))
+#else
+# define png_voidcast(type, value) (value)
+# define png_constcast(type, value) ((type)(void*)(const void*)(value))
+# define png_aligncast(type, value) ((void*)(value))
+# define png_aligncastconst(type, value) ((const void*)(value))
+#endif /* __cplusplus */
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\
+ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
+ /* png.c requires the following ANSI-C constants if the conversion of
+ * floating point to ASCII is implemented therein:
+ *
+ * DBL_DIG Maximum number of decimal digits (can be set to any constant)
+ * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value)
+ * DBL_MAX Maximum floating point number (can be set to an arbitrary value)
+ */
+# include
+
+# include
+
+# if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
+ /* Amiga SAS/C: We must include builtin FPU functions when compiling using
+ * MATH=68881
+ */
+# include
+# endif
+#endif
+
+/* This provides the non-ANSI (far) memory allocation routines. */
+#if defined(__TURBOC__) && defined(__MSDOS__)
+# include
+# include
+#endif
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+# include
+#endif
+#endif /* PNG_VERSION_INFO_ONLY */
+
+/* Moved here around 1.5.0beta36 from pngconf.h */
+/* Users may want to use these so they are not private. Any library
+ * functions that are passed far data must be model-independent.
+ */
+
+/* Platform-independent functions */
+#ifndef PNG_ABORT
+# define PNG_ABORT() abort()
+#endif
+
+/* These macros may need to be architecture dependent. */
+#define PNG_ALIGN_NONE 0 /* do not use data alignment */
+#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */
+#ifdef offsetof
+# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */
+#else
+# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */
+#endif
+#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */
+
+#ifndef PNG_ALIGN_TYPE
+ /* Default to using aligned access optimizations and requiring alignment to a
+ * multiple of the data type size. Override in a compiler specific fashion
+ * if necessary by inserting tests here:
+ */
+# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE
+#endif
+
+#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE
+ /* This is used because in some compiler implementations non-aligned
+ * structure members are supported, so the offsetof approach below fails.
+ * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access
+ * is good for performance. Do not do this unless you have tested the
+ * result and understand it.
+ */
+# define png_alignof(type) (sizeof(type))
+#else
+# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET
+# define png_alignof(type) offsetof(struct{char c; type t;}, t)
+# else
+# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS
+# define png_alignof(type) 1
+# endif
+ /* Else leave png_alignof undefined to prevent use thereof */
+# endif
+#endif
+
+/* This implicitly assumes alignment is always a multiple of 2. */
+#ifdef png_alignof
+# define png_isaligned(ptr, type) \
+ (((type)(size_t)((const void*)(ptr)) & (type)(png_alignof(type)-1)) == 0)
+#else
+# define png_isaligned(ptr, type) 0
+#endif
+
+/* End of memory model/platform independent support */
+/* End of 1.5.0beta36 move from pngconf.h */
+
+/* CONSTANTS and UTILITY MACROS
+ * These are used internally by libpng and not exposed in the API
+ */
+
+/* Various modes of operation. Note that after an init, mode is set to
+ * zero automatically when the structure is created. Three of these
+ * are defined in png.h because they need to be visible to applications
+ * that call png_set_unknown_chunk().
+ */
+/* #define PNG_HAVE_IHDR 0x01U (defined in png.h) */
+/* #define PNG_HAVE_PLTE 0x02U (defined in png.h) */
+#define PNG_HAVE_IDAT 0x04U
+/* #define PNG_AFTER_IDAT 0x08U (defined in png.h) */
+#define PNG_HAVE_IEND 0x10U
+ /* 0x20U (unused) */
+ /* 0x40U (unused) */
+ /* 0x80U (unused) */
+#define PNG_HAVE_CHUNK_HEADER 0x100U
+#define PNG_WROTE_tIME 0x200U
+#define PNG_WROTE_INFO_BEFORE_PLTE 0x400U
+#define PNG_BACKGROUND_IS_GRAY 0x800U
+#define PNG_HAVE_PNG_SIGNATURE 0x1000U
+#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
+#define PNG_WROTE_eXIf 0x4000U
+#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
+
+/* Flags for the transformations the PNG library does on the image data */
+#define PNG_BGR 0x0001U
+#define PNG_INTERLACE 0x0002U
+#define PNG_PACK 0x0004U
+#define PNG_SHIFT 0x0008U
+#define PNG_SWAP_BYTES 0x0010U
+#define PNG_INVERT_MONO 0x0020U
+#define PNG_QUANTIZE 0x0040U
+#define PNG_COMPOSE 0x0080U /* Was PNG_BACKGROUND */
+#define PNG_BACKGROUND_EXPAND 0x0100U
+#define PNG_EXPAND_16 0x0200U /* Added to libpng 1.5.2 */
+#define PNG_16_TO_8 0x0400U /* Becomes 'chop' in 1.5.4 */
+#define PNG_RGBA 0x0800U
+#define PNG_EXPAND 0x1000U
+#define PNG_GAMMA 0x2000U
+#define PNG_GRAY_TO_RGB 0x4000U
+#define PNG_FILLER 0x8000U
+#define PNG_PACKSWAP 0x10000U
+#define PNG_SWAP_ALPHA 0x20000U
+#define PNG_STRIP_ALPHA 0x40000U
+#define PNG_INVERT_ALPHA 0x80000U
+#define PNG_USER_TRANSFORM 0x100000U
+#define PNG_RGB_TO_GRAY_ERR 0x200000U
+#define PNG_RGB_TO_GRAY_WARN 0x400000U
+#define PNG_RGB_TO_GRAY 0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */
+#define PNG_ENCODE_ALPHA 0x800000U /* Added to libpng-1.5.4 */
+#define PNG_ADD_ALPHA 0x1000000U /* Added to libpng-1.2.7 */
+#define PNG_EXPAND_tRNS 0x2000000U /* Added to libpng-1.2.9 */
+#define PNG_SCALE_16_TO_8 0x4000000U /* Added to libpng-1.5.4 */
+ /* 0x8000000U unused */
+ /* 0x10000000U unused */
+ /* 0x20000000U unused */
+ /* 0x40000000U unused */
+/* Flags for png_create_struct */
+#define PNG_STRUCT_PNG 0x0001U
+#define PNG_STRUCT_INFO 0x0002U
+
+/* Flags for the png_ptr->flags rather than declaring a byte for each one */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001U
+#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002U /* Added to libpng-1.6.0 */
+ /* 0x0004U unused */
+#define PNG_FLAG_ZSTREAM_ENDED 0x0008U /* Added to libpng-1.6.0 */
+ /* 0x0010U unused */
+ /* 0x0020U unused */
+#define PNG_FLAG_ROW_INIT 0x0040U
+#define PNG_FLAG_FILLER_AFTER 0x0080U
+#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100U
+#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 */
+#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 */
+/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000U */
+#define PNG_FLAG_LIBRARY_MISMATCH 0x20000U
+#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000U
+#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000U
+#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000U /* Added to libpng-1.4.0 */
+#define PNG_FLAG_APP_WARNINGS_WARN 0x200000U /* Added to libpng-1.6.0 */
+#define PNG_FLAG_APP_ERRORS_WARN 0x400000U /* Added to libpng-1.6.0 */
+ /* 0x800000U unused */
+ /* 0x1000000U unused */
+ /* 0x2000000U unused */
+ /* 0x4000000U unused */
+ /* 0x8000000U unused */
+ /* 0x10000000U unused */
+ /* 0x20000000U unused */
+ /* 0x40000000U unused */
+
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+ PNG_FLAG_CRC_ANCILLARY_NOWARN)
+
+#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
+ PNG_FLAG_CRC_CRITICAL_IGNORE)
+
+#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
+ PNG_FLAG_CRC_CRITICAL_MASK)
+
+/* Save typing and make code easier to understand */
+
+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
+ abs((int)((c1).green) - (int)((c2).green)) + \
+ abs((int)((c1).blue) - (int)((c2).blue)))
+
+/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255
+ * by dividing by 257 *with rounding*. This macro is exact for the given range.
+ * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the
+ * macro were established by experiment (modifying the added value). The macro
+ * has a second variant that takes a value already scaled by 255 and divides by
+ * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it
+ * only gives off-by-one errors and only for 0.5% (1 in 200) of the values.
+ */
+#define PNG_DIV65535(v24) (((v24) + 32895) >> 16)
+#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255)
+
+/* Added to libpng-1.2.6 JB */
+#define PNG_ROWBYTES(pixel_bits, width) \
+ ((pixel_bits) >= 8 ? \
+ ((size_t)(width) * (((size_t)(pixel_bits)) >> 3)) : \
+ (( ((size_t)(width) * ((size_t)(pixel_bits))) + 7) >> 3) )
+
+/* This returns the number of trailing bits in the last byte of a row, 0 if the
+ * last byte is completely full of pixels. It is, in principle, (pixel_bits x
+ * width) % 8, but that would overflow for large 'width'. The second macro is
+ * the same except that it returns the number of unused bits in the last byte;
+ * (8-TRAILBITS), but 0 when TRAILBITS is 0.
+ *
+ * NOTE: these macros are intended to be self-evidently correct and never
+ * overflow on the assumption that pixel_bits is in the range 0..255. The
+ * arguments are evaluated only once and they can be signed (e.g. as a result of
+ * the integral promotions). The result of the expression always has type
+ * (png_uint_32), however the compiler always knows it is in the range 0..7.
+ */
+#define PNG_TRAILBITS(pixel_bits, width) \
+ (((pixel_bits) * ((width) % (png_uint_32)8)) % 8)
+
+#define PNG_PADBITS(pixel_bits, width) \
+ ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8)
+
+/* PNG_OUT_OF_RANGE returns true if value is outside the range
+ * ideal-delta..ideal+delta. Each argument is evaluated twice.
+ * "ideal" and "delta" should be constants, normally simple
+ * integers, "value" a variable. Added to libpng-1.2.6 JB
+ */
+#define PNG_OUT_OF_RANGE(value, ideal, delta) \
+ ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )
+
+/* Conversions between fixed and floating point, only defined if
+ * required (to make sure the code doesn't accidentally use float
+ * when it is supposedly disabled.)
+ */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+/* The floating point conversion can't overflow, though it can and
+ * does lose accuracy relative to the original fixed point value.
+ * In practice this doesn't matter because png_fixed_point only
+ * stores numbers with very low precision. The png_ptr and s
+ * arguments are unused by default but are there in case error
+ * checking becomes a requirement.
+ */
+#define png_float(png_ptr, fixed, s) (.00001 * (fixed))
+
+/* The fixed point conversion performs range checking and evaluates
+ * its argument multiple times, so must be used with care. The
+ * range checking uses the PNG specification values for a signed
+ * 32-bit fixed point value except that the values are deliberately
+ * rounded-to-zero to an integral value - 21474 (21474.83 is roughly
+ * (2^31-1) * 100000). 's' is a string that describes the value being
+ * converted.
+ *
+ * NOTE: this macro will raise a png_error if the range check fails,
+ * therefore it is normally only appropriate to use this on values
+ * that come from API calls or other sources where an out of range
+ * error indicates a programming error, not a data error!
+ *
+ * NOTE: by default this is off - the macro is not used - because the
+ * function call saves a lot of code.
+ */
+#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))
+#endif
+/* else the corresponding function is defined below, inside the scope of the
+ * cplusplus test.
+ */
+#endif
+
+/* Constants for known chunk types. If you need to add a chunk, define the name
+ * here. For historical reasons these constants have the form png_; i.e.
+ * the prefix is lower case. Please use decimal values as the parameters to
+ * match the ISO PNG specification and to avoid relying on the C locale
+ * interpretation of character values.
+ *
+ * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values
+ * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string
+ * to be generated if required.
+ *
+ * PNG_32b correctly produces a value shifted by up to 24 bits, even on
+ * architectures where (int) is only 16 bits.
+ */
+#define PNG_32b(b,s) ((png_uint_32)(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))
+
+/* Constants for known chunk types.
+ *
+ * MAINTAINERS: If you need to add a chunk, define the name here.
+ * For historical reasons these constants have the form png_; i.e.
+ * the prefix is lower case. Please use decimal values as the parameters to
+ * match the ISO PNG specification and to avoid relying on the C locale
+ * interpretation of character values. Please keep the list sorted.
+ *
+ * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk
+ * type. In fact the specification does not express chunk types this way,
+ * however using a 32-bit value means that the chunk type can be read from the
+ * stream using exactly the same code as used for a 32-bit unsigned value and
+ * can be examined far more efficiently (using one arithmetic compare).
+ *
+ * Prior to 1.5.6 the chunk type constants were expressed as C strings. The
+ * libpng API still uses strings for 'unknown' chunks and a macro,
+ * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice
+ * that for portable code numeric values must still be used; the string "IHDR"
+ * is not portable and neither is PNG_U32('I', 'H', 'D', 'R').
+ *
+ * In 1.7.0 the definitions will be made public in png.h to avoid having to
+ * duplicate the same definitions in application code.
+ */
+#define png_IDAT PNG_U32( 73, 68, 65, 84)
+#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_bKGD PNG_U32( 98, 75, 71, 68)
+#define png_cHRM PNG_U32( 99, 72, 82, 77)
+#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */
+#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)
+#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */
+#define png_gIFx PNG_U32(103, 73, 70, 120)
+#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_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)
+#define png_sBIT PNG_U32(115, 66, 73, 84)
+#define png_sCAL PNG_U32(115, 67, 65, 76)
+#define png_sPLT PNG_U32(115, 80, 76, 84)
+#define png_sRGB PNG_U32(115, 82, 71, 66)
+#define png_sTER PNG_U32(115, 84, 69, 82)
+#define png_tEXt PNG_U32(116, 69, 88, 116)
+#define png_tIME PNG_U32(116, 73, 77, 69)
+#define png_tRNS PNG_U32(116, 82, 78, 83)
+#define png_zTXt PNG_U32(122, 84, 88, 116)
+
+/* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+#define PNG_CHUNK_FROM_STRING(s)\
+ PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3])
+
+/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is
+ * signed and the argument is a (char[]) This macro will fail miserably on
+ * systems where (char) is more than 8 bits.
+ */
+#define PNG_STRING_FROM_CHUNK(s,c)\
+ (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \
+ ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\
+ ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \
+ ((char*)(s))[3]=(char)((c & 0xff)))
+
+/* Do the same but terminate with a null character. */
+#define PNG_CSTRING_FROM_CHUNK(s,c)\
+ (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0)
+
+/* Test on flag values as defined in the spec (section 5.4): */
+#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29))
+#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c))
+#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21))
+#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13))
+#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5))
+
+/* 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
+
+/* 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.
+ */
+#ifndef PNG_VERSION_INFO_ONLY
+
+#include "pngstruct.h"
+#include "pnginfo.h"
+
+/* Validate the include paths - the include path used to generate pnglibconf.h
+ * 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.
+ *
+ * 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.
+ */
+#endif
+
+/* This is used for 16-bit gamma tables -- only the top level pointers are
+ * const; this could be changed:
+ */
+typedef const png_uint_16p * png_const_uint_16pp;
+
+/* Added to libpng-1.5.7: sRGB conversion tables */
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]);
+ /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value,
+ * 0..65535. This table gives the closest 16-bit answers (no errors).
+ */
+#endif
+
+PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]);
+PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]);
+
+#define PNG_sRGB_FROM_LINEAR(linear) \
+ ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \
+ + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)))
+ /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB
+ * encoded value with maximum error 0.646365. Note that the input is not a
+ * 16-bit value; it has been multiplied by 255! */
+#endif /* SIMPLIFIED_READ/WRITE */
+
+
+/* Inhibit C++ name-mangling for libpng functions but not for system calls. */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Internal functions; these are not exported from a DLL however because they
+ * are used within several of the C source files they have to be C extern.
+ *
+ * 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),
+ PNG_EMPTY);
+ /* Used by the zlib handling functions to ensure that z_stream::msg is always
+ * set before they return.
+ */
+
+#ifdef PNG_WRITE_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
+ png_compression_bufferp *list),PNG_EMPTY);
+ /* Free the buffer list used by the compressed write code. */
+#endif
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
+ !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_READ_RGB_TO_GRAY_SUPPORTED)) || \
+ (defined(PNG_sCAL_SUPPORTED) && \
+ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
+PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(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);
+
+/* 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.)
+ */
+PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr,
+ png_alloc_size_t size),PNG_ALLOCATED);
+
+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\
+ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)
+/* Internal array allocator, outputs no error or warning messages on failure,
+ * just returns NULL.
+ */
+PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr,
+ int nelements, size_t element_size),PNG_ALLOCATED);
+
+/* The same but an existing array is extended by add_elements. This function
+ * also memsets the new elements to 0 and copies the old elements. The old
+ * array is not freed or altered.
+ */
+PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr,
+ png_const_voidp array, int old_elements, int add_elements,
+ size_t element_size),PNG_ALLOCATED);
+#endif /* text, sPLT or unknown chunks */
+
+/* Magic to create a struct when there is no struct to call the user supplied
+ * memory allocators. Because error handling has not been set up the memory
+ * handlers can't safely call png_error, but this is an obscure and undocumented
+ * restriction so libpng has to assume that the 'free' handler, at least, might
+ * call png_error.
+ */
+PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct,
+ (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn,
+ png_free_ptr free_fn),PNG_ALLOCATED);
+
+/* Free memory from internal libpng struct */
+PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr),
+ PNG_EMPTY);
+
+/* Free an allocated jmp_buf (always succeeds) */
+PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY);
+
+/* Function to allocate memory for zlib. PNGAPI is disallowed. */
+PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size),
+ PNG_ALLOCATED);
+
+/* Function to free memory for zlib. PNGAPI is disallowed. */
+PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);
+
+/* Next four functions are used internally as callbacks. PNGCBAPI is required
+ * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to
+ * PNGCBAPI at 1.5.0
+ */
+
+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,
+ png_bytep data, size_t length),PNG_EMPTY);
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,
+ png_bytep buffer, size_t length),PNG_EMPTY);
+#endif
+
+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr,
+ png_bytep data, size_t length),PNG_EMPTY);
+
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+# ifdef PNG_STDIO_SUPPORTED
+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr),
+ PNG_EMPTY);
+# endif
+#endif
+
+/* Reset the CRC variable */
+PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY);
+
+/* Write the "data" buffer to whatever output you are using */
+PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr,
+ png_const_bytep data, size_t length),PNG_EMPTY);
+
+/* Read and check the PNG file signature */
+PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr,
+ png_inforp info_ptr),PNG_EMPTY);
+
+/* Read the chunk header (length + type name) */
+PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr),
+ PNG_EMPTY);
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data,
+ size_t length),PNG_EMPTY);
+
+/* Read bytes into buf, and update png_ptr->crc */
+PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,
+ png_uint_32 length),PNG_EMPTY);
+
+/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
+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.
+ */
+PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,
+ png_const_bytep ptr, size_t length),PNG_EMPTY);
+
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);
+#endif
+
+/* Write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information.
+ */
+PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,
+ int compression_method, int filter_method, int interlace_method),PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr,
+ png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr,
+ png_const_bytep row_data, png_alloc_size_t row_data_length, int flush),
+ PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY);
+
+#ifdef PNG_WRITE_gAMA_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr,
+ png_fixed_point file_gamma),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_sBIT_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr,
+ png_const_color_8p sbit, int color_type),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_cHRM_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,
+ const png_xy *xy), PNG_EMPTY);
+ /* The xy value must have been previously validated */
+#endif
+
+#ifdef PNG_WRITE_sRGB_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
+ int intent),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,
+ png_bytep exif, int num_exif),PNG_EMPTY);
+#endif
+
+#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.
+ */
+#endif
+
+#ifdef PNG_WRITE_sPLT_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr,
+ png_const_sPLT_tp palette),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr,
+ png_const_bytep trans, png_const_color_16p values, int number,
+ int color_type),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_bKGD_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr,
+ png_const_color_16p values, int color_type),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_hIST_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr,
+ png_const_uint_16p hist, int num_hist),PNG_EMPTY);
+#endif
+
+/* Chunks that have keywords */
+#ifdef PNG_WRITE_tEXt_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr,
+ png_const_charp key, png_const_charp text, size_t text_len),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_zTXt_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp
+ key, png_const_charp text, int compression),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_iTXt_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr,
+ int compression, png_const_charp key, png_const_charp lang,
+ png_const_charp lang_key, png_const_charp text),PNG_EMPTY);
+#endif
+
+#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */
+PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_oFFs_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr,
+ png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_pCAL_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr,
+ png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_const_charp units, png_charpp params),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_pHYs_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr,
+ png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
+ int unit_type),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_tIME_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr,
+ png_const_timep mod_time),PNG_EMPTY);
+#endif
+
+#ifdef PNG_WRITE_sCAL_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,
+ int unit, png_const_charp width, png_const_charp height),PNG_EMPTY);
+#endif
+
+/* Called when finished processing a row of data */
+PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr),
+ PNG_EMPTY);
+
+/* Internal use only. Called before first row of data */
+PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr),
+ PNG_EMPTY);
+
+/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an
+ * array of png_ptr->width pixels. If the image is not interlaced or this
+ * is the final pass this just does a memcpy, otherwise the "display" flag
+ * is used to determine whether to copy pixels that are not in the current pass.
+ *
+ * Because 'png_do_read_interlace' (below) replicates pixels this allows this
+ * function to achieve the documented 'blocky' appearance during interlaced read
+ * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row'
+ * are not changed if they are not in the current pass, when display is 0.
+ *
+ * 'display' must be 0 or 1, otherwise the memcpy will be done regardless.
+ *
+ * The API always reads from the png_struct row buffer and always assumes that
+ * it is full width (png_do_read_interlace has already been called.)
+ *
+ * This function is only ever used to write to row buffers provided by the
+ * caller of the relevant libpng API and the row must have already been
+ * transformed by the read transformations.
+ *
+ * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed
+ * bitmasks for use within the code, otherwise runtime generated masks are used.
+ * The default is compile time masks.
+ */
+#ifndef PNG_USE_COMPILE_TIME_MASKS
+# define PNG_USE_COMPILE_TIME_MASKS 1
+#endif
+PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr,
+ png_bytep row, int display),PNG_EMPTY);
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+/* Expand an interlaced row: the 'row_info' describes the pass data that has
+ * been read in and must correspond to the pixels in 'row', the pixels are
+ * expanded (moved apart) in 'row' to match the final layout, when doing this
+ * the pixels are *replicated* to the intervening space. This is essential for
+ * the correct operation of png_combine_row, above.
+ */
+PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info,
+ png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY);
+#endif
+
+/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+/* Grab pixels out of a row for an interlaced pass */
+PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info,
+ png_bytep row, int pass),PNG_EMPTY);
+#endif
+
+/* Unfilter a row: check the filter value before calling this, there is no point
+ * calling it for PNG_FILTER_VALUE_NONE.
+ */
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY);
+
+#if PNG_ARM_NEON_OPT > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info,
+ png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info,
+ png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
+#if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_mmi,(png_row_infop row_info,
+ png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
+#if PNG_POWERPC_VSX_OPT > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info,
+ png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_vsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
+#if PNG_INTEL_SSE_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
+#if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+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
+
+/* 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);
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr,
+ png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY);
+ /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer
+ * is NULL the function checks, instead, for the end of the stream. In this
+ * case a benign error will be issued if the stream end is not found or if
+ * extra data has to be consumed.
+ */
+PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr),
+ PNG_EMPTY);
+ /* This cleans up when the IDAT LZ stream does not end when the last image
+ * byte is read; there is still some pending input.
+ */
+
+PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),
+ PNG_EMPTY);
+ /* Finish a row while reading, dealing with interlacing passes, etc. */
+#endif /* SEQUENTIAL_READ */
+
+/* Initialize the row buffers, etc. */
+PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);
+
+#if ZLIB_VERNUM >= 0x1240
+PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),
+ PNG_EMPTY);
+# define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush)
+#else /* Zlib < 1.2.4 */
+# define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush)
+#endif /* Zlib < 1.2.4 */
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+/* Optional call to update the users info structure */
+PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,
+ png_inforp info_ptr),PNG_EMPTY);
+#endif
+
+/* Shared transform functions, defined in pngtran.c */
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info,
+ png_bytep row, int at_start),PNG_EMPTY);
+#endif
+
+#ifdef PNG_16BIT_SUPPORTED
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info,
+ png_bytep row),PNG_EMPTY);
+#endif
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
+ defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info,
+ png_bytep row),PNG_EMPTY);
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info,
+ png_bytep row),PNG_EMPTY);
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,
+ png_bytep row),PNG_EMPTY);
+#endif
+
+/* 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);
+ /* 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.
+ */
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
+ defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
+PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
+ (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY);
+ /* Exactly as the API png_handle_as_unknown() except that the argument is a
+ * 32-bit chunk name, not a string.
+ */
+#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */
+
+/* Handle the transformations for reading and writing */
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr,
+ png_row_infop row_info),PNG_EMPTY);
+#endif
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr,
+ png_row_infop row_info),PNG_EMPTY);
+#endif
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr),
+ PNG_EMPTY);
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr,
+ png_inforp info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr,
+ png_inforp info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr),
+ PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr,
+ png_bytep buffer, size_t buffer_length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY);
+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,
+ png_inforp info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr,
+ png_bytep row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr,
+ png_inforp info_ptr),PNG_EMPTY);
+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);
+#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_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_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 */
+#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,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type),PNG_EMPTY);
+
+/* Added at libpng version 1.5.10 */
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes,
+ (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY);
+#endif
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
+PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr,
+ png_const_charp name),PNG_NORETURN);
+#endif
+
+/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite
+ * the end. Always leaves the buffer nul terminated. Never errors out (and
+ * there is no error code.)
+ */
+PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize,
+ size_t pos, png_const_charp string),PNG_EMPTY);
+
+/* Various internal functions to handle formatted warning messages, currently
+ * only implemented for warnings.
+ */
+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Utility to dump an unsigned value into a buffer, given a start pointer and
+ * and end pointer (which should point just *beyond* the end of the buffer!)
+ * Returns the pointer to the start of the formatted string. This utility only
+ * does unsigned values.
+ */
+PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start,
+ png_charp end, int format, png_alloc_size_t number),PNG_EMPTY);
+
+/* Convenience macro that takes an array: */
+#define PNG_FORMAT_NUMBER(buffer,format,number) \
+ png_format_number(buffer, buffer + (sizeof buffer), format, number)
+
+/* Suggested size for a number buffer (enough for 64 bits and a sign!) */
+#define PNG_NUMBER_BUFFER_SIZE 24
+
+/* These are the integer formats currently supported, the name is formed from
+ * the standard printf(3) format string.
+ */
+#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */
+#define PNG_NUMBER_FORMAT_02u 2
+#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */
+#define PNG_NUMBER_FORMAT_02d 2
+#define PNG_NUMBER_FORMAT_x 3
+#define PNG_NUMBER_FORMAT_02x 4
+#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */
+#endif
+
+#ifdef PNG_WARNINGS_SUPPORTED
+/* New defines and members adding in libpng-1.5.4 */
+# define PNG_WARNING_PARAMETER_SIZE 32
+# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */
+
+/* An l-value of this type has to be passed to the APIs below to cache the
+ * values of the parameters to a formatted warning message.
+ */
+typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][
+ PNG_WARNING_PARAMETER_SIZE];
+
+PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p,
+ int number, png_const_charp string),PNG_EMPTY);
+ /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters,
+ * including the trailing '\0'.
+ */
+PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned,
+ (png_warning_parameters p, int number, int format, png_alloc_size_t value),
+ PNG_EMPTY);
+ /* Use png_alloc_size_t because it is an unsigned type as big as any we
+ * need to output. Use the following for a signed value.
+ */
+PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed,
+ (png_warning_parameters p, int number, int format, png_int_32 value),
+ PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr,
+ png_warning_parameters p, png_const_charp message),PNG_EMPTY);
+ /* 'message' follows the X/Open approach of using @1, @2 to insert
+ * parameters previously supplied using the above functions. Errors in
+ * specifying the parameters will simply result in garbage substitutions.
+ */
+#endif
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+/* Application errors (new in 1.6); use these functions (declared below) for
+ * errors in the parameters or order of API function calls on read. The
+ * 'warning' should be used for an error that can be handled completely; the
+ * 'error' for one which can be handled safely but which may lose application
+ * information or settings.
+ *
+ * By default these both result in a png_error call prior to release, while in a
+ * released version the 'warning' is just a warning. However if the application
+ * explicitly disables benign errors (explicitly permitting the code to lose
+ * information) they both turn into warnings.
+ *
+ * If benign errors aren't supported they end up as the corresponding base call
+ * (png_warning or png_error.)
+ */
+PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr,
+ png_const_charp message),PNG_EMPTY);
+ /* The application provided invalid parameters to an API function or called
+ * an API function at the wrong time, libpng can completely recover.
+ */
+
+PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,
+ png_const_charp message),PNG_EMPTY);
+ /* As above but libpng will ignore the call, or attempt some other partial
+ * recovery from the error.
+ */
+#else
+# define png_app_warning(pp,s) png_warning(pp,s)
+# define png_app_error(pp,s) png_error(pp,s)
+#endif
+
+PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,
+ png_const_charp message, int error),PNG_EMPTY);
+ /* Report a recoverable issue in chunk data. On read this is used to report
+ * a problem found while reading a particular chunk and the
+ * png_chunk_benign_error or png_chunk_warning function is used as
+ * appropriate. On write this is used to report an error that comes from
+ * data set via an application call to a png_set_ API and png_app_error or
+ * png_app_warning is used as appropriate.
+ *
+ * The 'error' parameter must have one of the following values:
+ */
+#define PNG_CHUNK_WARNING 0 /* never an error */
+#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */
+#define PNG_CHUNK_ERROR 2 /* always an error */
+
+/* ASCII to FP interfaces, currently only implemented if sCAL
+ * support is required.
+ */
+#if defined(PNG_sCAL_SUPPORTED)
+/* MAX_DIGITS is actually the maximum number of characters in an sCAL
+ * width or height, derived from the precision (number of significant
+ * digits - a build time settable option) and assumptions about the
+ * maximum ridiculous exponent.
+ */
+#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr,
+ png_charp ascii, size_t size, double fp, unsigned int precision),
+ PNG_EMPTY);
+#endif /* FLOATING_POINT */
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
+ png_charp ascii, size_t size, png_fixed_point fp),PNG_EMPTY);
+#endif /* FIXED_POINT */
+#endif /* sCAL */
+
+#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
+/* An internal API to validate the format of a floating point number.
+ * The result is the index of the next character. If the number is
+ * not valid it will be the index of a character in the supposed number.
+ *
+ * The format of a number is defined in the PNG extensions specification
+ * and this API is strictly conformant to that spec, not anyone elses!
+ *
+ * The format as a regular expression is:
+ *
+ * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)?
+ *
+ * or:
+ *
+ * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)?
+ *
+ * The complexity is that either integer or fraction must be present and the
+ * fraction is permitted to have no digits only if the integer is present.
+ *
+ * NOTE: The dangling E problem.
+ * There is a PNG valid floating point number in the following:
+ *
+ * PNG floating point numbers are not greedy.
+ *
+ * Working this out requires *TWO* character lookahead (because of the
+ * sign), the parser does not do this - it will fail at the 'r' - this
+ * doesn't matter for PNG sCAL chunk values, but it requires more care
+ * if the value were ever to be embedded in something more complex. Use
+ * ANSI-C strtod if you need the lookahead.
+ */
+/* State table for the parser. */
+#define PNG_FP_INTEGER 0 /* before or in integer */
+#define PNG_FP_FRACTION 1 /* before or in fraction */
+#define PNG_FP_EXPONENT 2 /* before or in exponent */
+#define PNG_FP_STATE 3 /* mask for the above */
+#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */
+#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */
+#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */
+#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */
+#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */
+
+/* These three values don't affect the parser. They are set but not used.
+ */
+#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */
+#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */
+#define PNG_FP_NONZERO 256 /* A non-zero value */
+#define PNG_FP_STICKY 448 /* The above three flags */
+
+/* This is available for the caller to store in 'state' if required. Do not
+ * call the parser after setting it (the parser sometimes clears it.)
+ */
+#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */
+
+/* Result codes for the parser (boolean - true means ok, false means
+ * not ok yet.)
+ */
+#define PNG_FP_MAYBE 0 /* The number may be valid in the future */
+#define PNG_FP_OK 1 /* The number is valid */
+
+/* Tests on the sticky non-zero and negative flags. To pass these checks
+ * the state must also indicate that the whole number is valid - this is
+ * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this
+ * is equivalent to PNG_FP_OK above.)
+ */
+#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO)
+ /* NZ_MASK: the string is valid and a non-zero negative value */
+#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO)
+ /* Z MASK: the string is valid and a non-zero value. */
+ /* PNG_FP_SAW_DIGIT: the string is valid. */
+#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)
+#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)
+#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)
+
+/* The actual parser. This can be called repeatedly. It updates
+ * the index into the string and the state variable (which must
+ * be initialized to 0). It returns a result code, as above. There
+ * is no point calling the parser any more if it fails to advance to
+ * the end of the string - it is stuck on an invalid character (or
+ * terminated by '\0').
+ *
+ * Note that the pointer will consume an E or even an E+ and then leave
+ * a 'maybe' state even though a preceding integer.fraction is valid.
+ * The PNG_FP_WAS_VALID flag indicates that a preceding substring was
+ * a valid number. It's possible to recover from this by calling
+ * the parser again (from the start, with state 0) but with a string
+ * that omits the last character (i.e. set the size to the index of
+ * the problem character.) This has not been tested within libpng.
+ */
+PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,
+ size_t size, int *statep, size_t *whereami),PNG_EMPTY);
+
+/* This is the same but it checks a complete string and returns true
+ * only if it just contains a floating point number. As of 1.5.4 this
+ * function also returns the state at the end of parsing the number if
+ * it was valid (otherwise it returns 0.) This can be used for testing
+ * for negative or zero values using the sticky flag.
+ */
+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)
+/* 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)
+ * for overflow, true (1) if no overflow, in which case *res
+ * holds the result.
+ */
+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);
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+/* The same but gives a reciprocal of the product of two fixed point
+ * values. Accuracy is suitable for gamma calculations but this is
+ * not exact - use png_muldiv for that. Only required at present on read.
+ */
+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
+/* 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.
+ *
+ * While the input is an 'unsigned' value it must actually be the
+ * correct bit value - 0..255 or 0..65535 as required.
+ */
+PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr,
+ unsigned int value, png_fixed_point gamma_value),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value,
+ png_fixed_point gamma_value),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value,
+ png_fixed_point gamma_value),PNG_EMPTY);
+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
+
+/* SIMPLIFIED READ/WRITE SUPPORT */
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+/* The internal structure that png_image::opaque points to. */
+typedef struct png_control
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_voidp error_buf; /* Always a jmp_buf at present. */
+
+ png_const_bytep memory; /* Memory buffer. */
+ size_t size; /* Size of the memory buffer. */
+
+ unsigned int for_write :1; /* Otherwise it is a read structure */
+ unsigned int owned_file :1; /* We own the file in io_ptr */
+} png_control;
+
+/* Return the pointer to the jmp_buf from a png_control: necessary because C
+ * does not reveal the type of the elements of jmp_buf.
+ */
+#ifdef __cplusplus
+# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0])
+#else
+# define png_control_jmp_buf(pc) ((pc)->error_buf)
+#endif
+
+/* Utility to safely execute a piece of libpng code catching and logging any
+ * errors that might occur. Returns true on success, false on failure (either
+ * of the function or as a result of a png_error.)
+ */
+PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr,
+ png_const_charp error_message),PNG_NORETURN);
+
+#ifdef PNG_WARNINGS_SUPPORTED
+PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr,
+ png_const_charp warning_message),PNG_EMPTY);
+#else
+# define png_safe_warning 0/*dummy argument*/
+#endif
+
+PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image,
+ int (*function)(png_voidp), png_voidp arg),PNG_EMPTY);
+
+/* Utility to log an error; this also cleans up the png_image; the function
+ * always returns 0 (false).
+ */
+PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image,
+ png_const_charp error_message),PNG_EMPTY);
+
+#ifndef PNG_SIMPLIFIED_READ_SUPPORTED
+/* png_image_free is used by the write code but not exported */
+PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY);
+#endif /* !SIMPLIFIED_READ */
+
+#endif /* SIMPLIFIED READ/WRITE */
+
+/* These are initialization functions for hardware specific PNG filter
+ * optimizations; list these here then select the appropriate one at compile
+ * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined
+ * the generic code is used.
+ */
+#ifdef PNG_FILTER_OPTIMIZATIONS
+PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr,
+ unsigned int bpp), PNG_EMPTY);
+ /* Just declare the optimization that will be used */
+#else
+ /* List *all* the possible optimizations here - this branch is required if
+ * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in
+ * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing.
+ */
+# if PNG_ARM_NEON_OPT > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
+# if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+# endif
+
+# if PNG_INTEL_SSE_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+# endif
+#endif
+
+#if PNG_LOONGARCH_LSX_OPT > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
+ (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);
+
+#if PNG_ARM_NEON_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,
+ png_riffle_palette_neon,
+ (png_structrp),
+ PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int,
+ png_do_expand_palette_rgba8_neon,
+ (png_structrp,
+ png_row_infop,
+ png_const_bytep,
+ const png_bytepp,
+ const png_bytepp),
+ PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int,
+ png_do_expand_palette_rgb8_neon,
+ (png_structrp,
+ png_row_infop,
+ png_const_bytep,
+ const png_bytepp,
+ const png_bytepp),
+ PNG_EMPTY);
+#endif
+
+/* Maintainer: Put new private prototypes here ^ */
+
+#include "pngdebug.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PNG_VERSION_INFO_ONLY */
+#endif /* PNGPRIV_H */
diff --git a/PDF/include/Poco/PDF/pngstruct.h b/PDF/include/Poco/PDF/pngstruct.h
new file mode 100644
index 000000000..e591d94d5
--- /dev/null
+++ b/PDF/include/Poco/PDF/pngstruct.h
@@ -0,0 +1,479 @@
+
+/* pngstruct.h - header file for PNG reference library
+ *
+ * Copyright (c) 2018-2022 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * 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 PNGSTRUCT_H
+#define PNGSTRUCT_H
+/* zlib.h defines the structure z_stream, an instance of which is included
+ * in this structure and is required for decompressing the LZ compressed
+ * data in PNG files.
+ */
+#ifndef ZLIB_CONST
+ /* We must ensure that zlib uses 'const' in declarations. */
+# define ZLIB_CONST
+#endif
+#include "zlib.h"
+#ifdef const
+ /* zlib.h sometimes #defines const to nothing, undo this. */
+# undef const
+#endif
+
+/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility
+ * with older builds.
+ */
+#if ZLIB_VERNUM < 0x1260
+# define PNGZ_MSG_CAST(s) png_constcast(char*,s)
+# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)
+#else
+# define PNGZ_MSG_CAST(s) (s)
+# define PNGZ_INPUT_CAST(b) (b)
+#endif
+
+/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib
+ * can handle at once. This type need be no larger than 16 bits (so maximum of
+ * 65535), this define allows us to discover how big it is, but limited by the
+ * maximum for size_t. The value can be overridden in a library build
+ * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably
+ * lower value (e.g. 255 works). A lower value may help memory usage (slightly)
+ * and may even improve performance on some systems (and degrade it on others.)
+ */
+#ifndef ZLIB_IO_MAX
+# define ZLIB_IO_MAX ((uInt)-1)
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+/* The type of a compression buffer list used by the write code. */
+typedef struct png_compression_buffer
+{
+ struct png_compression_buffer *next;
+ png_byte output[1]; /* actually zbuf_size */
+} png_compression_buffer, *png_compression_bufferp;
+
+#define PNG_COMPRESSION_BUFFER_SIZE(pp)\
+ (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size)
+#endif
+
+/* 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)).
+ */
+typedef struct png_xy
+{
+ png_fixed_point redx, redy;
+ png_fixed_point greenx, greeny;
+ png_fixed_point bluex, bluey;
+ png_fixed_point whitex, whitey;
+} png_xy;
+
+/* The same data as above but encoded as CIE XYZ values. When this data comes
+ * from chromaticities the sum of the Y values is assumed to be 1.0
+ */
+typedef struct png_XYZ
+{
+ png_fixed_point red_X, red_Y, red_Z;
+ 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.
+ */
+typedef struct png_colorspace
+{
+#ifdef PNG_GAMMA_SUPPORTED
+ png_fixed_point gamma; /* File gamma */
+#endif
+
+#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;
+
+typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
+
+/* General flags for the 'flags' field */
+#define PNG_COLORSPACE_HAVE_GAMMA 0x0001
+#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002
+#define PNG_COLORSPACE_HAVE_INTENT 0x0004
+#define PNG_COLORSPACE_FROM_gAMA 0x0008
+#define PNG_COLORSPACE_FROM_cHRM 0x0010
+#define PNG_COLORSPACE_FROM_sRGB 0x0020
+#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040
+#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */
+#define PNG_COLORSPACE_INVALID 0x8000
+#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags))
+#endif /* COLORSPACE || GAMMA */
+
+struct png_struct_def
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */
+ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */
+ jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */
+ size_t jmp_buf_size; /* size of the above, if allocated */
+#endif
+ png_error_ptr error_fn; /* function for printing errors and aborting */
+#ifdef PNG_WARNINGS_SUPPORTED
+ png_error_ptr warning_fn; /* function for printing warnings */
+#endif
+ png_voidp error_ptr; /* user supplied struct for error functions */
+ png_rw_ptr write_data_fn; /* function for writing output data */
+ png_rw_ptr read_data_fn; /* function for reading input data */
+ png_voidp io_ptr; /* ptr to application struct for I/O functions */
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+ png_user_transform_ptr read_user_transform_fn; /* user read transform */
+#endif
+
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+ png_user_transform_ptr write_user_transform_fn; /* user write transform */
+#endif
+
+/* These were added in libpng-1.0.2 */
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_voidp user_transform_ptr; /* user supplied struct for user transform */
+ png_byte user_transform_depth; /* bit depth of user transformed pixels */
+ png_byte user_transform_channels; /* channels in user transformed pixels */
+#endif
+#endif
+
+ png_uint_32 mode; /* tells us where we are in the PNG file */
+ png_uint_32 flags; /* flags indicating various things to libpng */
+ png_uint_32 transformations; /* which transformations to perform */
+
+ png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
+ z_stream zstream; /* decompression structure */
+
+#ifdef PNG_WRITE_SUPPORTED
+ png_compression_bufferp zbuffer_list; /* Created on demand during write */
+ uInt zbuffer_size; /* size of the actual buffer */
+
+ int zlib_level; /* holds zlib compression level */
+ int zlib_method; /* holds zlib compression method */
+ int zlib_window_bits; /* holds zlib compression window bits */
+ int zlib_mem_level; /* holds zlib compression memory level */
+ int zlib_strategy; /* holds zlib compression strategy */
+#endif
+/* Added at libpng 1.5.4 */
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+ int zlib_text_level; /* holds zlib compression level */
+ int zlib_text_method; /* holds zlib compression method */
+ int zlib_text_window_bits; /* holds zlib compression window bits */
+ int zlib_text_mem_level; /* holds zlib compression memory level */
+ int zlib_text_strategy; /* holds zlib compression strategy */
+#endif
+/* End of material added at libpng 1.5.4 */
+/* Added at libpng 1.6.0 */
+#ifdef PNG_WRITE_SUPPORTED
+ int zlib_set_level; /* Actual values set into the zstream on write */
+ int zlib_set_method;
+ int zlib_set_window_bits;
+ int zlib_set_mem_level;
+ int zlib_set_strategy;
+#endif
+
+ 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 */
+ png_uint_32 usr_width; /* width of row at start of write */
+ size_t rowbytes; /* size of row in bytes */
+ png_uint_32 iwidth; /* width of current interlaced row in pixels */
+ png_uint_32 row_number; /* current row in interlace pass */
+ png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */
+ png_bytep prev_row; /* buffer to save previous (unfiltered) row.
+ * While reading this is a pointer into
+ * big_prev_row; while writing it is separately
+ * allocated if needed.
+ */
+ png_bytep row_buf; /* buffer to save current (unfiltered) row.
+ * While reading, this is a pointer into
+ * big_row_buf; while writing it is separately
+ * allocated.
+ */
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ png_bytep try_row; /* buffer to save trial row when filtering */
+ png_bytep tst_row; /* buffer to save best trial row when filtering */
+#endif
+ size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */
+
+ png_uint_32 idat_size; /* current IDAT size for read */
+ png_uint_32 crc; /* current chunk CRC value */
+ png_colorp palette; /* palette from the input file */
+ png_uint_16 num_palette; /* number of color entries in palette */
+
+/* Added at libpng-1.5.10 */
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ int num_palette_max; /* maximum palette index found in IDAT */
+#endif
+
+ png_uint_16 num_trans; /* number of transparency values */
+ png_byte compression; /* file compression type (always 0) */
+ png_byte filter; /* file filter type (always 0) */
+ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+ png_byte pass; /* current interlace pass (0 - 6) */
+ png_byte do_filter; /* row filter flags (see PNG_FILTER_ in png.h ) */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte usr_bit_depth; /* bit depth of users row: write only */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte channels; /* number of channels in file */
+#ifdef PNG_WRITE_SUPPORTED
+ png_byte usr_channels; /* channels at start of write: write only */
+#endif
+ png_byte sig_bytes; /* magic bytes read/written from start of file */
+ png_byte maximum_pixel_depth;
+ /* pixel depth used for the row buffers */
+ png_byte transformed_pixel_depth;
+ /* pixel depth after read/write transforms */
+#if ZLIB_VERNUM >= 0x1240
+ png_byte zstream_start; /* at start of an input zlib stream */
+#endif /* Zlib >= 1.2.4 */
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+ png_uint_16 filler; /* filler bytes for pixel expansion */
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+ png_byte background_gamma_type;
+ png_fixed_point background_gamma;
+ png_color_16 background; /* background color in screen gamma space */
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+#endif
+#endif /* bKGD */
+
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+ png_flush_ptr output_flush_fn; /* Function for flushing output */
+ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
+ png_uint_32 flush_rows; /* number of rows written since last flush */
+#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_bytep gamma_table; /* gamma table for 8-bit depth files */
+ png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ png_bytep gamma_from_1; /* converts from 1.0 to screen */
+ png_bytep gamma_to_1; /* converts from file to 1.0 */
+ 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
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
+ png_color_8 sig_bit; /* significant bits in each available channel */
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+ png_color_8 shift; /* shift for significant bit transformation */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
+ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep trans_alpha; /* alpha values for paletted files */
+ png_color_16 trans_color; /* transparent color for non-paletted files */
+#endif
+
+ png_read_status_ptr read_row_fn; /* called after each row is decoded */
+ png_write_status_ptr write_row_fn; /* called after each row is encoded */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_info_ptr info_fn; /* called after header data fully read */
+ png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */
+ png_progressive_end_ptr end_fn; /* called after image is complete */
+ png_bytep save_buffer_ptr; /* current location in save_buffer */
+ png_bytep save_buffer; /* buffer for previously read data */
+ png_bytep current_buffer_ptr; /* current location in current_buffer */
+ png_bytep current_buffer; /* buffer for recently used data */
+ png_uint_32 push_length; /* size of current input chunk */
+ png_uint_32 skip_length; /* bytes to skip in input data */
+ size_t save_buffer_size; /* amount of data now in save_buffer */
+ size_t save_buffer_max; /* total size of save_buffer */
+ size_t buffer_size; /* total amount of available input data */
+ size_t current_buffer_size; /* amount of data now in current_buffer */
+ int process_mode; /* what push library is currently doing */
+ int cur_palette; /* current push library palette index */
+#endif /* PROGRESSIVE_READ */
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+ png_bytep palette_lookup; /* lookup table for quantizing */
+ png_bytep quantize_index; /* index translation for palette files */
+#endif
+
+/* Options */
+#ifdef PNG_SET_OPTION_SUPPORTED
+ png_uint_32 options; /* On/off state (up to 16 options) */
+#endif
+
+#if PNG_LIBPNG_VER < 10700
+/* 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
+
+/* New members added in libpng-1.0.6 */
+
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+ 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
+
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ int unknown_default; /* As PNG_HANDLE_* */
+ unsigned int num_chunk_list; /* Number of entries in the list */
+ png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name
+ * followed by a PNG_HANDLE_* byte */
+#endif
+
+/* New members added in libpng-1.0.3 */
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ png_byte rgb_to_gray_status;
+ /* Added in libpng 1.5.5 to record setting of coefficients: */
+ png_byte rgb_to_gray_coefficients_set;
+ /* These were changed from png_byte in libpng-1.0.6 */
+ png_uint_16 rgb_to_gray_red_coeff;
+ png_uint_16 rgb_to_gray_green_coeff;
+ /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */
+#endif
+
+/* New member added in libpng-1.6.36 */
+#if defined(PNG_READ_EXPAND_SUPPORTED) && \
+ defined(PNG_ARM_NEON_IMPLEMENTATION)
+ png_bytep riffled_palette; /* buffer for accelerated palette expansion */
+#endif
+
+/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+/* Changed from png_byte to png_uint_32 at version 1.2.0 */
+ png_uint_32 mng_features_permitted;
+#endif
+
+/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ png_byte filter_type;
+#endif
+
+/* New members added in libpng-1.2.0 */
+
+/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_voidp mem_ptr; /* user supplied struct for mem functions */
+ png_malloc_ptr malloc_fn; /* function for allocating memory */
+ png_free_ptr free_fn; /* function for freeing memory */
+#endif
+
+/* New member added in libpng-1.0.13 and 1.2.0 */
+ png_bytep big_row_buf; /* buffer to save current (unfiltered) row */
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+/* The following three members were added at version 1.0.14 and 1.2.4 */
+ png_bytep quantize_sort; /* working sort array */
+ png_bytep index_to_palette; /* where the original index currently is
+ in the palette */
+ png_bytep palette_to_index; /* which original index points to this
+ palette color */
+#endif
+
+/* New members added in libpng-1.0.16 and 1.2.6 */
+ png_byte compression_type;
+
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ png_uint_32 user_width_max;
+ png_uint_32 user_height_max;
+
+ /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown
+ * chunks that can be stored (0 means unlimited).
+ */
+ png_uint_32 user_chunk_cache_max;
+
+ /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk
+ * can occupy when decompressed. 0 means unlimited.
+ */
+ png_alloc_size_t user_chunk_malloc_max;
+#endif
+
+/* New member added in libpng-1.0.25 and 1.2.17 */
+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* Temporary storage for unknown chunk that the library doesn't recognize,
+ * used while reading the chunk.
+ */
+ png_unknown_chunk unknown_chunk;
+#endif
+
+/* New member added in libpng-1.2.26 */
+ size_t old_big_row_buf_size;
+
+#ifdef PNG_READ_SUPPORTED
+/* New member added in libpng-1.2.30 */
+ png_bytep read_buffer; /* buffer for reading chunk data */
+ png_alloc_size_t read_buffer_size; /* current size of the buffer */
+#endif
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+ uInt IDAT_read_size; /* limit on read buffer size for IDAT */
+#endif
+
+#ifdef PNG_IO_STATE_SUPPORTED
+/* New member added in libpng-1.4.0 */
+ png_uint_32 io_state;
+#endif
+
+/* New member added in libpng-1.5.6 */
+ png_bytep big_prev_row;
+
+/* 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 a/PDF/src/png.c b/PDF/src/png.c
index 4d25559cf..9ed315700 100644
--- a/PDF/src/png.c
+++ b/PDF/src/png.c
@@ -1,86 +1,20 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.2.21 October 4, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-#define PNG_INTERNAL
-#define PNG_NO_EXTERN
-#include "png.h"
+#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef version_1_2_24 Your_png_h_is_not_version_1_2_24;
-
-/* Version information for C files. This had better match the version
- * string defined in png.h. */
-
-#ifdef PNG_USE_GLOBAL_ARRAYS
-/* png_libpng_ver was changed to a function in version 1.0.5c */
-PNG_CONST char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING;
-
-#ifdef PNG_READ_SUPPORTED
-
-/* png_sig was changed to a function in version 1.0.5c */
-/* Place to hold the signature string for a PNG file. */
-PNG_CONST png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
-#endif /* PNG_READ_SUPPORTED */
-
-/* Invoke global declarations for constant strings for known chunk types */
-PNG_IHDR;
-PNG_IDAT;
-PNG_IEND;
-PNG_PLTE;
-PNG_bKGD;
-PNG_cHRM;
-PNG_gAMA;
-PNG_hIST;
-PNG_iCCP;
-PNG_iTXt;
-PNG_oFFs;
-PNG_pCAL;
-PNG_sCAL;
-PNG_pHYs;
-PNG_sBIT;
-PNG_sPLT;
-PNG_sRGB;
-PNG_tEXt;
-PNG_tIME;
-PNG_tRNS;
-PNG_zTXt;
-
-#ifdef PNG_READ_SUPPORTED
-/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
-/* start of interlace block */
-PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
-
-/* offset to next interlace block */
-PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
-
-/* start of interlace block in the y direction */
-PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
-
-/* offset to next interlace block in the y direction */
-PNG_CONST int FARDATA 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
-PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
-*/
-
-/* Mask to determine which pixels are valid in a pass */
-PNG_CONST int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
-
-/* Mask to determine which pixels to overwrite while displaying */
-PNG_CONST int FARDATA png_pass_dsp_mask[]
- = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
-
-#endif /* PNG_READ_SUPPORTED */
-#endif /* PNG_USE_GLOBAL_ARRAYS */
+typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43;
/* 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
@@ -90,14 +24,22 @@ PNG_CONST int FARDATA png_pass_dsp_mask[]
#ifdef PNG_READ_SUPPORTED
void PNGAPI
-png_set_sig_bytes(png_structp png_ptr, int num_bytes)
+png_set_sig_bytes(png_structrp png_ptr, int num_bytes)
{
- if(png_ptr == NULL) return;
- png_debug(1, "in png_set_sig_bytes\n");
- if (num_bytes > 8)
- png_error(png_ptr, "Too many bytes for PNG signature.");
+ unsigned int nb = (unsigned int)num_bytes;
- png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
+ png_debug(1, "in png_set_sig_bytes");
+
+ if (png_ptr == NULL)
+ return;
+
+ if (num_bytes < 0)
+ nb = 0;
+
+ if (nb > 8)
+ png_error(png_ptr, "Too many bytes for PNG signature");
+
+ png_ptr->sig_bytes = (png_byte)nb;
}
/* Checks whether the supplied bytes match the PNG signature. We allow
@@ -106,101 +48,66 @@ png_set_sig_bytes(png_structp png_ptr, int num_bytes)
* can simply check the remaining bytes for extra assurance. Returns
* an integer less than, equal to, or greater than zero if sig is found,
* respectively, to be less than, to match, or be greater than the correct
- * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ * PNG signature (this is the same behavior as strcmp, memcmp, etc).
*/
int PNGAPI
-png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
+png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check)
{
- png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ static const png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+
if (num_to_check > 8)
num_to_check = 8;
+
else if (num_to_check < 1)
- return (-1);
+ return -1;
if (start > 7)
- return (-1);
+ return -1;
if (start + num_to_check > 8)
num_to_check = 8 - start;
- return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
+ return memcmp(&sig[start], &png_signature[start], num_to_check);
}
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-/* (Obsolete) function to check signature bytes. It does not allow one
- * to check a partial signature. This function might be removed in the
- * future - use png_sig_cmp(). Returns true (nonzero) if the file is PNG.
- */
-int PNGAPI
-png_check_sig(png_bytep sig, int num)
-{
- return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num));
-}
-#endif
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ */
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-/* Function to allocate memory for zlib and clear it to 0. */
-#ifdef PNG_1_0_X
-voidpf PNGAPI
-#else
-voidpf /* private */
-#endif
-png_zalloc(voidpf png_ptr, uInt items, uInt size)
+/* Function to allocate memory for zlib */
+PNG_FUNCTION(voidpf /* PRIVATE */,
+png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
{
- png_voidp ptr;
- png_structp p=(png_structp)png_ptr;
- png_uint_32 save_flags=p->flags;
- png_uint_32 num_bytes;
+ png_alloc_size_t num_bytes = size;
- if(png_ptr == NULL) return (NULL);
- if (items > PNG_UINT_32_MAX/size)
+ if (png_ptr == NULL)
+ return NULL;
+
+ if (items >= (~(png_alloc_size_t)0)/size)
{
- png_warning (p, "Potential overflow in png_zalloc()");
- return (NULL);
+ png_warning (png_voidcast(png_structrp, png_ptr),
+ "Potential overflow in png_zalloc()");
+ return NULL;
}
- num_bytes = (png_uint_32)items * size;
- p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
- ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
- p->flags=save_flags;
-
-#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO)
- if (ptr == NULL)
- return ((voidpf)ptr);
-
- if (num_bytes > (png_uint_32)0x8000L)
- {
- png_memset(ptr, 0, (png_size_t)0x8000L);
- png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
- (png_size_t)(num_bytes - (png_uint_32)0x8000L));
- }
- else
- {
- png_memset(ptr, 0, (png_size_t)num_bytes);
- }
-#endif
- return ((voidpf)ptr);
+ num_bytes *= items;
+ return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes);
}
-/* function to free memory for zlib */
-#ifdef PNG_1_0_X
-void PNGAPI
-#else
-void /* private */
-#endif
+/* Function to free memory for zlib */
+void /* PRIVATE */
png_zfree(voidpf png_ptr, voidpf ptr)
{
- png_free((png_structp)png_ptr, (png_voidp)ptr);
+ png_free(png_voidcast(png_const_structrp,png_ptr), ptr);
}
/* Reset the CRC variable to 32 bits of 1's. Care must be taken
* in case CRC is > 32 bits to leave the top bits 0.
*/
void /* PRIVATE */
-png_reset_crc(png_structp png_ptr)
+png_reset_crc(png_structrp png_ptr)
{
- png_ptr->crc = crc32(0, Z_NULL, 0);
+ /* The cast is safe because the crc is a 32-bit value. */
+ png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0);
}
/* Calculate the CRC over a section of data. We can only pass as
@@ -209,494 +116,692 @@ png_reset_crc(png_structp png_ptr)
* trouble of calculating it.
*/
void /* PRIVATE */
-png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length)
{
int need_crc = 1;
- if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ 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 */
+
+ else /* critical */
{
- if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
need_crc = 0;
}
- if (need_crc)
- png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+ /* 'uLong' is defined in zlib.h as unsigned long; this means that on some
+ * systems it is a 64-bit value. crc32, however, returns 32 bits so the
+ * following cast is safe. 'uInt' may be no more than 16 bits, so it is
+ * necessary to perform a loop here.
+ */
+ if (need_crc != 0 && length > 0)
+ {
+ uLong crc = png_ptr->crc; /* Should never issue a warning */
+
+ do
+ {
+ uInt safe_length = (uInt)length;
+#ifndef __COVERITY__
+ if (safe_length == 0)
+ safe_length = (uInt)-1; /* evil, but safe */
+#endif
+
+ crc = crc32(crc, ptr, safe_length);
+
+ /* The following should never issue compiler warnings; if they do the
+ * target system has characteristics that will probably violate other
+ * assumptions within the libpng code.
+ */
+ ptr += safe_length;
+ length -= safe_length;
+ }
+ while (length > 0);
+
+ /* And the following is always safe because the crc is only 32 bits. */
+ png_ptr->crc = (png_uint_32)crc;
+ }
}
-/* Allocate the memory for an info_struct for the application. We don't
- * really need the png_ptr, but it could potentially be useful in the
- * future. This should be used in favour of malloc(png_sizeof(png_info))
- * and png_info_init() so that applications that want to use a shared
- * libpng don't have to be recompiled if png_info changes size.
+/* Check a user supplied version number, called from both read and write
+ * functions that create a png_struct.
*/
-png_infop PNGAPI
-png_create_info_struct(png_structp png_ptr)
+int
+png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
{
- png_infop info_ptr;
+ /* Libpng versions 1.0.0 and later are binary compatible if the version
+ * string matches through the second '.'; we must recompile any
+ * applications that use any older library version.
+ */
- png_debug(1, "in png_create_info_struct\n");
- if(png_ptr == NULL) return (NULL);
-#ifdef PNG_USER_MEM_SUPPORTED
- info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
- png_ptr->malloc_fn, png_ptr->mem_ptr);
-#else
- info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
+ if (user_png_ver != NULL)
+ {
+ int i = -1;
+ int found_dots = 0;
+
+ do
+ {
+ i++;
+ if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+ if (user_png_ver[i] == '.')
+ found_dots++;
+ } while (found_dots < 2 && user_png_ver[i] != 0 &&
+ PNG_LIBPNG_VER_STRING[i] != 0);
+ }
+
+ else
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+
+ if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0)
+ {
+#ifdef PNG_WARNINGS_SUPPORTED
+ size_t pos = 0;
+ char m[128];
+
+ pos = png_safecat(m, (sizeof m), pos,
+ "Application built with libpng-");
+ pos = png_safecat(m, (sizeof m), pos, user_png_ver);
+ pos = png_safecat(m, (sizeof m), pos, " but running with ");
+ pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
+ PNG_UNUSED(pos)
+
+ png_warning(png_ptr, m);
#endif
- if (info_ptr != NULL)
- png_info_init_3(&info_ptr, png_sizeof(png_info));
- return (info_ptr);
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags = 0;
+#endif
+
+ return 0;
+ }
+
+ /* Success return. */
+ return 1;
+}
+
+/* Generic function to create a png_struct for either read or write - this
+ * contains the common initialization.
+ */
+PNG_FUNCTION(png_structp /* PRIVATE */,
+png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
+{
+ png_struct create_struct;
+# ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf create_jmp_buf;
+# endif
+
+ /* This temporary stack-allocated structure is used to provide a place to
+ * build enough context to allow the user provided memory allocator (if any)
+ * to be called.
+ */
+ 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.
+ */
+ create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
+# endif
+# endif
+
+ /* The following two API calls simply set fields in png_struct, so it is safe
+ * to do them now even though error handling is not yet set up.
+ */
+# ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn);
+# else
+ PNG_UNUSED(mem_ptr)
+ PNG_UNUSED(malloc_fn)
+ PNG_UNUSED(free_fn)
+# endif
+
+ /* (*error_fn) can return control to the caller after the error_ptr is set,
+ * this will result in a memory leak unless the error_fn does something
+ * extremely sophisticated. The design lacks merit but is implicit in the
+ * API.
+ */
+ png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn);
+
+# ifdef PNG_SETJMP_SUPPORTED
+ if (!setjmp(create_jmp_buf))
+# endif
+ {
+# ifdef PNG_SETJMP_SUPPORTED
+ /* Temporarily fake out the longjmp information until we have
+ * successfully completed this function. This only works if we have
+ * setjmp() support compiled in, but it is safe - this stuff should
+ * never happen.
+ */
+ create_struct.jmp_buf_ptr = &create_jmp_buf;
+ create_struct.jmp_buf_size = 0; /*stack allocation*/
+ create_struct.longjmp_fn = longjmp;
+# endif
+ /* Call the general version checker (shared with read and write code):
+ */
+ if (png_user_version_check(&create_struct, user_png_ver) != 0)
+ {
+ png_structrp png_ptr = png_voidcast(png_structrp,
+ png_malloc_warn(&create_struct, (sizeof *png_ptr)));
+
+ if (png_ptr != NULL)
+ {
+ /* png_ptr->zstream holds a back-pointer to the png_struct, so
+ * this can only be done now:
+ */
+ create_struct.zstream.zalloc = png_zalloc;
+ create_struct.zstream.zfree = png_zfree;
+ create_struct.zstream.opaque = png_ptr;
+
+# ifdef PNG_SETJMP_SUPPORTED
+ /* Eliminate the local error handling: */
+ create_struct.jmp_buf_ptr = NULL;
+ create_struct.jmp_buf_size = 0;
+ create_struct.longjmp_fn = 0;
+# endif
+
+ *png_ptr = create_struct;
+
+ /* This is the successful return point */
+ return png_ptr;
+ }
+ }
+ }
+
+ /* A longjmp because of a bug in the application storage allocator or a
+ * simple failure to allocate the png_struct.
+ */
+ return NULL;
+}
+
+/* Allocate the memory for an info_struct for the application. */
+PNG_FUNCTION(png_infop,PNGAPI
+png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED)
+{
+ png_inforp info_ptr;
+
+ png_debug(1, "in png_create_info_struct");
+
+ if (png_ptr == NULL)
+ return NULL;
+
+ /* Use the internal API that does not (or at least should not) error out, so
+ * that this call always returns ok. The application typically sets up the
+ * error handling *after* creating the info_struct because this is the way it
+ * has always been done in 'example.c'.
+ */
+ info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr,
+ (sizeof *info_ptr)));
+
+ if (info_ptr != NULL)
+ memset(info_ptr, 0, (sizeof *info_ptr));
+
+ return info_ptr;
}
/* This function frees the memory associated with a single info struct.
* Normally, one would use either png_destroy_read_struct() or
* png_destroy_write_struct() to free an info struct, but this may be
- * useful for some applications.
+ * useful for some applications. From libpng 1.6.0 this function is also used
+ * internally to implement the png_info release part of the 'struct' destroy
+ * APIs. This ensures that all possible approaches free the same data (all of
+ * it).
*/
void PNGAPI
-png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
+png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr)
{
- png_infop info_ptr = NULL;
- if(png_ptr == NULL) return;
+ png_inforp info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_info_struct");
+
+ if (png_ptr == NULL)
+ return;
- png_debug(1, "in png_destroy_info_struct\n");
if (info_ptr_ptr != NULL)
info_ptr = *info_ptr_ptr;
if (info_ptr != NULL)
{
- png_info_destroy(png_ptr, info_ptr);
-
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
- png_ptr->mem_ptr);
-#else
- png_destroy_struct((png_voidp)info_ptr);
-#endif
+ /* Do this first in case of an error below; if the app implements its own
+ * memory management this can lead to png_free calling png_error, which
+ * will abort this routine and return control to the app error handler.
+ * An infinite loop may result if it then tries to free the same info
+ * ptr.
+ */
*info_ptr_ptr = NULL;
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+ memset(info_ptr, 0, (sizeof *info_ptr));
+ png_free(png_ptr, info_ptr);
}
}
/* Initialize the info structure. This is now an internal function (0.89)
* and applications using it are urged to use png_create_info_struct()
- * instead.
+ * instead. Use deprecated in 1.6.0, internal use removed (used internally it
+ * is just a memset).
+ *
+ * NOTE: it is almost inconceivable that this API is used because it bypasses
+ * the user-memory mechanism and the user error handling/warning mechanisms in
+ * those cases where it does anything other than a memset.
*/
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-#undef png_info_init
-void PNGAPI
-png_info_init(png_infop info_ptr)
+PNG_FUNCTION(void,PNGAPI
+png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size),
+ PNG_DEPRECATED)
{
- /* We only come here via pre-1.0.12-compiled applications */
- png_info_init_3(&info_ptr, 0);
-}
-#endif
+ png_inforp info_ptr = *ptr_ptr;
-void PNGAPI
-png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
-{
- png_infop info_ptr = *ptr_ptr;
+ png_debug(1, "in png_info_init_3");
- if(info_ptr == NULL) return;
-
- png_debug(1, "in png_info_init_3\n");
-
- if(png_sizeof(png_info) > png_info_struct_size)
- {
- png_destroy_struct(info_ptr);
- info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
- *ptr_ptr = info_ptr;
- }
-
- /* set everything to 0 */
- png_memset(info_ptr, 0, png_sizeof (png_info));
-}
-
-#ifdef PNG_FREE_ME_SUPPORTED
-void PNGAPI
-png_data_freer(png_structp png_ptr, png_infop info_ptr,
- int freer, png_uint_32 mask)
-{
- png_debug(1, "in png_data_freer\n");
- if (png_ptr == NULL || info_ptr == NULL)
- return;
- if(freer == PNG_DESTROY_WILL_FREE_DATA)
- info_ptr->free_me |= mask;
- else if(freer == PNG_USER_WILL_FREE_DATA)
- info_ptr->free_me &= ~mask;
- else
- png_warning(png_ptr,
- "Unknown freer parameter in png_data_freer.");
-}
-#endif
-
-void PNGAPI
-png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
- int num)
-{
- png_debug(1, "in png_free_data\n");
- if (png_ptr == NULL || info_ptr == NULL)
+ if (info_ptr == NULL)
return;
-#if defined(PNG_TEXT_SUPPORTED)
-/* free text item num or (if num == -1) all text items */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_TEXT)
-#endif
-{
- if (num != -1)
+ if ((sizeof (png_info)) > png_info_struct_size)
{
- if (info_ptr->text && info_ptr->text[num].key)
- {
+ *ptr_ptr = NULL;
+ /* The following line is why this API should not be used: */
+ free(info_ptr);
+ info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL,
+ (sizeof *info_ptr)));
+ if (info_ptr == NULL)
+ return;
+ *ptr_ptr = info_ptr;
+ }
+
+ /* Set everything to 0 */
+ memset(info_ptr, 0, (sizeof *info_ptr));
+}
+
+void PNGAPI
+png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,
+ int freer, png_uint_32 mask)
+{
+ png_debug(1, "in png_data_freer");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (freer == PNG_DESTROY_WILL_FREE_DATA)
+ info_ptr->free_me |= mask;
+
+ else if (freer == PNG_USER_WILL_FREE_DATA)
+ info_ptr->free_me &= ~mask;
+
+ else
+ png_error(png_ptr, "Unknown freer parameter in png_data_freer");
+}
+
+void PNGAPI
+png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
+ int num)
+{
+ png_debug(1, "in png_free_data");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+#ifdef PNG_TEXT_SUPPORTED
+ /* Free text item num or (if num == -1) all text items */
+ if (info_ptr->text != NULL &&
+ ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
+ {
+ if (num != -1)
+ {
png_free(png_ptr, info_ptr->text[num].key);
info_ptr->text[num].key = NULL;
- }
- }
- else
- {
- int i;
- for (i = 0; i < info_ptr->num_text; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
- png_free(png_ptr, info_ptr->text);
- info_ptr->text = NULL;
- info_ptr->num_text=0;
- }
-}
-#endif
+ }
-#if defined(PNG_tRNS_SUPPORTED)
-/* free any tRNS entry */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
-#else
-if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS))
-#endif
-{
- png_free(png_ptr, info_ptr->trans);
- info_ptr->valid &= ~PNG_INFO_tRNS;
-#ifndef PNG_FREE_ME_SUPPORTED
- png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
-#endif
- info_ptr->trans = NULL;
-}
-#endif
-
-#if defined(PNG_sCAL_SUPPORTED)
-/* free any sCAL entry */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_SCAL)
-#endif
-{
-#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
- png_free(png_ptr, info_ptr->scal_s_width);
- png_free(png_ptr, info_ptr->scal_s_height);
- info_ptr->scal_s_width = NULL;
- info_ptr->scal_s_height = NULL;
-#endif
- info_ptr->valid &= ~PNG_INFO_sCAL;
-}
-#endif
-
-#if defined(PNG_pCAL_SUPPORTED)
-/* free any pCAL entry */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_PCAL)
-#endif
-{
- png_free(png_ptr, info_ptr->pcal_purpose);
- png_free(png_ptr, info_ptr->pcal_units);
- info_ptr->pcal_purpose = NULL;
- info_ptr->pcal_units = NULL;
- if (info_ptr->pcal_params != NULL)
- {
- int i;
- for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
- {
- png_free(png_ptr, info_ptr->pcal_params[i]);
- info_ptr->pcal_params[i]=NULL;
- }
- png_free(png_ptr, info_ptr->pcal_params);
- info_ptr->pcal_params = NULL;
- }
- info_ptr->valid &= ~PNG_INFO_pCAL;
-}
-#endif
-
-#if defined(PNG_iCCP_SUPPORTED)
-/* free any iCCP entry */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_ICCP)
-#endif
-{
- png_free(png_ptr, info_ptr->iccp_name);
- png_free(png_ptr, info_ptr->iccp_profile);
- info_ptr->iccp_name = NULL;
- info_ptr->iccp_profile = NULL;
- info_ptr->valid &= ~PNG_INFO_iCCP;
-}
-#endif
-
-#if defined(PNG_sPLT_SUPPORTED)
-/* free a given sPLT entry, or (if num == -1) all sPLT entries */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_SPLT)
-#endif
-{
- if (num != -1)
- {
- if(info_ptr->splt_palettes)
+ else
{
- png_free(png_ptr, info_ptr->splt_palettes[num].name);
- png_free(png_ptr, info_ptr->splt_palettes[num].entries);
- info_ptr->splt_palettes[num].name = NULL;
- info_ptr->splt_palettes[num].entries = NULL;
+ int i;
+
+ for (i = 0; i < info_ptr->num_text; i++)
+ png_free(png_ptr, info_ptr->text[i].key);
+
+ png_free(png_ptr, info_ptr->text);
+ info_ptr->text = NULL;
+ info_ptr->num_text = 0;
+ info_ptr->max_text = 0;
}
}
- else
+#endif
+
+#ifdef PNG_tRNS_SUPPORTED
+ /* Free any tRNS entry */
+ if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0)
{
- if(info_ptr->splt_palettes_num)
- {
+ info_ptr->valid &= ~PNG_INFO_tRNS;
+ png_free(png_ptr, info_ptr->trans_alpha);
+ info_ptr->trans_alpha = NULL;
+ info_ptr->num_trans = 0;
+ }
+#endif
+
+#ifdef PNG_sCAL_SUPPORTED
+ /* Free any sCAL entry */
+ if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0)
+ {
+ png_free(png_ptr, info_ptr->scal_s_width);
+ png_free(png_ptr, info_ptr->scal_s_height);
+ info_ptr->scal_s_width = NULL;
+ info_ptr->scal_s_height = NULL;
+ info_ptr->valid &= ~PNG_INFO_sCAL;
+ }
+#endif
+
+#ifdef PNG_pCAL_SUPPORTED
+ /* Free any pCAL entry */
+ if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
+ {
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ info_ptr->pcal_purpose = NULL;
+ info_ptr->pcal_units = NULL;
+
+ if (info_ptr->pcal_params != NULL)
+ {
+ int i;
+
+ for (i = 0; i < info_ptr->pcal_nparams; i++)
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+
+ png_free(png_ptr, info_ptr->pcal_params);
+ info_ptr->pcal_params = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_pCAL;
+ }
+#endif
+
+#ifdef PNG_iCCP_SUPPORTED
+ /* Free any profile entry */
+ if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0)
+ {
+ png_free(png_ptr, info_ptr->iccp_name);
+ png_free(png_ptr, info_ptr->iccp_profile);
+ info_ptr->iccp_name = NULL;
+ info_ptr->iccp_profile = NULL;
+ info_ptr->valid &= ~PNG_INFO_iCCP;
+ }
+#endif
+
+#ifdef PNG_sPLT_SUPPORTED
+ /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
+ if (info_ptr->splt_palettes != NULL &&
+ ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
+ {
+ if (num != -1)
+ {
+ png_free(png_ptr, info_ptr->splt_palettes[num].name);
+ png_free(png_ptr, info_ptr->splt_palettes[num].entries);
+ info_ptr->splt_palettes[num].name = NULL;
+ info_ptr->splt_palettes[num].entries = NULL;
+ }
+
+ else
+ {
int i;
- for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
+
+ for (i = 0; i < info_ptr->splt_palettes_num; i++)
+ {
+ png_free(png_ptr, info_ptr->splt_palettes[i].name);
+ png_free(png_ptr, info_ptr->splt_palettes[i].entries);
+ }
png_free(png_ptr, info_ptr->splt_palettes);
info_ptr->splt_palettes = NULL;
info_ptr->splt_palettes_num = 0;
- }
- info_ptr->valid &= ~PNG_INFO_sPLT;
+ info_ptr->valid &= ~PNG_INFO_sPLT;
+ }
}
-}
#endif
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- if(png_ptr->unknown_chunk.data)
- {
- png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
- }
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_UNKN)
-#endif
-{
- if (num != -1)
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ if (info_ptr->unknown_chunks != NULL &&
+ ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
{
- if(info_ptr->unknown_chunks)
- {
+ if (num != -1)
+ {
png_free(png_ptr, info_ptr->unknown_chunks[num].data);
info_ptr->unknown_chunks[num].data = NULL;
- }
- }
- else
- {
- int i;
+ }
- if(info_ptr->unknown_chunks_num)
- {
- for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
+ else
+ {
+ int i;
+
+ for (i = 0; i < info_ptr->unknown_chunks_num; i++)
+ png_free(png_ptr, info_ptr->unknown_chunks[i].data);
png_free(png_ptr, info_ptr->unknown_chunks);
info_ptr->unknown_chunks = NULL;
info_ptr->unknown_chunks_num = 0;
- }
+ }
}
-}
#endif
-#if defined(PNG_hIST_SUPPORTED)
-/* free any hIST entry */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
-#else
-if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST))
-#endif
-{
- png_free(png_ptr, info_ptr->hist);
- info_ptr->hist = NULL;
- info_ptr->valid &= ~PNG_INFO_hIST;
-#ifndef PNG_FREE_ME_SUPPORTED
- png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
-#endif
-}
-#endif
-
-/* free any PLTE entry that was internally allocated */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
-#else
-if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE))
-#endif
-{
- png_zfree(png_ptr, info_ptr->palette);
- info_ptr->palette = NULL;
- info_ptr->valid &= ~PNG_INFO_PLTE;
-#ifndef PNG_FREE_ME_SUPPORTED
- png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
-#endif
- info_ptr->num_palette = 0;
-}
-
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
-/* free any image bits attached to the info structure */
-#ifdef PNG_FREE_ME_SUPPORTED
-if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
-#else
-if (mask & PNG_FREE_ROWS)
-#endif
-{
- if(info_ptr->row_pointers)
- {
- int row;
- for (row = 0; row < (int)info_ptr->height; row++)
- {
- png_free(png_ptr, info_ptr->row_pointers[row]);
- info_ptr->row_pointers[row]=NULL;
- }
- png_free(png_ptr, info_ptr->row_pointers);
- info_ptr->row_pointers=NULL;
- }
- info_ptr->valid &= ~PNG_INFO_IDAT;
-}
-#endif
-
-#ifdef PNG_FREE_ME_SUPPORTED
- if(num == -1)
- info_ptr->free_me &= ~mask;
- else
- info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
-#endif
-}
-
-/* This is an internal routine to free any memory that the info struct is
- * pointing to before re-using it or freeing the struct itself. Recall
- * that png_free() checks for NULL pointers for us.
- */
-void /* PRIVATE */
-png_info_destroy(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_info_destroy\n");
-
- png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- if (png_ptr->num_chunk_list)
+#ifdef PNG_eXIf_SUPPORTED
+ /* Free any eXIf entry */
+ if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)
{
- png_free(png_ptr, png_ptr->chunk_list);
- png_ptr->chunk_list=NULL;
- png_ptr->num_chunk_list=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);
+ info_ptr->exif = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_eXIf;
}
#endif
- png_info_init_3(&info_ptr, png_sizeof(png_info));
+#ifdef PNG_hIST_SUPPORTED
+ /* Free any hIST entry */
+ if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)
+ {
+ png_free(png_ptr, info_ptr->hist);
+ info_ptr->hist = NULL;
+ info_ptr->valid &= ~PNG_INFO_hIST;
+ }
+#endif
+
+ /* Free any PLTE entry that was internally allocated */
+ if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0)
+ {
+ png_free(png_ptr, info_ptr->palette);
+ info_ptr->palette = NULL;
+ info_ptr->valid &= ~PNG_INFO_PLTE;
+ info_ptr->num_palette = 0;
+ }
+
+#ifdef PNG_INFO_IMAGE_SUPPORTED
+ /* Free any image bits attached to the info structure */
+ if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
+ {
+ if (info_ptr->row_pointers != NULL)
+ {
+ png_uint_32 row;
+ for (row = 0; row < info_ptr->height; row++)
+ png_free(png_ptr, info_ptr->row_pointers[row]);
+
+ png_free(png_ptr, info_ptr->row_pointers);
+ info_ptr->row_pointers = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_IDAT;
+ }
+#endif
+
+ if (num != -1)
+ mask &= ~PNG_FREE_MUL;
+
+ info_ptr->free_me &= ~mask;
}
-#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+#endif /* READ || WRITE */
/* This function returns a pointer to the io_ptr associated with the user
* functions. The application should free any memory associated with this
* pointer before png_write_destroy() or png_read_destroy() are called.
*/
png_voidp PNGAPI
-png_get_io_ptr(png_structp png_ptr)
+png_get_io_ptr(png_const_structrp png_ptr)
{
- if(png_ptr == NULL) return (NULL);
- return (png_ptr->io_ptr);
+ if (png_ptr == NULL)
+ return NULL;
+
+ return png_ptr->io_ptr;
}
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-#if !defined(PNG_NO_STDIO)
+# ifdef PNG_STDIO_SUPPORTED
/* Initialize the default input/output functions for the PNG file. If you
* use your own read or write routines, you can call either png_set_read_fn()
* or png_set_write_fn() instead of png_init_io(). If you have defined
- * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
- * necessarily available.
+ * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
+ * function of your own because "FILE *" isn't necessarily available.
*/
void PNGAPI
-png_init_io(png_structp png_ptr, png_FILE_p fp)
+png_init_io(png_structrp png_ptr, png_FILE_p fp)
{
- png_debug(1, "in png_init_io\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_init_io");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->io_ptr = (png_voidp)fp;
}
-#endif
+# endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
+# ifdef PNG_SAVE_INT_32_SUPPORTED
+/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90
+ * defines a cast of a signed integer to an unsigned integer either to preserve
+ * the value, if it is positive, or to calculate:
+ *
+ * (UNSIGNED_MAX+1) + integer
+ *
+ * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
+ * negative integral value is added the result will be an unsigned value
+ * corresponding to the 2's complement representation.
+ */
+void PNGAPI
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ png_save_uint_32(buf, (png_uint_32)i);
+}
+# endif
+
+# ifdef PNG_TIME_RFC1123_SUPPORTED
/* Convert the supplied time into an RFC 1123 string suitable for use in
* a "Creation Time" or other text-based time string.
*/
-png_charp PNGAPI
-png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
+int PNGAPI
+png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)
{
- static PNG_CONST char short_months[12][4] =
+ static const char short_months[12][4] =
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- if(png_ptr == NULL) return (NULL);
- if (png_ptr->time_buffer == NULL)
+ if (out == NULL)
+ return 0;
+
+ if (ptime->year > 9999 /* RFC1123 limitation */ ||
+ ptime->month == 0 || ptime->month > 12 ||
+ ptime->day == 0 || ptime->day > 31 ||
+ ptime->hour > 23 || ptime->minute > 59 ||
+ ptime->second > 60)
+ return 0;
+
{
- png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
- png_sizeof(char)));
+ size_t pos = 0;
+ char number_buf[5] = {0, 0, 0, 0, 0}; /* enough for a four-digit year */
+
+# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))
+# define APPEND_NUMBER(format, value)\
+ APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
+# define APPEND(ch) if (pos < 28) out[pos++] = (ch)
+
+ APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day);
+ APPEND(' ');
+ APPEND_STRING(short_months[(ptime->month - 1)]);
+ APPEND(' ');
+ APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
+ APPEND(' ');
+ APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);
+ APPEND(':');
+ APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);
+ APPEND(':');
+ APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);
+ APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
+ PNG_UNUSED (pos)
+
+# undef APPEND
+# undef APPEND_NUMBER
+# undef APPEND_STRING
}
-#if defined(_WIN32_WCE)
- {
- wchar_t time_buf[29];
- wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"),
- ptime->day % 32, short_months[(ptime->month - 1) % 12],
- ptime->year, ptime->hour % 24, ptime->minute % 60,
- ptime->second % 61);
- WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29,
- NULL, NULL);
- }
-#else
-#ifdef USE_FAR_KEYWORD
- {
- char near_time_buf[29];
- png_snprintf6(near_time_buf,29,"%d %s %d %02d:%02d:%02d +0000",
- ptime->day % 32, short_months[(ptime->month - 1) % 12],
- ptime->year, ptime->hour % 24, ptime->minute % 60,
- ptime->second % 61);
- png_memcpy(png_ptr->time_buffer, near_time_buf,
- 29*png_sizeof(char));
- }
-#else
- png_snprintf6(png_ptr->time_buffer,29,"%d %s %d %02d:%02d:%02d +0000",
- ptime->day % 32, short_months[(ptime->month - 1) % 12],
- ptime->year, ptime->hour % 24, ptime->minute % 60,
- ptime->second % 61);
-#endif
-#endif /* _WIN32_WCE */
- return ((png_charp)png_ptr->time_buffer);
+ return 1;
}
-#endif /* PNG_TIME_RFC1123_SUPPORTED */
-#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
-
-png_charp PNGAPI
-png_get_copyright(png_structp png_ptr)
+# if PNG_LIBPNG_VER < 10700
+/* To do: remove the following from libpng-1.7 */
+/* Original API that uses a private buffer in png_struct.
+ * Deprecated because it causes png_struct to carry a spurious temporary
+ * buffer (png_struct::time_buffer), better to have the caller pass this in.
+ */
+png_const_charp PNGAPI
+png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime)
{
- png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
- return ((png_charp) "\n libpng version 1.2.24 - December 14, 2007\n\
- Copyright (c) 1998-2007 Glenn Randers-Pehrson\n\
- Copyright (c) 1996-1997 Andreas Dilger\n\
- Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n");
+ if (png_ptr != NULL)
+ {
+ /* The only failure above if png_ptr != NULL is from an invalid ptime */
+ if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0)
+ png_warning(png_ptr, "Ignoring invalid time value");
+
+ else
+ return png_ptr->time_buffer;
+ }
+
+ return NULL;
+}
+# endif /* LIBPNG_VER < 10700 */
+# endif /* TIME_RFC1123 */
+
+#endif /* READ || WRITE */
+
+png_const_charp PNGAPI
+png_get_copyright(png_const_structrp png_ptr)
+{
+ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
+#ifdef PNG_STRING_COPYRIGHT
+ return PNG_STRING_COPYRIGHT
+#else
+ return PNG_STRING_NEWLINE \
+ "libpng version 1.6.43" PNG_STRING_NEWLINE \
+ "Copyright (c) 2018-2024 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 \
+ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
+ PNG_STRING_NEWLINE;
+#endif
}
/* The following return the library version as a short string in the
@@ -707,92 +812,3748 @@ png_get_copyright(png_structp png_ptr)
* png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
* it is guaranteed that png.c uses the correct version of png.h.
*/
-png_charp PNGAPI
-png_get_libpng_ver(png_structp png_ptr)
+png_const_charp PNGAPI
+png_get_libpng_ver(png_const_structrp png_ptr)
{
/* Version of *.c files used when building libpng */
- png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
- return ((png_charp) PNG_LIBPNG_VER_STRING);
+ return png_get_header_ver(png_ptr);
}
-png_charp PNGAPI
-png_get_header_ver(png_structp png_ptr)
+png_const_charp PNGAPI
+png_get_header_ver(png_const_structrp png_ptr)
{
/* Version of *.h files used when building libpng */
- png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
- return ((png_charp) PNG_LIBPNG_VER_STRING);
+ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
+ return PNG_LIBPNG_VER_STRING;
}
-png_charp PNGAPI
-png_get_header_version(png_structp png_ptr)
+png_const_charp PNGAPI
+png_get_header_version(png_const_structrp png_ptr)
{
/* Returns longer string containing both version and date */
- png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
- return ((png_charp) PNG_HEADER_VERSION_STRING
-#ifndef PNG_READ_SUPPORTED
- " (NO READ SUPPORT)"
+ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
+#ifdef __STDC__
+ return PNG_HEADER_VERSION_STRING
+# ifndef PNG_READ_SUPPORTED
+ " (NO READ SUPPORT)"
+# endif
+ PNG_STRING_NEWLINE;
+#else
+ return PNG_HEADER_VERSION_STRING;
#endif
- "\n");
}
-#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-int PNGAPI
-png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name)
+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+/* NOTE: this routine is not used internally! */
+/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
+ * large of png_color. This lets grayscale images be treated as
+ * paletted. Most useful for gamma correction and simplification
+ * of code. This API is not used internally.
+ */
+void PNGAPI
+png_build_grayscale_palette(int bit_depth, png_colorp palette)
{
- /* check chunk_name and return "keep" value if it's on the list, else 0 */
+ int num_palette;
+ int color_inc;
int i;
- png_bytep p;
- if(png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0)
- return 0;
- p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5;
- for (i = png_ptr->num_chunk_list; i; i--, p-=5)
- if (!png_memcmp(chunk_name, p, 4))
- return ((int)*(p+4));
- return 0;
+ int v;
+
+ png_debug(1, "in png_do_build_grayscale_palette");
+
+ if (palette == NULL)
+ return;
+
+ switch (bit_depth)
+ {
+ case 1:
+ num_palette = 2;
+ color_inc = 0xff;
+ break;
+
+ case 2:
+ num_palette = 4;
+ color_inc = 0x55;
+ break;
+
+ case 4:
+ num_palette = 16;
+ color_inc = 0x11;
+ break;
+
+ case 8:
+ num_palette = 256;
+ color_inc = 1;
+ break;
+
+ default:
+ num_palette = 0;
+ color_inc = 0;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = (png_byte)(v & 0xff);
+ palette[i].green = (png_byte)(v & 0xff);
+ palette[i].blue = (png_byte)(v & 0xff);
+ }
}
#endif
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+int PNGAPI
+png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name)
+{
+ /* Check chunk_name and return "keep" value if it's on the list, else 0 */
+ png_const_bytep p, p_end;
+
+ if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0)
+ return PNG_HANDLE_CHUNK_AS_DEFAULT;
+
+ p_end = png_ptr->chunk_list;
+ p = p_end + png_ptr->num_chunk_list*5; /* beyond end */
+
+ /* The code is the fifth byte after each four byte string. Historically this
+ * code was always searched from the end of the list, this is no longer
+ * necessary because the 'set' routine handles duplicate entries correctly.
+ */
+ do /* num_chunk_list > 0, so at least one */
+ {
+ p -= 5;
+
+ if (memcmp(chunk_name, p, 4) == 0)
+ return p[4];
+ }
+ while (p > p_end);
+
+ /* This means that known chunks should be processed and unknown chunks should
+ * be handled according to the value of png_ptr->unknown_default; this can be
+ * confusing because, as a result, there are two levels of defaulting for
+ * unknown chunks.
+ */
+ return PNG_HANDLE_CHUNK_AS_DEFAULT;
+}
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
+ defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
+int /* PRIVATE */
+png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name)
+{
+ png_byte chunk_string[5];
+
+ PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name);
+ return png_handle_as_unknown(png_ptr, chunk_string);
+}
+#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */
+#endif /* SET_UNKNOWN_CHUNKS */
+
+#ifdef PNG_READ_SUPPORTED
/* This function, added to libpng-1.0.6g, is untested. */
int PNGAPI
-png_reset_zstream(png_structp png_ptr)
+png_reset_zstream(png_structrp png_ptr)
{
- if (png_ptr == NULL) return Z_STREAM_ERROR;
- return (inflateReset(&png_ptr->zstream));
+ if (png_ptr == NULL)
+ return Z_STREAM_ERROR;
+
+ /* WARNING: this resets the window bits to the maximum! */
+ return inflateReset(&png_ptr->zstream);
}
-#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+#endif /* READ */
/* This function was added to libpng-1.0.7 */
png_uint_32 PNGAPI
png_access_version_number(void)
{
/* Version of *.c files used when building libpng */
- return((png_uint_32) PNG_LIBPNG_VER);
+ return (png_uint_32)PNG_LIBPNG_VER;
}
-
-#if defined(PNG_READ_SUPPORTED) && defined(PNG_ASSEMBLER_CODE_SUPPORTED)
-#if !defined(PNG_1_0_X)
-/* this function was added to libpng 1.2.0 */
-int PNGAPI
-png_mmx_support(void)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- return -1;
-}
-#endif /* PNG_1_0_X */
-#endif /* PNG_READ_SUPPORTED && PNG_ASSEMBLER_CODE_SUPPORTED */
-
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-#ifdef PNG_SIZE_T
-/* Added at libpng version 1.2.6 */
- PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
-png_size_t PNGAPI
-png_convert_size(size_t size)
+/* Ensure that png_ptr->zstream.msg holds some appropriate error message string.
+ * If it doesn't 'ret' is used to set it to something appropriate, even in cases
+ * like Z_OK or Z_STREAM_END where the error code is apparently a success code.
+ */
+void /* PRIVATE */
+png_zstream_error(png_structrp png_ptr, int ret)
{
- if (size > (png_size_t)-1)
- PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
- return ((png_size_t)size);
+ /* Translate 'ret' into an appropriate error string, priority is given to the
+ * one in zstream if set. This always returns a string, even in cases like
+ * Z_OK or Z_STREAM_END where the error code is a success code.
+ */
+ if (png_ptr->zstream.msg == NULL) switch (ret)
+ {
+ default:
+ case Z_OK:
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code");
+ break;
+
+ case Z_STREAM_END:
+ /* Normal exit */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream");
+ break;
+
+ case Z_NEED_DICT:
+ /* This means the deflate stream did not have a dictionary; this
+ * indicates a bogus PNG.
+ */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary");
+ break;
+
+ case Z_ERRNO:
+ /* gz APIs only: should not happen */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error");
+ break;
+
+ case Z_STREAM_ERROR:
+ /* internal libpng error */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib");
+ break;
+
+ case Z_DATA_ERROR:
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream");
+ break;
+
+ case Z_MEM_ERROR:
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory");
+ break;
+
+ case Z_BUF_ERROR:
+ /* End of input or output; not a problem if the caller is doing
+ * incremental read or write.
+ */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated");
+ break;
+
+ case Z_VERSION_ERROR:
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version");
+ break;
+
+ case PNG_UNEXPECTED_ZLIB_RETURN:
+ /* Compile errors here mean that zlib now uses the value co-opted in
+ * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above
+ * and change pngpriv.h. Note that this message is "... return",
+ * whereas the default/Z_OK one is "... return code".
+ */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return");
+ break;
+ }
}
-#endif /* PNG_SIZE_T */
-#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+/* png_convert_size: a PNGAPI but no longer in png.h, so deleted
+ * at libpng 1.5.5!
+ */
+
+/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
+#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
+static int
+png_colorspace_check_gamma(png_const_structrp png_ptr,
+ png_colorspacerp colorspace, png_fixed_point gAMA, int from)
+ /* This is called to check a new gamma value against an existing one. The
+ * routine returns false if the new gamma value should not be written.
+ *
+ * 'from' says where the new gamma value comes from:
+ *
+ * 0: the new gamma value is the libpng estimate for an ICC profile
+ * 1: the new gamma value comes from a gAMA chunk
+ * 2: the new gamma value comes from an sRGB chunk
+ */
+{
+ png_fixed_point gtest;
+
+ if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
+ (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 ||
+ png_gamma_significant(gtest) != 0))
+ {
+ /* Either this is an sRGB image, in which case the calculated gamma
+ * approximation should match, or this is an image with a profile and the
+ * value libpng calculates for the gamma of the profile does not match the
+ * value recorded in the file. The former, sRGB, case is an error, the
+ * latter is just a warning.
+ */
+ if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)
+ {
+ png_chunk_report(png_ptr, "gamma value does not match sRGB",
+ PNG_CHUNK_ERROR);
+ /* Do not overwrite an sRGB value */
+ return from == 2;
+ }
+
+ else /* sRGB tag not involved */
+ {
+ png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
+ PNG_CHUNK_WARNING);
+ return from == 1;
+ }
+ }
+
+ return 1;
+}
+
+void /* PRIVATE */
+png_colorspace_set_gamma(png_const_structrp png_ptr,
+ png_colorspacerp colorspace, png_fixed_point gAMA)
+{
+ /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
+ * occur. Since the fixed point representation is asymmetrical it is
+ * possible for 1/gamma to overflow the limit of 21474 and this means the
+ * gamma value must be at least 5/100000 and hence at most 20000.0. For
+ * safety the limits here are a little narrower. The values are 0.00016 to
+ * 6250.0, which are truly ridiculous gamma values (and will produce
+ * displays that are all black or all white.)
+ *
+ * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
+ * handling code, which only required the value to be >0.
+ */
+ png_const_charp errmsg;
+
+ if (gAMA < 16 || gAMA > 625000000)
+ errmsg = "gamma value out of range";
+
+# ifdef PNG_READ_gAMA_SUPPORTED
+ /* Allow the application to set the gamma value more than once */
+ else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
+ (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
+ errmsg = "duplicate";
+# endif
+
+ /* Do nothing if the colorspace is already invalid */
+ else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
+ return;
+
+ else
+ {
+ if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
+ 1/*from gAMA*/) != 0)
+ {
+ /* Store this gamma value. */
+ colorspace->gamma = gAMA;
+ colorspace->flags |=
+ (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
+ }
+
+ /* At present if the check_gamma test fails the gamma of the colorspace is
+ * not updated however the colorspace is not invalidated. This
+ * corresponds to the case where the existing gamma comes from an sRGB
+ * chunk or profile. An error message has already been output.
+ */
+ return;
+ }
+
+ /* Error exit - errmsg has been set. */
+ colorspace->flags |= PNG_COLORSPACE_INVALID;
+ png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
+}
+
+void /* PRIVATE */
+png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)
+{
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
+ {
+ /* Everything is invalid */
+ info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|
+ PNG_INFO_iCCP);
+
+# ifdef PNG_COLORSPACE_SUPPORTED
+ /* Clean up the iCCP profile now if it won't be used. */
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);
+# else
+ PNG_UNUSED(png_ptr)
+# endif
+ }
+
+ else
+ {
+# ifdef PNG_COLORSPACE_SUPPORTED
+ /* Leave the INFO_iCCP flag set if the pngset.c code has already set
+ * it; this allows a PNG to contain a profile which matches sRGB and
+ * yet still have that profile retrievable by the application.
+ */
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0)
+ info_ptr->valid |= PNG_INFO_sRGB;
+
+ else
+ info_ptr->valid &= ~PNG_INFO_sRGB;
+
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+ info_ptr->valid |= PNG_INFO_cHRM;
+
+ else
+ info_ptr->valid &= ~PNG_INFO_cHRM;
+# endif
+
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0)
+ info_ptr->valid |= PNG_INFO_gAMA;
+
+ else
+ info_ptr->valid &= ~PNG_INFO_gAMA;
+ }
+}
+
+#ifdef PNG_READ_SUPPORTED
+void /* PRIVATE */
+png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
+{
+ if (info_ptr == NULL) /* reduce code size; check here not in the caller */
+ return;
+
+ info_ptr->colorspace = png_ptr->colorspace;
+ png_colorspace_sync_info(png_ptr, info_ptr);
+}
+#endif
+#endif /* GAMMA */
+
+#ifdef PNG_COLORSPACE_SUPPORTED
+/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
+ * cHRM, as opposed to using chromaticities. These internal APIs return
+ * non-zero on a parameter error. The X, Y and Z values are required to be
+ * positive and less than 1.0.
+ */
+static int
+png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
+{
+ png_int_32 d, dwhite, whiteX, whiteY;
+
+ d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z;
+ if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
+ return 1;
+ if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
+ return 1;
+ dwhite = d;
+ whiteX = XYZ->red_X;
+ whiteY = XYZ->red_Y;
+
+ d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z;
+ if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
+ return 1;
+ if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
+ return 1;
+ dwhite += d;
+ whiteX += XYZ->green_X;
+ whiteY += XYZ->green_Y;
+
+ d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z;
+ if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
+ return 1;
+ if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
+ return 1;
+ dwhite += d;
+ whiteX += XYZ->blue_X;
+ whiteY += XYZ->blue_Y;
+
+ /* The reference white is simply the sum of the end-point (X,Y,Z) vectors,
+ * thus:
+ */
+ if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0)
+ return 1;
+ if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int
+png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
+{
+ 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.
+ */
+ if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1;
+ if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;
+ if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;
+ if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;
+ if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1;
+ if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;
+ if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;
+ if (xy->whitey < 5 || xy->whitey > PNG_FP_1-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;
+ * (red,green,blue,white)x(x,y). This loses one degree of freedom and
+ * therefore an arbitrary ninth value has to be introduced to undo the
+ * original transformations.
+ *
+ * Think of the original end-points as points in (X,Y,Z) space. The
+ * chromaticity values (c) have the property:
+ *
+ * C
+ * c = ---------
+ * X + Y + Z
+ *
+ * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the
+ * three chromaticity values (x,y,z) for each end-point obey the
+ * relationship:
+ *
+ * x + y + z = 1
+ *
+ * This describes the plane in (X,Y,Z) space that intersects each axis at the
+ * value 1.0; call this the chromaticity plane. Thus the chromaticity
+ * calculation has scaled each end-point so that it is on the x+y+z=1 plane
+ * and chromaticity is the intersection of the vector from the origin to the
+ * (X,Y,Z) value with the chromaticity plane.
+ *
+ * To fully invert the chromaticity calculation we would need the three
+ * end-point scale factors, (red-scale, green-scale, blue-scale), but these
+ * were not recorded. Instead we calculated the reference white (X,Y,Z) and
+ * recorded the chromaticity of this. The reference white (X,Y,Z) would have
+ * given all three of the scale factors since:
+ *
+ * color-C = color-c * color-scale
+ * white-C = red-C + green-C + blue-C
+ * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
+ *
+ * But cHRM records only white-x and white-y, so we have lost the white scale
+ * factor:
+ *
+ * white-C = white-c*white-scale
+ *
+ * To handle this the inverse transformation makes an arbitrary assumption
+ * about white-scale:
+ *
+ * Assume: white-Y = 1.0
+ * Hence: white-scale = 1/white-y
+ * Or: red-Y + green-Y + blue-Y = 1.0
+ *
+ * Notice the last statement of the assumption gives an equation in three of
+ * the nine values we want to calculate. 8 more equations come from the
+ * above routine as summarised at the top above (the chromaticity
+ * calculation):
+ *
+ * Given: color-x = color-X / (color-X + color-Y + color-Z)
+ * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0
+ *
+ * This is 9 simultaneous equations in the 9 variables "color-C" and can be
+ * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix
+ * determinants, however this is not as bad as it seems because only 28 of
+ * the total of 90 terms in the various matrices are non-zero. Nevertheless
+ * Cramer's rule is notoriously numerically unstable because the determinant
+ * calculation involves the difference of large, but similar, numbers. It is
+ * difficult to be sure that the calculation is stable for real world values
+ * and it is certain that it becomes unstable where the end points are close
+ * together.
+ *
+ * So this code uses the perhaps slightly less optimal but more
+ * understandable and totally obvious approach of calculating color-scale.
+ *
+ * This algorithm depends on the precision in white-scale and that is
+ * (1/white-y), so we can immediately see that as white-y approaches 0 the
+ * accuracy inherent in the cHRM chunk drops off substantially.
+ *
+ * libpng arithmetic: a simple inversion of the above equations
+ * ------------------------------------------------------------
+ *
+ * white_scale = 1/white-y
+ * white-X = white-x * white-scale
+ * white-Y = 1.0
+ * white-Z = (1 - white-x - white-y) * white_scale
+ *
+ * white-C = red-C + green-C + blue-C
+ * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
+ *
+ * This gives us three equations in (red-scale,green-scale,blue-scale) where
+ * all the coefficients are now known:
+ *
+ * red-x*red-scale + green-x*green-scale + blue-x*blue-scale
+ * = white-x/white-y
+ * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1
+ * red-z*red-scale + green-z*green-scale + blue-z*blue-scale
+ * = (1 - white-x - white-y)/white-y
+ *
+ * In the last equation color-z is (1 - color-x - color-y) so we can add all
+ * three equations together to get an alternative third:
+ *
+ * red-scale + green-scale + blue-scale = 1/white-y = white-scale
+ *
+ * So now we have a Cramer's rule solution where the determinants are just
+ * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve
+ * multiplication of three coefficients so we can't guarantee to avoid
+ * overflow in the libpng fixed point representation. Using Cramer's rule in
+ * floating point is probably a good choice here, but it's not an option for
+ * fixed point. Instead proceed to simplify the first two equations by
+ * eliminating what is likely to be the largest value, blue-scale:
+ *
+ * blue-scale = white-scale - red-scale - green-scale
+ *
+ * Hence:
+ *
+ * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale =
+ * (white-x - blue-x)*white-scale
+ *
+ * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale =
+ * 1 - blue-y*white-scale
+ *
+ * And now we can trivially solve for (red-scale,green-scale):
+ *
+ * green-scale =
+ * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale
+ * -----------------------------------------------------------
+ * green-x - blue-x
+ *
+ * red-scale =
+ * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale
+ * ---------------------------------------------------------
+ * red-y - blue-y
+ *
+ * Hence:
+ *
+ * red-scale =
+ * ( (green-x - blue-x) * (white-y - blue-y) -
+ * (green-y - blue-y) * (white-x - blue-x) ) / white-y
+ * -------------------------------------------------------------------------
+ * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
+ *
+ * green-scale =
+ * ( (red-y - blue-y) * (white-x - blue-x) -
+ * (red-x - blue-x) * (white-y - blue-y) ) / white-y
+ * -------------------------------------------------------------------------
+ * (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 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.
+ *
+ * Note that the values of the differences of the products of the
+ * chromaticities in the above equations tend to be small, for example for
+ * the sRGB chromaticities they are:
+ *
+ * red numerator: -0.04751
+ * green numerator: -0.08788
+ * denominator: -0.2241 (without white-y multiplication)
+ *
+ * The resultant Y coefficients from the chromaticities of some widely used
+ * color space definitions are (to 15 decimal places):
+ *
+ * sRGB
+ * 0.212639005871510 0.715168678767756 0.072192315360734
+ * Kodak ProPhoto
+ * 0.288071128229293 0.711843217810102 0.000085653960605
+ * Adobe RGB
+ * 0.297344975250536 0.627363566255466 0.075291458493998
+ * 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 2;
+ if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
+ return 2;
+ denominator = left - right;
+
+ /* Now find the red numerator. */
+ if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
+ return 2;
+ if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
+ return 2;
+
+ /* 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;
+
+ /* Similarly for green_inverse: */
+ if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
+ return 2;
+ if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
+ return 2;
+ if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
+ 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_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -
+ png_reciprocal(green_inverse);
+ if (blue_scale <= 0)
+ return 1;
+
+
+ /* And fill in the png_XYZ: */
+ 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)
+ return 1;
+ if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,
+ red_inverse) == 0)
+ return 1;
+
+ if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0)
+ return 1;
+ if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0)
+ return 1;
+ if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,
+ green_inverse) == 0)
+ return 1;
+
+ if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0)
+ return 1;
+ if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0)
+ return 1;
+ if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,
+ PNG_FP_1) == 0)
+ return 1;
+
+ return 0; /*success*/
+}
+
+static int
+png_XYZ_normalize(png_XYZ *XYZ)
+{
+ png_int_32 Y;
+
+ if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 ||
+ XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||
+ XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)
+ return 1;
+
+ /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1.
+ * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
+ * relying on addition of two positive values producing a negative one is not
+ * safe.
+ */
+ Y = XYZ->red_Y;
+ if (0x7fffffff - Y < XYZ->green_X)
+ return 1;
+ Y += XYZ->green_Y;
+ if (0x7fffffff - Y < XYZ->blue_X)
+ return 1;
+ Y += XYZ->blue_Y;
+
+ 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)
+/* Error message generation */
+static char
+png_icc_tag_char(png_uint_32 byte)
+{
+ byte &= 0xff;
+ if (byte >= 32 && byte <= 126)
+ return (char)byte;
+ else
+ return '?';
+}
+
+static void
+png_icc_tag_name(char *name, png_uint_32 tag)
+{
+ name[0] = '\'';
+ name[1] = png_icc_tag_char(tag >> 24);
+ name[2] = png_icc_tag_char(tag >> 16);
+ name[3] = png_icc_tag_char(tag >> 8);
+ name[4] = png_icc_tag_char(tag );
+ name[5] = '\'';
+}
+
+static int
+is_ICC_signature_char(png_alloc_size_t it)
+{
+ return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||
+ (it >= 97 && it <= 122);
+}
+
+static int
+is_ICC_signature(png_alloc_size_t it)
+{
+ return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&
+ is_ICC_signature_char((it >> 16) & 0xff) &&
+ is_ICC_signature_char((it >> 8) & 0xff) &&
+ is_ICC_signature_char(it & 0xff);
+}
+
+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)
+{
+ 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 */
+ if (is_ICC_signature(value) != 0)
+ {
+ /* So 'value' is at most 4 bytes and the following cast is safe */
+ png_icc_tag_name(message+pos, (png_uint_32)value);
+ pos += 6; /* total +8; less than the else clause */
+ message[pos++] = ':';
+ message[pos++] = ' ';
+ }
+# ifdef PNG_WARNINGS_SUPPORTED
+ else
+ {
+ char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
+
+ pos = png_safecat(message, (sizeof message), pos,
+ png_format_number(number, number+(sizeof number),
+ PNG_NUMBER_FORMAT_x, value));
+ pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
+ }
+# endif
+ /* The 'reason' is an arbitrary message, allow +79 maximum 195 */
+ 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);
+
+ 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:
+ *
+ * (63189.8112, 65536, 54060.6464)
+ */
+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)
+{
+ if (profile_length < 132)
+ return png_icc_profile_error(png_ptr, colorspace, 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)
+{
+ if (!icc_check_length(png_ptr, colorspace, name, profile_length))
+ return 0;
+
+ /* This needs to be here because the 'normal' check is in
+ * png_decompress_chunk, yet this happens after the attempt to
+ * png_malloc_base the required data. We only need this on read; on write
+ * 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 */
+
+ 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_uint_32 temp;
+
+ /* Length check; this cannot be ignored in this code because profile_length
+ * is used later to check the tag table, so even if the profile seems over
+ * long profile_length from the caller must be correct. The caller can fix
+ * this up on read or write by just passing in the profile header length.
+ */
+ temp = png_get_uint_32(profile);
+ if (temp != profile_length)
+ return png_icc_profile_error(png_ptr, colorspace, 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,
+ "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,
+ "tag count too large");
+
+ /* The 'intent' must be valid or we can't store it, ICC limits the intent to
+ * 16 bits.
+ */
+ temp = png_get_uint_32(profile+64);
+ if (temp >= 0xffff) /* The ICC limit */
+ return png_icc_profile_error(png_ptr, colorspace, 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,
+ "intent outside defined range");
+
+ /* At this point the tag table can't be checked because it hasn't necessarily
+ * been loaded; however, various header fields can be checked. These checks
+ * are for values permitted by the PNG spec in an ICC profile; the PNG spec
+ * restricts the profiles that can be passed in an iCCP chunk (they must be
+ * appropriate to processing PNG data!)
+ */
+
+ /* Data checks (could be skipped). These checks must be independent of the
+ * version number; however, the version number doesn't accommodate changes in
+ * the header fields (just the known tags and the interpretation of the
+ * data.)
+ */
+ temp = png_get_uint_32(profile+36); /* signature 'ascp' */
+ if (temp != 0x61637370)
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
+ "invalid signature");
+
+ /* Currently the PCS illuminant/adopted white point (the computational
+ * white point) are required to be D50,
+ * however the profile contains a record of the illuminant so perhaps ICC
+ * expects to be able to change this in the future (despite the rationale in
+ * the introduction for using a fixed PCS adopted white.) Consequently the
+ * 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*/,
+ "PCS illuminant is not D50");
+
+ /* The PNG spec requires this:
+ * "If the iCCP chunk is present, the image samples conform to the colour
+ * space represented by the embedded ICC profile as defined by the
+ * International Color Consortium [ICC]. The colour space of the ICC profile
+ * shall be an RGB colour space for colour images (PNG colour types 2, 3, and
+ * 6), or a greyscale colour space for greyscale images (PNG colour types 0
+ * and 4)."
+ *
+ * This checking code ensures the embedded profile (on either read or write)
+ * conforms to the specification requirements. Notice that an ICC 'gray'
+ * color-space profile contains the information to transform the monochrome
+ * data to XYZ or L*a*b (according to which PCS the profile uses) and this
+ * should be used in preference to the standard libpng K channel replication
+ * into R, G and B channels.
+ *
+ * Previously it was suggested that an RGB profile on grayscale data could be
+ * handled. However it it is clear that using an RGB profile in this context
+ * must be an error - there is no specification of what it means. Thus it is
+ * almost certainly more correct to ignore the profile.
+ */
+ temp = png_get_uint_32(profile+16); /* data colour space field */
+ switch (temp)
+ {
+ case 0x52474220: /* 'RGB ' */
+ if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
+ return png_icc_profile_error(png_ptr, colorspace, 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,
+ "Gray color space not permitted on RGB PNG");
+ break;
+
+ default:
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
+ "invalid ICC profile color space");
+ }
+
+ /* It is up to the application to check that the profile class matches the
+ * application requirements; the spec provides no guidance, but it's pretty
+ * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer
+ * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these
+ * cases. Issue an error for device link or abstract profiles - these don't
+ * contain the records necessary to transform the color-space to anything
+ * other than the target device (and not even that for an abstract profile).
+ * Profiles of these classes may not be embedded in images.
+ */
+ temp = png_get_uint_32(profile+12); /* profile/device class */
+ switch (temp)
+ {
+ case 0x73636e72: /* 'scnr' */
+ case 0x6d6e7472: /* 'mntr' */
+ case 0x70727472: /* 'prtr' */
+ case 0x73706163: /* 'spac' */
+ /* All supported */
+ break;
+
+ case 0x61627374: /* 'abst' */
+ /* May not be embedded in an image */
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
+ "invalid embedded Abstract ICC profile");
+
+ case 0x6c696e6b: /* 'link' */
+ /* DeviceLink profiles cannot be interpreted in a non-device specific
+ * fashion, if an app uses the AToB0Tag in the profile the results are
+ * undefined unless the result is sent to the intended device,
+ * therefore a DeviceLink profile should not be found embedded in a
+ * PNG.
+ */
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
+ "unexpected DeviceLink ICC profile class");
+
+ case 0x6e6d636c: /* 'nmcl' */
+ /* A NamedColor profile is also device specific, however it doesn't
+ * 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,
+ "unexpected NamedColor ICC profile class");
+ break;
+
+ default:
+ /* To allow for future enhancements to the profile accept unrecognized
+ * profile classes with a warning, these then hit the test below on the
+ * tag content to ensure they are backward compatible with one of the
+ * understood profiles.
+ */
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
+ "unrecognized ICC profile class");
+ break;
+ }
+
+ /* For any profile other than a device link one the PCS must be encoded
+ * either in XYZ or Lab.
+ */
+ temp = png_get_uint_32(profile+20);
+ switch (temp)
+ {
+ case 0x58595a20: /* 'XYZ ' */
+ case 0x4c616220: /* 'Lab ' */
+ break;
+
+ default:
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
+ "unexpected ICC PCS encoding");
+ }
+
+ return 1;
+}
+
+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_uint_32 tag_count = png_get_uint_32(profile+128);
+ png_uint_32 itag;
+ png_const_bytep tag = profile+132; /* The first tag */
+
+ /* First scan all the tags in the table and add bits to the icc_info value
+ * (temporarily in 'tags').
+ */
+ for (itag=0; itag < tag_count; ++itag, tag += 12)
+ {
+ png_uint_32 tag_id = png_get_uint_32(tag+0);
+ png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */
+ png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */
+
+ /* The ICC specification does not exclude zero length tags, therefore the
+ * start might actually be anywhere if there is no data, but this would be
+ * a clear abuse of the intent of the standard so the start is checked for
+ * being in range. All defined tag types have an 8 byte header - a 4 byte
+ * type signature then 0.
+ */
+
+ /* This is a hard error; potentially it can cause read outside the
+ * profile.
+ */
+ if (tag_start > profile_length || tag_length > profile_length - tag_start)
+ return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
+ "ICC profile tag outside profile");
+
+ if ((tag_start & 3) != 0)
+ {
+ /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is
+ * only a warning here because libpng does not care about the
+ * alignment.
+ */
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
+ "ICC profile tag start not a multiple of 4");
+ }
+ }
+
+ return 1; /* success, maybe with warnings */
+}
+
+#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")
+};
+
+static int
+png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
+ png_const_bytep profile, uLong adler)
+{
+ /* 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.
+ */
+
+ 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;
+ }
+ }
+
+# if PNG_sRGB_PROFILE_CHECKS > 0
+ /* The signature matched, but the profile had been changed in some
+ * way. This probably indicates a data error or uninformed hacking.
+ * Fall through to "no match".
+ */
+ png_chunk_report(png_ptr,
+ "Not recognizing known sRGB profile that has been edited",
+ PNG_CHUNK_WARNING);
+ break;
+# endif
+ }
+ }
+ }
+
+ return 0; /* no match */
+}
+
+void /* PRIVATE */
+png_icc_set_sRGB(png_const_structrp png_ptr,
+ png_colorspacerp colorspace, png_const_bytep profile, uLong adler)
+{
+ /* Is this profile one of the known ICC sRGB profiles? If it is, just set
+ * the sRGB information.
+ */
+ if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0)
+ (void)png_colorspace_set_sRGB(png_ptr, colorspace,
+ (int)/*already checked*/png_get_uint_32(profile+64));
+}
+#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */
+#endif /* sRGB */
+
+int /* PRIVATE */
+png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,
+ png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,
+ int color_type)
+{
+ if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
+ return 0;
+
+ if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
+ png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
+ color_type) != 0 &&
+ png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
+ profile) != 0)
+ {
+# if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
+ /* If no sRGB support, don't try storing sRGB information */
+ png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
+# endif
+ return 1;
+ }
+
+ /* Failure case */
+ return 0;
+}
+#endif /* iCCP */
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+void /* PRIVATE */
+png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
+{
+ /* Set the rgb_to_gray coefficients from the colorspace. */
+ if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
+ (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
+ {
+ /* png_set_background has not been called, get the coefficients from the Y
+ * values of the colorspace colorants.
+ */
+ png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;
+ png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
+ png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
+ png_fixed_point total = r+g+b;
+
+ if (total > 0 &&
+ r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
+ g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
+ b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
+ r+g+b <= 32769)
+ {
+ /* We allow 0 coefficients here. r+g+b may be 32769 if two or
+ * all of the coefficients were rounded up. Handle this by
+ * reducing the *largest* coefficient by 1; this matches the
+ * approach used for the default coefficients in pngrtran.c
+ */
+ int add = 0;
+
+ if (r+g+b > 32768)
+ add = -1;
+ else if (r+g+b < 32768)
+ add = 1;
+
+ if (add != 0)
+ {
+ if (g >= r && g >= b)
+ g += add;
+ else if (r >= g && r >= b)
+ r += add;
+ else
+ b += add;
+ }
+
+ /* Check for an internal error. */
+ if (r+g+b != 32768)
+ png_error(png_ptr,
+ "internal error handling cHRM coefficients");
+
+ else
+ {
+ png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
+ png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
+ }
+ }
+
+ /* This is a png_error at present even though it could be ignored -
+ * it should never happen, but it is important that if it does, the
+ * bug is fixed.
+ */
+ else
+ png_error(png_ptr, "internal error handling cHRM->XYZ");
+ }
+}
+#endif /* READ_RGB_TO_GRAY */
+
+#endif /* COLORSPACE */
+
+void /* PRIVATE */
+png_check_IHDR(png_const_structrp png_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
+{
+ int error = 0;
+
+ /* Check for width and height valid values */
+ if (width == 0)
+ {
+ png_warning(png_ptr, "Image width is zero in IHDR");
+ error = 1;
+ }
+
+ if (width > PNG_UINT_31_MAX)
+ {
+ png_warning(png_ptr, "Invalid image width in IHDR");
+ error = 1;
+ }
+
+ /* The bit mask on the first line below must be at least as big as a
+ * png_uint_32. "~7U" is not adequate on 16-bit systems because it will
+ * be an unsigned 16-bit value. Casting to (png_alloc_size_t) makes the
+ * type of the result at least as bit (in bits) as the RHS of the > operator
+ * which also avoids a common warning on 64-bit systems that the comparison
+ * of (png_uint_32) against the constant value on the RHS will always be
+ * false.
+ */
+ if (((width + 7) & ~(png_alloc_size_t)7) >
+ (((PNG_SIZE_MAX
+ - 48 /* big_row_buf hack */
+ - 1) /* filter byte */
+ / 8) /* 8-byte RGBA pixels */
+ - 1)) /* extra max_pixel_depth pad */
+ {
+ /* The size of the row must be within the limits of this architecture.
+ * Because the read code can perform arbitrary transformations the
+ * maximum size is checked here. Because the code in png_read_start_row
+ * adds extra space "for safety's sake" in several places a conservative
+ * limit is used here.
+ *
+ * NOTE: it would be far better to check the size that is actually used,
+ * but the effect in the real world is minor and the changes are more
+ * extensive, therefore much more dangerous and much more difficult to
+ * write in a way that avoids compiler warnings.
+ */
+ png_warning(png_ptr, "Image width is too large for this architecture");
+ error = 1;
+ }
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (width > png_ptr->user_width_max)
+#else
+ if (width > PNG_USER_WIDTH_MAX)
+#endif
+ {
+ png_warning(png_ptr, "Image width exceeds user limit in IHDR");
+ error = 1;
+ }
+
+ if (height == 0)
+ {
+ png_warning(png_ptr, "Image height is zero in IHDR");
+ error = 1;
+ }
+
+ if (height > PNG_UINT_31_MAX)
+ {
+ png_warning(png_ptr, "Invalid image height in IHDR");
+ error = 1;
+ }
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (height > png_ptr->user_height_max)
+#else
+ if (height > PNG_USER_HEIGHT_MAX)
+#endif
+ {
+ png_warning(png_ptr, "Image height exceeds user limit in IHDR");
+ error = 1;
+ }
+
+ /* Check other values */
+ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+ bit_depth != 8 && bit_depth != 16)
+ {
+ png_warning(png_ptr, "Invalid bit depth in IHDR");
+ error = 1;
+ }
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ {
+ png_warning(png_ptr, "Invalid color type in IHDR");
+ error = 1;
+ }
+
+ if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
+ ((color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
+ {
+ png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
+ error = 1;
+ }
+
+ if (interlace_type >= PNG_INTERLACE_LAST)
+ {
+ png_warning(png_ptr, "Unknown interlace method in IHDR");
+ error = 1;
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Unknown compression method in IHDR");
+ error = 1;
+ }
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ /* Accept filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not read a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 &&
+ png_ptr->mng_features_permitted != 0)
+ png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
+
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
+ ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
+ {
+ png_warning(png_ptr, "Unknown filter method in IHDR");
+ error = 1;
+ }
+
+ if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0)
+ {
+ png_warning(png_ptr, "Invalid filter method in IHDR");
+ error = 1;
+ }
+ }
+
+#else
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Unknown filter method in IHDR");
+ error = 1;
+ }
+#endif
+
+ if (error == 1)
+ png_error(png_ptr, "Invalid IHDR data");
+}
+
+#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
+/* ASCII to fp functions */
+/* Check an ASCII formatted floating point value, see the more detailed
+ * comments in pngpriv.h
+ */
+/* The following is used internally to preserve the sticky flags */
+#define png_fp_add(state, flags) ((state) |= (flags))
+#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))
+
+int /* PRIVATE */
+png_check_fp_number(png_const_charp string, size_t size, int *statep,
+ size_t *whereami)
+{
+ int state = *statep;
+ size_t i = *whereami;
+
+ while (i < size)
+ {
+ int type;
+ /* First find the type of the next character */
+ switch (string[i])
+ {
+ case 43: type = PNG_FP_SAW_SIGN; break;
+ case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;
+ case 46: type = PNG_FP_SAW_DOT; break;
+ case 48: type = PNG_FP_SAW_DIGIT; break;
+ case 49: case 50: case 51: case 52:
+ case 53: case 54: case 55: case 56:
+ case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;
+ case 69:
+ case 101: type = PNG_FP_SAW_E; break;
+ default: goto PNG_FP_End;
+ }
+
+ /* Now deal with this type according to the current
+ * state, the type is arranged to not overlap the
+ * bits of the PNG_FP_STATE.
+ */
+ switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY))
+ {
+ case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:
+ if ((state & PNG_FP_SAW_ANY) != 0)
+ goto PNG_FP_End; /* not a part of the number */
+
+ png_fp_add(state, type);
+ break;
+
+ case PNG_FP_INTEGER + PNG_FP_SAW_DOT:
+ /* Ok as trailer, ok as lead of fraction. */
+ if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */
+ goto PNG_FP_End;
+
+ else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */
+ png_fp_add(state, type);
+
+ else
+ png_fp_set(state, PNG_FP_FRACTION | type);
+
+ break;
+
+ case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT:
+ if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */
+ png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
+
+ png_fp_add(state, type | PNG_FP_WAS_VALID);
+
+ break;
+
+ case PNG_FP_INTEGER + PNG_FP_SAW_E:
+ if ((state & PNG_FP_SAW_DIGIT) == 0)
+ goto PNG_FP_End;
+
+ png_fp_set(state, PNG_FP_EXPONENT);
+
+ break;
+
+ /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN:
+ goto PNG_FP_End; ** no sign in fraction */
+
+ /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT:
+ goto PNG_FP_End; ** Because SAW_DOT is always set */
+
+ case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT:
+ png_fp_add(state, type | PNG_FP_WAS_VALID);
+ break;
+
+ case PNG_FP_FRACTION + PNG_FP_SAW_E:
+ /* This is correct because the trailing '.' on an
+ * integer is handled above - so we can only get here
+ * with the sequence ".E" (with no preceding digits).
+ */
+ if ((state & PNG_FP_SAW_DIGIT) == 0)
+ goto PNG_FP_End;
+
+ png_fp_set(state, PNG_FP_EXPONENT);
+
+ break;
+
+ case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN:
+ if ((state & PNG_FP_SAW_ANY) != 0)
+ goto PNG_FP_End; /* not a part of the number */
+
+ png_fp_add(state, PNG_FP_SAW_SIGN);
+
+ break;
+
+ /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT:
+ goto PNG_FP_End; */
+
+ case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT:
+ png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);
+
+ break;
+
+ /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E:
+ goto PNG_FP_End; */
+
+ default: goto PNG_FP_End; /* I.e. break 2 */
+ }
+
+ /* The character seems ok, continue. */
+ ++i;
+ }
+
+PNG_FP_End:
+ /* Here at the end, update the state and return the correct
+ * return code.
+ */
+ *statep = state;
+ *whereami = i;
+
+ return (state & PNG_FP_SAW_DIGIT) != 0;
+}
+
+
+/* The same but for a complete string. */
+int
+png_check_fp_string(png_const_charp string, size_t size)
+{
+ int state=0;
+ size_t char_index=0;
+
+ if (png_check_fp_number(string, size, &state, &char_index) != 0 &&
+ (char_index == size || string[char_index] == 0))
+ return state /* must be non-zero - see above */;
+
+ return 0; /* i.e. fail */
+}
+#endif /* pCAL || sCAL */
+
+#ifdef PNG_sCAL_SUPPORTED
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+/* Utility used below - a simple accurate power of ten from an integral
+ * exponent.
+ */
+static double
+png_pow10(int power)
+{
+ int recip = 0;
+ double d = 1;
+
+ /* Handle negative exponent with a reciprocal at the end because
+ * 10 is exact whereas .1 is inexact in base 2
+ */
+ if (power < 0)
+ {
+ if (power < DBL_MIN_10_EXP) return 0;
+ recip = 1; power = -power;
+ }
+
+ if (power > 0)
+ {
+ /* Decompose power bitwise. */
+ double mult = 10;
+ do
+ {
+ if (power & 1) d *= mult;
+ mult *= mult;
+ power >>= 1;
+ }
+ while (power > 0);
+
+ if (recip != 0) d = 1/d;
+ }
+ /* else power is 0 and d is 1 */
+
+ return d;
+}
+
+/* Function to format a floating point value in ASCII with a given
+ * precision.
+ */
+void /* PRIVATE */
+png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,
+ double fp, unsigned int precision)
+{
+ /* We use standard functions from math.h, but not printf because
+ * that would require stdio. The caller must supply a buffer of
+ * sufficient size or we will png_error. The tests on size and
+ * the space in ascii[] consumed are indicated below.
+ */
+ if (precision < 1)
+ precision = DBL_DIG;
+
+ /* Enforce the limit of the implementation precision too. */
+ if (precision > DBL_DIG+1)
+ precision = DBL_DIG+1;
+
+ /* Basic sanity checks */
+ if (size >= precision+5) /* See the requirements below. */
+ {
+ if (fp < 0)
+ {
+ fp = -fp;
+ *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */
+ --size;
+ }
+
+ if (fp >= DBL_MIN && fp <= DBL_MAX)
+ {
+ int exp_b10; /* A base 10 exponent */
+ double base; /* 10^exp_b10 */
+
+ /* First extract a base 10 exponent of the number,
+ * the calculation below rounds down when converting
+ * from base 2 to base 10 (multiply by log10(2) -
+ * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
+ * be increased. Note that the arithmetic shift
+ * performs a floor() unlike C arithmetic - using a
+ * C multiply would break the following for negative
+ * exponents.
+ */
+ (void)frexp(fp, &exp_b10); /* exponent to base 2 */
+
+ exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */
+
+ /* Avoid underflow here. */
+ base = png_pow10(exp_b10); /* May underflow */
+
+ while (base < DBL_MIN || base < fp)
+ {
+ /* And this may overflow. */
+ double test = png_pow10(exp_b10+1);
+
+ if (test <= DBL_MAX)
+ {
+ ++exp_b10; base = test;
+ }
+
+ else
+ break;
+ }
+
+ /* Normalize fp and correct exp_b10, after this fp is in the
+ * range [.1,1) and exp_b10 is both the exponent and the digit
+ * *before* which the decimal point should be inserted
+ * (starting with 0 for the first digit). Note that this
+ * works even if 10^exp_b10 is out of range because of the
+ * test on DBL_MAX above.
+ */
+ fp /= base;
+ while (fp >= 1)
+ {
+ fp /= 10; ++exp_b10;
+ }
+
+ /* Because of the code above fp may, at this point, be
+ * less than .1, this is ok because the code below can
+ * handle the leading zeros this generates, so no attempt
+ * is made to correct that here.
+ */
+
+ {
+ unsigned int czero, clead, cdigits;
+ char exponent[10];
+
+ /* Allow up to two leading zeros - this will not lengthen
+ * the number compared to using E-n.
+ */
+ if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
+ {
+ czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */
+ exp_b10 = 0; /* Dot added below before first output. */
+ }
+ else
+ czero = 0; /* No zeros to add */
+
+ /* Generate the digit list, stripping trailing zeros and
+ * inserting a '.' before a digit if the exponent is 0.
+ */
+ clead = czero; /* Count of leading zeros */
+ cdigits = 0; /* Count of digits in list. */
+
+ do
+ {
+ double d;
+
+ fp *= 10;
+ /* Use modf here, not floor and subtract, so that
+ * the separation is done in one step. At the end
+ * of the loop don't break the number into parts so
+ * that the final digit is rounded.
+ */
+ if (cdigits+czero+1 < precision+clead)
+ fp = modf(fp, &d);
+
+ else
+ {
+ d = floor(fp + .5);
+
+ if (d > 9)
+ {
+ /* Rounding up to 10, handle that here. */
+ if (czero > 0)
+ {
+ --czero; d = 1;
+ if (cdigits == 0) --clead;
+ }
+ else
+ {
+ while (cdigits > 0 && d > 9)
+ {
+ int ch = *--ascii;
+
+ if (exp_b10 != (-1))
+ ++exp_b10;
+
+ else if (ch == 46)
+ {
+ ch = *--ascii; ++size;
+ /* Advance exp_b10 to '1', so that the
+ * decimal point happens after the
+ * previous digit.
+ */
+ exp_b10 = 1;
+ }
+
+ --cdigits;
+ d = ch - 47; /* I.e. 1+(ch-48) */
+ }
+
+ /* Did we reach the beginning? If so adjust the
+ * exponent but take into account the leading
+ * decimal point.
+ */
+ if (d > 9) /* cdigits == 0 */
+ {
+ if (exp_b10 == (-1))
+ {
+ /* Leading decimal point (plus zeros?), if
+ * we lose the decimal point here it must
+ * be reentered below.
+ */
+ int ch = *--ascii;
+
+ if (ch == 46)
+ {
+ ++size; exp_b10 = 1;
+ }
+
+ /* Else lost a leading zero, so 'exp_b10' is
+ * still ok at (-1)
+ */
+ }
+ else
+ ++exp_b10;
+
+ /* In all cases we output a '1' */
+ d = 1;
+ }
+ }
+ }
+ fp = 0; /* Guarantees termination below. */
+ }
+
+ if (d == 0)
+ {
+ ++czero;
+ if (cdigits == 0) ++clead;
+ }
+ else
+ {
+ /* Included embedded zeros in the digit count. */
+ cdigits += czero - clead;
+ clead = 0;
+
+ while (czero > 0)
+ {
+ /* exp_b10 == (-1) means we just output the decimal
+ * place - after the DP don't adjust 'exp_b10' any
+ * more!
+ */
+ if (exp_b10 != (-1))
+ {
+ if (exp_b10 == 0)
+ {
+ *ascii++ = 46; --size;
+ }
+ /* PLUS 1: TOTAL 4 */
+ --exp_b10;
+ }
+ *ascii++ = 48; --czero;
+ }
+
+ if (exp_b10 != (-1))
+ {
+ if (exp_b10 == 0)
+ {
+ *ascii++ = 46; --size; /* counted above */
+ }
+
+ --exp_b10;
+ }
+ *ascii++ = (char)(48 + (int)d); ++cdigits;
+ }
+ }
+ while (cdigits+czero < precision+clead && fp > DBL_MIN);
+
+ /* The total output count (max) is now 4+precision */
+
+ /* Check for an exponent, if we don't need one we are
+ * done and just need to terminate the string. At this
+ * point, exp_b10==(-1) is effectively a flag: it got
+ * to '-1' because of the decrement, after outputting
+ * the decimal point above. (The exponent required is
+ * *not* -1.)
+ */
+ if (exp_b10 >= (-1) && exp_b10 <= 2)
+ {
+ /* The following only happens if we didn't output the
+ * leading zeros above for negative exponent, so this
+ * doesn't add to the digit requirement. Note that the
+ * two zeros here can only be output if the two leading
+ * zeros were *not* output, so this doesn't increase
+ * the output count.
+ */
+ while (exp_b10-- > 0) *ascii++ = 48;
+
+ *ascii = 0;
+
+ /* Total buffer requirement (including the '\0') is
+ * 5+precision - see check at the start.
+ */
+ return;
+ }
+
+ /* Here if an exponent is required, adjust size for
+ * the digits we output but did not count. The total
+ * digit output here so far is at most 1+precision - no
+ * decimal point and no leading or trailing zeros have
+ * been output.
+ */
+ size -= cdigits;
+
+ *ascii++ = 69; --size; /* 'E': PLUS 1 TOTAL 2+precision */
+
+ /* The following use of an unsigned temporary avoids ambiguities in
+ * the signed arithmetic on exp_b10 and permits GCC at least to do
+ * better optimization.
+ */
+ {
+ unsigned int uexp_b10;
+
+ if (exp_b10 < 0)
+ {
+ *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */
+ uexp_b10 = 0U-exp_b10;
+ }
+
+ else
+ uexp_b10 = 0U+exp_b10;
+
+ cdigits = 0;
+
+ while (uexp_b10 > 0)
+ {
+ exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
+ uexp_b10 /= 10;
+ }
+ }
+
+ /* Need another size check here for the exponent digits, so
+ * this need not be considered above.
+ */
+ if (size > cdigits)
+ {
+ while (cdigits > 0) *ascii++ = exponent[--cdigits];
+
+ *ascii = 0;
+
+ return;
+ }
+ }
+ }
+ else if (!(fp >= DBL_MIN))
+ {
+ *ascii++ = 48; /* '0' */
+ *ascii = 0;
+ return;
+ }
+ else
+ {
+ *ascii++ = 105; /* 'i' */
+ *ascii++ = 110; /* 'n' */
+ *ascii++ = 102; /* 'f' */
+ *ascii = 0;
+ return;
+ }
+ }
+
+ /* Here on buffer too small. */
+ png_error(png_ptr, "ASCII conversion buffer too small");
+}
+# endif /* FLOATING_POINT */
+
+# ifdef PNG_FIXED_POINT_SUPPORTED
+/* Function to format a fixed point value in ASCII.
+ */
+void /* PRIVATE */
+png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,
+ size_t size, png_fixed_point fp)
+{
+ /* Require space for 10 decimal digits, a decimal point, a minus sign and a
+ * trailing \0, 13 characters:
+ */
+ if (size > 12)
+ {
+ png_uint_32 num;
+
+ /* Avoid overflow here on the minimum integer. */
+ if (fp < 0)
+ {
+ *ascii++ = 45; num = (png_uint_32)(-fp);
+ }
+ else
+ num = (png_uint_32)fp;
+
+ if (num <= 0x80000000) /* else overflowed */
+ {
+ unsigned int ndigits = 0, first = 16 /* flag value */;
+ char digits[10] = {0};
+
+ while (num)
+ {
+ /* Split the low digit off num: */
+ unsigned int tmp = num/10;
+ num -= tmp*10;
+ digits[ndigits++] = (char)(48 + num);
+ /* Record the first non-zero digit, note that this is a number
+ * starting at 1, it's not actually the array index.
+ */
+ if (first == 16 && num > 0)
+ first = ndigits;
+ num = tmp;
+ }
+
+ if (ndigits > 0)
+ {
+ while (ndigits > 5) *ascii++ = digits[--ndigits];
+ /* The remaining digits are fractional digits, ndigits is '5' or
+ * smaller at this point. It is certainly not zero. Check for a
+ * non-zero fractional digit:
+ */
+ if (first <= 5)
+ {
+ unsigned int i;
+ *ascii++ = 46; /* decimal point */
+ /* ndigits may be <5 for small numbers, output leading zeros
+ * then ndigits digits to first:
+ */
+ i = 5;
+ while (ndigits < i)
+ {
+ *ascii++ = 48; --i;
+ }
+ while (ndigits >= first) *ascii++ = digits[--ndigits];
+ /* Don't output the trailing zeros! */
+ }
+ }
+ else
+ *ascii++ = 48;
+
+ /* And null terminate the string: */
+ *ascii = 0;
+ return;
+ }
+ }
+
+ /* Here on buffer too small. */
+ png_error(png_ptr, "ASCII conversion buffer too small");
+}
+# endif /* FIXED_POINT */
+#endif /* SCAL */
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
+ !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_READ_RGB_TO_GRAY_SUPPORTED)) || \
+ (defined(PNG_sCAL_SUPPORTED) && \
+ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
+png_fixed_point
+png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
+{
+ double r = floor(100000 * fp + .5);
+
+ if (r > 2147483647. || r < -2147483648.)
+ png_fixed_error(png_ptr, text);
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(text)
+# endif
+
+ return (png_fixed_point)r;
+}
+#endif
+
+#if defined(PNG_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
+ * integer (or, for a fixed point number - the standard argument - to
+ * the nearest .00001). Overflow and divide by zero are signalled in
+ * the result, a boolean - true on success, false on overflow.
+ */
+int
+png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
+ png_int_32 divisor)
+{
+ /* Return a * times / divisor, rounded. */
+ if (divisor != 0)
+ {
+ if (a == 0 || times == 0)
+ {
+ *res = 0;
+ return 1;
+ }
+ else
+ {
+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ double r = a;
+ r *= times;
+ r /= divisor;
+ r = floor(r+.5);
+
+ /* A png_fixed_point is a 32-bit integer. */
+ if (r <= 2147483647. && r >= -2147483648.)
+ {
+ *res = (png_fixed_point)r;
+ return 1;
+ }
+#else
+ int negative = 0;
+ png_uint_32 A, T, D;
+ png_uint_32 s16, s32, s00;
+
+ if (a < 0)
+ negative = 1, A = -a;
+ else
+ A = a;
+
+ if (times < 0)
+ negative = !negative, T = -times;
+ else
+ T = times;
+
+ if (divisor < 0)
+ negative = !negative, D = -divisor;
+ else
+ D = divisor;
+
+ /* Following can't overflow because the arguments only
+ * have 31 bits each, however the result may be 32 bits.
+ */
+ s16 = (A >> 16) * (T & 0xffff) +
+ (A & 0xffff) * (T >> 16);
+ /* Can't overflow because the a*times bit is only 30
+ * bits at most.
+ */
+ s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
+ s00 = (A & 0xffff) * (T & 0xffff);
+
+ s16 = (s16 & 0xffff) << 16;
+ s00 += s16;
+
+ if (s00 < s16)
+ ++s32; /* carry */
+
+ if (s32 < D) /* else overflow */
+ {
+ /* s32.s00 is now the 64-bit product, do a standard
+ * division, we know that s32 < D, so the maximum
+ * required shift is 31.
+ */
+ int bitshift = 32;
+ png_fixed_point result = 0; /* NOTE: signed */
+
+ while (--bitshift >= 0)
+ {
+ png_uint_32 d32, d00;
+
+ if (bitshift > 0)
+ d32 = D >> (32-bitshift), d00 = D << bitshift;
+
+ else
+ d32 = 0, d00 = D;
+
+ if (s32 > d32)
+ {
+ if (s00 < d00) --s32; /* carry */
+ s32 -= d32, s00 -= d00, result += 1<= d00)
+ s32 = 0, s00 -= d00, result += 1<= (D >> 1))
+ ++result;
+
+ if (negative != 0)
+ result = -result;
+
+ /* Check for overflow. */
+ if ((negative != 0 && result <= 0) ||
+ (negative == 0 && result >= 0))
+ {
+ *res = result;
+ return 1;
+ }
+ }
+#endif
+ }
+ }
+
+ 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)
+{
+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ double r = floor(1E10/a+.5);
+
+ if (r <= 2147483647. && r >= -2147483648.)
+ return (png_fixed_point)r;
+#else
+ png_fixed_point res;
+
+ if (png_muldiv(&res, 100000, 100000, a) != 0)
+ return res;
+#endif
+
+ return 0; /* error/overflow */
+}
+
+/* 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)
+{
+ 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
+/* 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
+ double r = a * 1E-5;
+ r *= b;
+ r = floor(r+.5);
+
+ if (r <= 2147483647. && r >= -2147483648.)
+ return (png_fixed_point)r;
+#else
+ png_fixed_point res;
+
+ if (png_muldiv(&res, a, b, 100000) != 0)
+ return res;
+#endif
+
+ return 0; /* overflow */
+}
+#endif /* 16BIT */
+
+/* The inverse of the above. */
+png_fixed_point
+png_reciprocal2(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
+ if (a != 0 && b != 0)
+ {
+ double r = 1E15/a;
+ r /= b;
+ r = floor(r+.5);
+
+ if (r <= 2147483647. && r >= -2147483648.)
+ return (png_fixed_point)r;
+ }
+#else
+ /* This may overflow because the range of png_fixed_point isn't symmetric,
+ * but this API is only used for the product of file and screen gamma so it
+ * doesn't matter that the smallest number it can produce is 1/21474, not
+ * 1/100000
+ */
+ png_fixed_point res = png_product2(a, b);
+
+ if (res != 0)
+ return png_reciprocal(res);
+#endif
+
+ return 0; /* overflow */
+}
+#endif /* READ_GAMMA */
+
+#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
+#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
+/* Fixed point gamma.
+ *
+ * The code to calculate the tables used below can be found in the shell script
+ * contrib/tools/intgamma.sh
+ *
+ * To calculate gamma this code implements fast log() and exp() calls using only
+ * fixed point arithmetic. This code has sufficient precision for either 8-bit
+ * or 16-bit sample values.
+ *
+ * The tables used here were calculated using simple 'bc' programs, but C double
+ * precision floating point arithmetic would work fine.
+ *
+ * 8-bit log table
+ * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
+ * 255, so it's the base 2 logarithm of a normalized 8-bit floating point
+ * mantissa. The numbers are 32-bit fractions.
+ */
+static const png_uint_32
+png_8bit_l2[128] =
+{
+ 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
+ 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
+ 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
+ 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
+ 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
+ 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
+ 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
+ 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
+ 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
+ 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
+ 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
+ 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
+ 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
+ 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
+ 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
+ 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
+ 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
+ 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
+ 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
+ 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
+ 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
+ 24347096U, 0U
+
+#if 0
+ /* The following are the values for 16-bit tables - these work fine for the
+ * 8-bit conversions but produce very slightly larger errors in the 16-bit
+ * log (about 1.2 as opposed to 0.7 absolute error in the final value). To
+ * use these all the shifts below must be adjusted appropriately.
+ */
+ 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
+ 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
+ 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
+ 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
+ 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
+ 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
+ 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
+ 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
+ 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
+ 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
+ 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
+ 1119, 744, 372
+#endif
+};
+
+static png_int_32
+png_log8bit(unsigned int x)
+{
+ unsigned int lg2 = 0;
+ /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
+ * because the log is actually negate that means adding 1. The final
+ * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
+ * input), return -1 for the overflow (log 0) case, - so the result is
+ * always at most 19 bits.
+ */
+ if ((x &= 0xff) == 0)
+ return -1;
+
+ if ((x & 0xf0) == 0)
+ lg2 = 4, x <<= 4;
+
+ if ((x & 0xc0) == 0)
+ lg2 += 2, x <<= 2;
+
+ if ((x & 0x80) == 0)
+ lg2 += 1, x <<= 1;
+
+ /* result is at most 19 bits, so this cast is safe: */
+ return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
+}
+
+/* The above gives exact (to 16 binary places) log2 values for 8-bit images,
+ * for 16-bit images we use the most significant 8 bits of the 16-bit value to
+ * get an approximation then multiply the approximation by a correction factor
+ * determined by the remaining up to 8 bits. This requires an additional step
+ * in the 16-bit case.
+ *
+ * We want log2(value/65535), we have log2(v'/255), where:
+ *
+ * value = v' * 256 + v''
+ * = v' * f
+ *
+ * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
+ * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
+ * than 258. The final factor also needs to correct for the fact that our 8-bit
+ * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
+ *
+ * This gives a final formula using a calculated value 'x' which is value/v' and
+ * scaling by 65536 to match the above table:
+ *
+ * log2(x/257) * 65536
+ *
+ * Since these numbers are so close to '1' we can use simple linear
+ * interpolation between the two end values 256/257 (result -368.61) and 258/257
+ * (result 367.179). The values used below are scaled by a further 64 to give
+ * 16-bit precision in the interpolation:
+ *
+ * Start (256): -23591
+ * Zero (257): 0
+ * End (258): 23499
+ */
+#ifdef PNG_16BIT_SUPPORTED
+static png_int_32
+png_log16bit(png_uint_32 x)
+{
+ unsigned int lg2 = 0;
+
+ /* As above, but now the input has 16 bits. */
+ if ((x &= 0xffff) == 0)
+ return -1;
+
+ if ((x & 0xff00) == 0)
+ lg2 = 8, x <<= 8;
+
+ if ((x & 0xf000) == 0)
+ lg2 += 4, x <<= 4;
+
+ if ((x & 0xc000) == 0)
+ lg2 += 2, x <<= 2;
+
+ if ((x & 0x8000) == 0)
+ lg2 += 1, x <<= 1;
+
+ /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
+ * value.
+ */
+ lg2 <<= 28;
+ lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
+
+ /* Now we need to interpolate the factor, this requires a division by the top
+ * 8 bits. Do this with maximum precision.
+ */
+ x = ((x << 16) + (x >> 9)) / (x >> 8);
+
+ /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
+ * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
+ * 16 bits to interpolate to get the low bits of the result. Round the
+ * answer. Note that the end point values are scaled by 64 to retain overall
+ * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
+ * the overall scaling by 6-12. Round at every step.
+ */
+ x -= 1U << 24;
+
+ if (x <= 65536U) /* <= '257' */
+ lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
+
+ else
+ lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
+
+ /* Safe, because the result can't have more than 20 bits: */
+ return (png_int_32)((lg2 + 2048) >> 12);
+}
+#endif /* 16BIT */
+
+/* The 'exp()' case must invert the above, taking a 20-bit fixed point
+ * logarithmic value and returning a 16 or 8-bit number as appropriate. In
+ * each case only the low 16 bits are relevant - the fraction - since the
+ * integer bits (the top 4) simply determine a shift.
+ *
+ * The worst case is the 16-bit distinction between 65535 and 65534. This
+ * requires perhaps spurious accuracy in the decoding of the logarithm to
+ * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance
+ * of getting this accuracy in practice.
+ *
+ * To deal with this the following exp() function works out the exponent of the
+ * fractional part of the logarithm by using an accurate 32-bit value from the
+ * top four fractional bits then multiplying in the remaining bits.
+ */
+static const png_uint_32
+png_32bit_exp[16] =
+{
+ /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
+ 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
+ 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
+ 2553802834U, 2445529972U, 2341847524U, 2242560872U
+};
+
+/* Adjustment table; provided to explain the numbers in the code below. */
+#if 0
+for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
+ 11 44937.64284865548751208448
+ 10 45180.98734845585101160448
+ 9 45303.31936980687359311872
+ 8 45364.65110595323018870784
+ 7 45395.35850361789624614912
+ 6 45410.72259715102037508096
+ 5 45418.40724413220722311168
+ 4 45422.25021786898173001728
+ 3 45424.17186732298419044352
+ 2 45425.13273269940811464704
+ 1 45425.61317555035558641664
+ 0 45425.85339951654943850496
+#endif
+
+static png_uint_32
+png_exp(png_fixed_point x)
+{
+ if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
+ {
+ /* Obtain a 4-bit approximation */
+ png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f];
+
+ /* Incorporate the low 12 bits - these decrease the returned value by
+ * multiplying by a number less than 1 if the bit is set. The multiplier
+ * is determined by the above table and the shift. Notice that the values
+ * converge on 45426 and this is used to allow linear interpolation of the
+ * low bits.
+ */
+ if (x & 0x800)
+ e -= (((e >> 16) * 44938U) + 16U) >> 5;
+
+ if (x & 0x400)
+ e -= (((e >> 16) * 45181U) + 32U) >> 6;
+
+ if (x & 0x200)
+ e -= (((e >> 16) * 45303U) + 64U) >> 7;
+
+ if (x & 0x100)
+ e -= (((e >> 16) * 45365U) + 128U) >> 8;
+
+ if (x & 0x080)
+ e -= (((e >> 16) * 45395U) + 256U) >> 9;
+
+ if (x & 0x040)
+ e -= (((e >> 16) * 45410U) + 512U) >> 10;
+
+ /* And handle the low 6 bits in a single block. */
+ e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
+
+ /* Handle the upper bits of x. */
+ e >>= x >> 16;
+ return e;
+ }
+
+ /* Check for overflow */
+ if (x <= 0)
+ return png_32bit_exp[0];
+
+ /* Else underflow */
+ return 0;
+}
+
+static png_byte
+png_exp8bit(png_fixed_point lg2)
+{
+ /* Get a 32-bit value: */
+ png_uint_32 x = png_exp(lg2);
+
+ /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the
+ * second, rounding, step can't overflow because of the first, subtraction,
+ * step.
+ */
+ x -= x >> 8;
+ return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff);
+}
+
+#ifdef PNG_16BIT_SUPPORTED
+static png_uint_16
+png_exp16bit(png_fixed_point lg2)
+{
+ /* Get a 32-bit value: */
+ png_uint_32 x = png_exp(lg2);
+
+ /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
+ x -= x >> 16;
+ return (png_uint_16)((x + 32767U) >> 16);
+}
+#endif /* 16BIT */
+#endif /* FLOATING_ARITHMETIC */
+
+png_byte
+png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
+{
+ if (value > 0 && value < 255)
+ {
+# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly
+ * convert this to a floating point value. This includes values that
+ * would overflow if 'value' were to be converted to 'int'.
+ *
+ * Apparently GCC, however, does an intermediate conversion to (int)
+ * on some (ARM) but not all (x86) platforms, possibly because of
+ * hardware FP limitations. (E.g. if the hardware conversion always
+ * assumes the integer register contains a signed value.) This results
+ * in ANSI-C undefined behavior for large values.
+ *
+ * Other implementations on the same machine might actually be ANSI-C90
+ * conformant and therefore compile spurious extra code for the large
+ * values.
+ *
+ * We can be reasonably sure that an unsigned to float conversion
+ * won't be faster than an int to float one. Therefore this code
+ * assumes responsibility for the undefined behavior, which it knows
+ * can't happen because of the check above.
+ *
+ * Note the argument to this routine is an (unsigned int) because, on
+ * 16-bit platforms, it is assigned a value which might be out of
+ * range for an (int); that would result in undefined behavior in the
+ * caller if the *argument* ('value') were to be declared (int).
+ */
+ double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5);
+ return (png_byte)r;
+# else
+ png_int_32 lg2 = png_log8bit(value);
+ png_fixed_point res;
+
+ if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)
+ return png_exp8bit(res);
+
+ /* Overflow. */
+ value = 0;
+# endif
+ }
+
+ return (png_byte)(value & 0xff);
+}
+
+#ifdef PNG_16BIT_SUPPORTED
+png_uint_16
+png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
+{
+ if (value > 0 && value < 65535)
+ {
+# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ /* The same (unsigned int)->(double) constraints apply here as above,
+ * however in this case the (unsigned int) to (int) conversion can
+ * overflow on an ANSI-C90 compliant system so the cast needs to ensure
+ * that this is not possible.
+ */
+ double r = floor(65535*pow((png_int_32)value/65535.,
+ gamma_val*.00001)+.5);
+ return (png_uint_16)r;
+# else
+ png_int_32 lg2 = png_log16bit(value);
+ png_fixed_point res;
+
+ if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)
+ return png_exp16bit(res);
+
+ /* Overflow. */
+ value = 0;
+# endif
+ }
+
+ return (png_uint_16)value;
+}
+#endif /* 16BIT */
+
+/* This does the right thing based on the bit_depth field of the
+ * png_struct, interpreting values as 8-bit or 16-bit. While the result
+ * is nominally a 16-bit value if bit depth is 8 then the result is
+ * 8-bit (as are the arguments.)
+ */
+png_uint_16 /* PRIVATE */
+png_gamma_correct(png_structrp png_ptr, unsigned int value,
+ png_fixed_point gamma_val)
+{
+ if (png_ptr->bit_depth == 8)
+ return png_gamma_8bit_correct(value, gamma_val);
+
+#ifdef PNG_16BIT_SUPPORTED
+ else
+ return png_gamma_16bit_correct(value, gamma_val);
+#else
+ /* should not reach this */
+ return 0;
+#endif /* 16BIT */
+}
+
+#ifdef PNG_16BIT_SUPPORTED
+/* Internal function to build a single 16-bit table - the table consists of
+ * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
+ * to shift the input values right (or 16-number_of_signifiant_bits).
+ *
+ * The caller is responsible for ensuring that the table gets cleaned up on
+ * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
+ * should be somewhere that will be cleaned.
+ */
+static void
+png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,
+ unsigned int shift, png_fixed_point gamma_val)
+{
+ /* Various values derived from 'shift': */
+ unsigned int num = 1U << (8U - shift);
+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ /* CSE the division and work round wacky GCC warnings (see the comments
+ * in png_gamma_8bit_correct for where these come from.)
+ */
+ double fmax = 1.0 / (((png_int_32)1 << (16U - shift)) - 1);
+#endif
+ unsigned int max = (1U << (16U - shift)) - 1U;
+ unsigned int max_by_2 = 1U << (15U - shift);
+ unsigned int i;
+
+ png_uint_16pp table = *ptable =
+ (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));
+
+ for (i = 0; i < num; i++)
+ {
+ png_uint_16p sub_table = table[i] =
+ (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16)));
+
+ /* The 'threshold' test is repeated here because it can arise for one of
+ * the 16-bit tables even if the others don't hit it.
+ */
+ if (png_gamma_significant(gamma_val) != 0)
+ {
+ /* The old code would overflow at the end and this would cause the
+ * 'pow' function to return a result >1, resulting in an
+ * arithmetic error. This code follows the spec exactly; ig is
+ * the recovered input sample, it always has 8-16 bits.
+ *
+ * We want input * 65535/max, rounded, the arithmetic fits in 32
+ * bits (unsigned) so long as max <= 32767.
+ */
+ unsigned int j;
+ for (j = 0; j < 256; j++)
+ {
+ png_uint_32 ig = (j << (8-shift)) + i;
+# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ /* Inline the 'max' scaling operation: */
+ /* See png_gamma_8bit_correct for why the cast to (int) is
+ * required here.
+ */
+ double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5);
+ sub_table[j] = (png_uint_16)d;
+# else
+ if (shift != 0)
+ ig = (ig * 65535U + max_by_2)/max;
+
+ sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
+# endif
+ }
+ }
+ else
+ {
+ /* We must still build a table, but do it the fast way. */
+ unsigned int j;
+
+ for (j = 0; j < 256; j++)
+ {
+ png_uint_32 ig = (j << (8-shift)) + i;
+
+ if (shift != 0)
+ ig = (ig * 65535U + max_by_2)/max;
+
+ sub_table[j] = (png_uint_16)ig;
+ }
+ }
+ }
+}
+
+/* NOTE: this function expects the *inverse* of the overall gamma transformation
+ * required.
+ */
+static void
+png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable,
+ unsigned int shift, png_fixed_point gamma_val)
+{
+ unsigned int num = 1U << (8U - shift);
+ unsigned int max = (1U << (16U - shift))-1U;
+ unsigned int i;
+ png_uint_32 last;
+
+ png_uint_16pp table = *ptable =
+ (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));
+
+ /* 'num' is the number of tables and also the number of low bits of low
+ * bits of the input 16-bit value used to select a table. Each table is
+ * itself indexed by the high 8 bits of the value.
+ */
+ for (i = 0; i < num; i++)
+ table[i] = (png_uint_16p)png_malloc(png_ptr,
+ 256 * (sizeof (png_uint_16)));
+
+ /* 'gamma_val' is set to the reciprocal of the value calculated above, so
+ * pow(out,g) is an *input* value. 'last' is the last input value set.
+ *
+ * In the loop 'i' is used to find output values. Since the output is
+ * 8-bit there are only 256 possible values. The tables are set up to
+ * select the closest possible output value for each input by finding
+ * the input value at the boundary between each pair of output values
+ * and filling the table up to that boundary with the lower output
+ * value.
+ *
+ * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit
+ * values the code below uses a 16-bit value in i; the values start at
+ * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
+ * entries are filled with 255). Start i at 128 and fill all 'last'
+ * table entries <= 'max'
+ */
+ last = 0;
+ for (i = 0; i < 255; ++i) /* 8-bit output value */
+ {
+ /* Find the corresponding maximum input value */
+ png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */
+
+ /* Find the boundary value in 16 bits: */
+ png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
+
+ /* Adjust (round) to (16-shift) bits: */
+ bound = (bound * max + 32768U)/65535U + 1U;
+
+ while (last < bound)
+ {
+ table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
+ last++;
+ }
+ }
+
+ /* And fill in the final entries. */
+ while (last < (num << 8))
+ {
+ table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
+ last++;
+ }
+}
+#endif /* 16BIT */
+
+/* Build a single 8-bit table: same as the 16-bit case but much simpler (and
+ * typically much faster). Note that libpng currently does no sBIT processing
+ * (apparently contrary to the spec) so a 256-entry table is always generated.
+ */
+static void
+png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable,
+ png_fixed_point gamma_val)
+{
+ unsigned int i;
+ png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
+
+ if (png_gamma_significant(gamma_val) != 0)
+ for (i=0; i<256; i++)
+ table[i] = png_gamma_8bit_correct(i, gamma_val);
+
+ else
+ for (i=0; i<256; ++i)
+ table[i] = (png_byte)(i & 0xff);
+}
+
+/* Used from png_read_destroy and below to release the memory used by the gamma
+ * tables.
+ */
+void /* PRIVATE */
+png_destroy_gamma_table(png_structrp png_ptr)
+{
+ png_free(png_ptr, png_ptr->gamma_table);
+ png_ptr->gamma_table = NULL;
+
+#ifdef PNG_16BIT_SUPPORTED
+ if (png_ptr->gamma_16_table != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ png_ptr->gamma_16_table = NULL;
+ }
+#endif /* 16BIT */
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_ptr->gamma_from_1 = NULL;
+ png_free(png_ptr, png_ptr->gamma_to_1);
+ png_ptr->gamma_to_1 = NULL;
+
+#ifdef PNG_16BIT_SUPPORTED
+ if (png_ptr->gamma_16_from_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_from_1);
+ png_ptr->gamma_16_from_1 = NULL;
+ }
+ if (png_ptr->gamma_16_to_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+ png_ptr->gamma_16_to_1 = NULL;
+ }
+#endif /* 16BIT */
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
+}
+
+/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
+ * 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.
+ */
+void /* PRIVATE */
+png_build_gamma_table(png_structrp png_ptr, int bit_depth)
+{
+ png_debug(1, "in png_build_gamma_table");
+
+ /* Remove any existing table; this copes with multiple calls to
+ * png_read_update_info. The warning is because building the gamma tables
+ * multiple times is a performance hit - it's harmless but the ability to
+ * call png_read_update_info() multiple times is new in 1.5.6 so it seems
+ * sensible to warn if the app introduces such a hit.
+ */
+ if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL)
+ {
+ png_warning(png_ptr, "gamma table being rebuilt");
+ png_destroy_gamma_table(png_ptr);
+ }
+
+ 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);
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ 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_from_1,
+ png_ptr->screen_gamma > 0 ?
+ png_reciprocal(png_ptr->screen_gamma) :
+ png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
+ }
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
+ }
+#ifdef PNG_16BIT_SUPPORTED
+ else
+ {
+ png_byte shift, sig_bit;
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+ {
+ sig_bit = png_ptr->sig_bit.red;
+
+ if (png_ptr->sig_bit.green > sig_bit)
+ sig_bit = png_ptr->sig_bit.green;
+
+ if (png_ptr->sig_bit.blue > sig_bit)
+ sig_bit = png_ptr->sig_bit.blue;
+ }
+ else
+ sig_bit = png_ptr->sig_bit.gray;
+
+ /* 16-bit gamma code uses this equation:
+ *
+ * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
+ *
+ * Where 'iv' is the input color value and 'ov' is the output value -
+ * pow(iv, gamma).
+ *
+ * Thus the gamma table consists of up to 256 256-entry tables. The table
+ * is selected by the (8-gamma_shift) most significant of the low 8 bits
+ * of the color value then indexed by the upper 8 bits:
+ *
+ * table[low bits][high 8 bits]
+ *
+ * So the table 'n' corresponds to all those 'iv' of:
+ *
+ * ..<(n+1 << gamma_shift)-1>
+ *
+ */
+ if (sig_bit > 0 && sig_bit < 16U)
+ /* shift == insignificant bits */
+ shift = (png_byte)((16U - sig_bit) & 0xff);
+
+ else
+ shift = 0; /* keep all 16 bits */
+
+ if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)
+ {
+ /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
+ * the significant bits in the *input* when the output will
+ * eventually be 8 bits. By default it is 11.
+ */
+ if (shift < (16U - PNG_MAX_GAMMA_8))
+ shift = (16U - PNG_MAX_GAMMA_8);
+ }
+
+ if (shift > 8U)
+ shift = 8U; /* Guarantees at least one table! */
+
+ png_ptr->gamma_shift = shift;
+
+ /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now
+ * PNG_COMPOSE). This effectively smashed the background calculation for
+ * 16-bit output because the 8-bit table assumes the result will be
+ * 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);
+
+ 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);
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ 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));
+
+ /* 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 */);
+ }
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
+ }
+#endif /* 16BIT */
+}
+#endif /* READ_GAMMA */
+
+/* HARDWARE OR SOFTWARE OPTION SUPPORT */
+#ifdef PNG_SET_OPTION_SUPPORTED
+int PNGAPI
+png_set_option(png_structrp png_ptr, int option, int onoff)
+{
+ if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&
+ (option & 1) == 0)
+ {
+ png_uint_32 mask = 3U << option;
+ png_uint_32 setting = (2U + (onoff != 0)) << option;
+ png_uint_32 current = png_ptr->options;
+
+ png_ptr->options = (png_uint_32)((current & ~mask) | setting);
+
+ return (int)(current & mask) >> option;
+ }
+
+ return PNG_OPTION_INVALID;
+}
+#endif
+
+/* sRGB support */
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+/* sRGB conversion tables; these are machine generated with the code in
+ * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the
+ * specification (see the article at https://en.wikipedia.org/wiki/SRGB)
+ * is used, not the gamma=1/2.2 approximation use elsewhere in libpng.
+ * The sRGB to linear table is exact (to the nearest 16-bit linear fraction).
+ * The inverse (linear to sRGB) table has accuracies as follows:
+ *
+ * For all possible (255*65535+1) input values:
+ *
+ * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact
+ *
+ * For the input values corresponding to the 65536 16-bit values:
+ *
+ * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact
+ *
+ * In all cases the inexact readings are only off by one.
+ */
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+/* The convert-to-sRGB table is only currently required for read. */
+const png_uint_16 png_sRGB_table[256] =
+{
+ 0,20,40,60,80,99,119,139,
+ 159,179,199,219,241,264,288,313,
+ 340,367,396,427,458,491,526,562,
+ 599,637,677,718,761,805,851,898,
+ 947,997,1048,1101,1156,1212,1270,1330,
+ 1391,1453,1517,1583,1651,1720,1790,1863,
+ 1937,2013,2090,2170,2250,2333,2418,2504,
+ 2592,2681,2773,2866,2961,3058,3157,3258,
+ 3360,3464,3570,3678,3788,3900,4014,4129,
+ 4247,4366,4488,4611,4736,4864,4993,5124,
+ 5257,5392,5530,5669,5810,5953,6099,6246,
+ 6395,6547,6700,6856,7014,7174,7335,7500,
+ 7666,7834,8004,8177,8352,8528,8708,8889,
+ 9072,9258,9445,9635,9828,10022,10219,10417,
+ 10619,10822,11028,11235,11446,11658,11873,12090,
+ 12309,12530,12754,12980,13209,13440,13673,13909,
+ 14146,14387,14629,14874,15122,15371,15623,15878,
+ 16135,16394,16656,16920,17187,17456,17727,18001,
+ 18277,18556,18837,19121,19407,19696,19987,20281,
+ 20577,20876,21177,21481,21787,22096,22407,22721,
+ 23038,23357,23678,24002,24329,24658,24990,25325,
+ 25662,26001,26344,26688,27036,27386,27739,28094,
+ 28452,28813,29176,29542,29911,30282,30656,31033,
+ 31412,31794,32179,32567,32957,33350,33745,34143,
+ 34544,34948,35355,35764,36176,36591,37008,37429,
+ 37852,38278,38706,39138,39572,40009,40449,40891,
+ 41337,41785,42236,42690,43147,43606,44069,44534,
+ 45002,45473,45947,46423,46903,47385,47871,48359,
+ 48850,49344,49841,50341,50844,51349,51858,52369,
+ 52884,53401,53921,54445,54971,55500,56032,56567,
+ 57105,57646,58190,58737,59287,59840,60396,60955,
+ 61517,62082,62650,63221,63795,64372,64952,65535
+};
+#endif /* SIMPLIFIED_READ */
+
+/* The base/delta tables are required for both read and write (but currently
+ * only the simplified versions.)
+ */
+const png_uint_16 png_sRGB_base[512] =
+{
+ 128,1782,3383,4644,5675,6564,7357,8074,
+ 8732,9346,9921,10463,10977,11466,11935,12384,
+ 12816,13233,13634,14024,14402,14769,15125,15473,
+ 15812,16142,16466,16781,17090,17393,17690,17981,
+ 18266,18546,18822,19093,19359,19621,19879,20133,
+ 20383,20630,20873,21113,21349,21583,21813,22041,
+ 22265,22487,22707,22923,23138,23350,23559,23767,
+ 23972,24175,24376,24575,24772,24967,25160,25352,
+ 25542,25730,25916,26101,26284,26465,26645,26823,
+ 27000,27176,27350,27523,27695,27865,28034,28201,
+ 28368,28533,28697,28860,29021,29182,29341,29500,
+ 29657,29813,29969,30123,30276,30429,30580,30730,
+ 30880,31028,31176,31323,31469,31614,31758,31902,
+ 32045,32186,32327,32468,32607,32746,32884,33021,
+ 33158,33294,33429,33564,33697,33831,33963,34095,
+ 34226,34357,34486,34616,34744,34873,35000,35127,
+ 35253,35379,35504,35629,35753,35876,35999,36122,
+ 36244,36365,36486,36606,36726,36845,36964,37083,
+ 37201,37318,37435,37551,37668,37783,37898,38013,
+ 38127,38241,38354,38467,38580,38692,38803,38915,
+ 39026,39136,39246,39356,39465,39574,39682,39790,
+ 39898,40005,40112,40219,40325,40431,40537,40642,
+ 40747,40851,40955,41059,41163,41266,41369,41471,
+ 41573,41675,41777,41878,41979,42079,42179,42279,
+ 42379,42478,42577,42676,42775,42873,42971,43068,
+ 43165,43262,43359,43456,43552,43648,43743,43839,
+ 43934,44028,44123,44217,44311,44405,44499,44592,
+ 44685,44778,44870,44962,45054,45146,45238,45329,
+ 45420,45511,45601,45692,45782,45872,45961,46051,
+ 46140,46229,46318,46406,46494,46583,46670,46758,
+ 46846,46933,47020,47107,47193,47280,47366,47452,
+ 47538,47623,47709,47794,47879,47964,48048,48133,
+ 48217,48301,48385,48468,48552,48635,48718,48801,
+ 48884,48966,49048,49131,49213,49294,49376,49458,
+ 49539,49620,49701,49782,49862,49943,50023,50103,
+ 50183,50263,50342,50422,50501,50580,50659,50738,
+ 50816,50895,50973,51051,51129,51207,51285,51362,
+ 51439,51517,51594,51671,51747,51824,51900,51977,
+ 52053,52129,52205,52280,52356,52432,52507,52582,
+ 52657,52732,52807,52881,52956,53030,53104,53178,
+ 53252,53326,53400,53473,53546,53620,53693,53766,
+ 53839,53911,53984,54056,54129,54201,54273,54345,
+ 54417,54489,54560,54632,54703,54774,54845,54916,
+ 54987,55058,55129,55199,55269,55340,55410,55480,
+ 55550,55620,55689,55759,55828,55898,55967,56036,
+ 56105,56174,56243,56311,56380,56448,56517,56585,
+ 56653,56721,56789,56857,56924,56992,57059,57127,
+ 57194,57261,57328,57395,57462,57529,57595,57662,
+ 57728,57795,57861,57927,57993,58059,58125,58191,
+ 58256,58322,58387,58453,58518,58583,58648,58713,
+ 58778,58843,58908,58972,59037,59101,59165,59230,
+ 59294,59358,59422,59486,59549,59613,59677,59740,
+ 59804,59867,59930,59993,60056,60119,60182,60245,
+ 60308,60370,60433,60495,60558,60620,60682,60744,
+ 60806,60868,60930,60992,61054,61115,61177,61238,
+ 61300,61361,61422,61483,61544,61605,61666,61727,
+ 61788,61848,61909,61969,62030,62090,62150,62211,
+ 62271,62331,62391,62450,62510,62570,62630,62689,
+ 62749,62808,62867,62927,62986,63045,63104,63163,
+ 63222,63281,63340,63398,63457,63515,63574,63632,
+ 63691,63749,63807,63865,63923,63981,64039,64097,
+ 64155,64212,64270,64328,64385,64443,64500,64557,
+ 64614,64672,64729,64786,64843,64900,64956,65013,
+ 65070,65126,65183,65239,65296,65352,65409,65465
+};
+
+const png_byte png_sRGB_delta[512] =
+{
+ 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,
+ 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,
+ 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,
+ 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,
+ 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,
+ 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,
+ 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,
+ 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,
+ 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+#endif /* SIMPLIFIED READ/WRITE sRGB support */
+
+/* SIMPLIFIED READ/WRITE SUPPORT */
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+static int
+png_image_free_function(png_voidp argument)
+{
+ png_imagep image = png_voidcast(png_imagep, argument);
+ png_controlp cp = image->opaque;
+ png_control c;
+
+ /* Double check that we have a png_ptr - it should be impossible to get here
+ * without one.
+ */
+ if (cp->png_ptr == NULL)
+ return 0;
+
+ /* First free any data held in the control structure. */
+# ifdef PNG_STDIO_SUPPORTED
+ if (cp->owned_file != 0)
+ {
+ FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
+ cp->owned_file = 0;
+
+ /* Ignore errors here. */
+ if (fp != NULL)
+ {
+ cp->png_ptr->io_ptr = NULL;
+ (void)fclose(fp);
+ }
+ }
+# endif
+
+ /* Copy the control structure so that the original, allocated, version can be
+ * safely freed. Notice that a png_error here stops the remainder of the
+ * cleanup, but this is probably fine because that would indicate bad memory
+ * problems anyway.
+ */
+ c = *cp;
+ image->opaque = &c;
+ png_free(c.png_ptr, cp);
+
+ /* Then the structures, calling the correct API. */
+ if (c.for_write != 0)
+ {
+# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ png_destroy_write_struct(&c.png_ptr, &c.info_ptr);
+# else
+ png_error(c.png_ptr, "simplified write not supported");
+# endif
+ }
+ else
+ {
+# ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+ png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);
+# else
+ png_error(c.png_ptr, "simplified read not supported");
+# endif
+ }
+
+ /* Success. */
+ return 1;
+}
+
+void PNGAPI
+png_image_free(png_imagep image)
+{
+ /* Safely call the real function, but only if doing so is safe at this point
+ * (if not inside an error handling context). Otherwise assume
+ * png_safe_execute will call this API after the return.
+ */
+ if (image != NULL && image->opaque != NULL &&
+ image->opaque->error_buf == NULL)
+ {
+ png_image_free_function(image);
+ image->opaque = NULL;
+ }
+}
+
+int /* PRIVATE */
+png_image_error(png_imagep image, png_const_charp error_message)
+{
+ /* Utility to log an error. */
+ png_safecat(image->message, (sizeof image->message), 0, error_message);
+ image->warning_or_error |= PNG_IMAGE_ERROR;
+ png_image_free(image);
+ return 0;
+}
+
+#endif /* SIMPLIFIED READ/WRITE */
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngerror.c b/PDF/src/pngerror.c
index b364fc00a..29ebda794 100644
--- a/PDF/src/pngerror.c
+++ b/PDF/src/pngerror.c
@@ -1,11 +1,14 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
- * Last changed in libpng 1.2.22 [October 13, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* This file provides a location for all error handling. Users who
* need special error handling are expected to write replacement functions
@@ -13,306 +16,835 @@
* at each function.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+
+static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,
+ png_const_charp error_message)),PNG_NORETURN);
+
+#ifdef PNG_WARNINGS_SUPPORTED
static void /* PRIVATE */
-png_default_error PNGARG((png_structp png_ptr,
- png_const_charp error_message));
-#ifndef PNG_NO_WARNINGS
-static void /* PRIVATE */
-png_default_warning PNGARG((png_structp png_ptr,
- png_const_charp warning_message));
-#endif /* PNG_NO_WARNINGS */
+png_default_warning PNGARG((png_const_structrp png_ptr,
+ png_const_charp warning_message));
+#endif /* WARNINGS */
/* This function is called whenever there is a fatal error. This function
* should not be changed. If there is a need to handle errors differently,
* you should supply a replacement error function and use png_set_error_fn()
* to replace the error function at run-time.
*/
-#ifndef PNG_NO_ERROR_TEXT
-void PNGAPI
-png_error(png_structp png_ptr, png_const_charp error_message)
+#ifdef PNG_ERROR_TEXT_SUPPORTED
+PNG_FUNCTION(void,PNGAPI
+png_error,(png_const_structrp png_ptr, png_const_charp error_message),
+ PNG_NORETURN)
{
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
char msg[16];
if (png_ptr != NULL)
{
- if (png_ptr->flags&
- (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
- {
- if (*error_message == '#')
- {
- int offset;
- for (offset=1; offset<15; offset++)
- if (*(error_message+offset) == ' ')
+ if ((png_ptr->flags &
+ (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
+ {
+ if (*error_message == PNG_LITERAL_SHARP)
+ {
+ /* Strip "#nnnn " from beginning of error message. */
+ int offset;
+ for (offset = 1; offset<15; offset++)
+ if (error_message[offset] == ' ')
break;
- if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
- {
- int i;
- for (i=0; iflags&PNG_FLAG_STRIP_ERROR_TEXT)
- {
- msg[0]='0';
- msg[1]='\0';
- error_message=msg;
- }
- }
- }
+
+ if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
+ {
+ int i;
+ for (i = 0; i < offset - 1; i++)
+ msg[i] = error_message[i + 1];
+ msg[i - 1] = '\0';
+ error_message = msg;
+ }
+
+ else
+ error_message += offset;
+ }
+
+ else
+ {
+ if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
+ {
+ msg[0] = '0';
+ msg[1] = '\0';
+ error_message = msg;
+ }
+ }
+ }
}
#endif
if (png_ptr != NULL && png_ptr->error_fn != NULL)
- (*(png_ptr->error_fn))(png_ptr, error_message);
+ (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
+ error_message);
/* If the custom handler doesn't exist, or if it returns,
use the default handler, which will not return. */
png_default_error(png_ptr, error_message);
}
#else
-void PNGAPI
-png_err(png_structp png_ptr)
+PNG_FUNCTION(void,PNGAPI
+png_err,(png_const_structrp png_ptr),PNG_NORETURN)
{
+ /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
+ * erroneously as '\0', instead of the empty string "". This was
+ * apparently an error, introduced in libpng-1.2.20, and png_default_error
+ * will crash in this case.
+ */
if (png_ptr != NULL && png_ptr->error_fn != NULL)
- (*(png_ptr->error_fn))(png_ptr, '\0');
+ (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), "");
/* If the custom handler doesn't exist, or if it returns,
use the default handler, which will not return. */
- png_default_error(png_ptr, '\0');
+ png_default_error(png_ptr, "");
}
-#endif /* PNG_NO_ERROR_TEXT */
+#endif /* ERROR_TEXT */
-#ifndef PNG_NO_WARNINGS
+/* Utility to safely appends strings to a buffer. This never errors out so
+ * error checking is not required in the caller.
+ */
+size_t
+png_safecat(png_charp buffer, size_t bufsize, size_t pos,
+ png_const_charp string)
+{
+ if (buffer != NULL && pos < bufsize)
+ {
+ if (string != NULL)
+ while (*string != '\0' && pos < bufsize-1)
+ buffer[pos++] = *string++;
+
+ buffer[pos] = '\0';
+ }
+
+ return pos;
+}
+
+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Utility to dump an unsigned value into a buffer, given a start pointer and
+ * and end pointer (which should point just *beyond* the end of the buffer!)
+ * Returns the pointer to the start of the formatted string.
+ */
+png_charp
+png_format_number(png_const_charp start, png_charp end, int format,
+ png_alloc_size_t number)
+{
+ int count = 0; /* number of digits output */
+ int mincount = 1; /* minimum number required */
+ int output = 0; /* digit output (for the fixed point format) */
+
+ *--end = '\0';
+
+ /* This is written so that the loop always runs at least once, even with
+ * number zero.
+ */
+ while (end > start && (number != 0 || count < mincount))
+ {
+
+ static const char digits[] = "0123456789ABCDEF";
+
+ switch (format)
+ {
+ case PNG_NUMBER_FORMAT_fixed:
+ /* Needs five digits (the fraction) */
+ mincount = 5;
+ if (output != 0 || number % 10 != 0)
+ {
+ *--end = digits[number % 10];
+ output = 1;
+ }
+ number /= 10;
+ break;
+
+ case PNG_NUMBER_FORMAT_02u:
+ /* Expects at least 2 digits. */
+ mincount = 2;
+ /* FALLTHROUGH */
+
+ case PNG_NUMBER_FORMAT_u:
+ *--end = digits[number % 10];
+ number /= 10;
+ break;
+
+ case PNG_NUMBER_FORMAT_02x:
+ /* This format expects at least two digits */
+ mincount = 2;
+ /* FALLTHROUGH */
+
+ case PNG_NUMBER_FORMAT_x:
+ *--end = digits[number & 0xf];
+ number >>= 4;
+ break;
+
+ default: /* an error */
+ number = 0;
+ break;
+ }
+
+ /* Keep track of the number of digits added */
+ ++count;
+
+ /* Float a fixed number here: */
+ if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start))
+ {
+ /* End of the fraction, but maybe nothing was output? In that case
+ * drop the decimal point. If the number is a true zero handle that
+ * here.
+ */
+ if (output != 0)
+ *--end = '.';
+ else if (number == 0) /* and !output */
+ *--end = '0';
+ }
+ }
+
+ return end;
+}
+#endif
+
+#ifdef PNG_WARNINGS_SUPPORTED
/* This function is called whenever there is a non-fatal error. This function
* should not be changed. If there is a need to handle warnings differently,
* you should supply a replacement warning function and use
* png_set_error_fn() to replace the warning function at run-time.
*/
void PNGAPI
-png_warning(png_structp png_ptr, png_const_charp warning_message)
+png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
{
int offset = 0;
if (png_ptr != NULL)
{
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- if (png_ptr->flags&
- (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
+ if ((png_ptr->flags &
+ (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
#endif
- {
- if (*warning_message == '#')
- {
- for (offset=1; offset<15; offset++)
- if (*(warning_message+offset) == ' ')
+ {
+ if (*warning_message == PNG_LITERAL_SHARP)
+ {
+ for (offset = 1; offset < 15; offset++)
+ if (warning_message[offset] == ' ')
break;
- }
- }
- if (png_ptr != NULL && png_ptr->warning_fn != NULL)
- (*(png_ptr->warning_fn))(png_ptr, warning_message+offset);
+ }
+ }
}
+ if (png_ptr != NULL && png_ptr->warning_fn != NULL)
+ (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
+ warning_message + offset);
else
- png_default_warning(png_ptr, warning_message+offset);
+ png_default_warning(png_ptr, warning_message + offset);
}
-#endif /* PNG_NO_WARNINGS */
+/* These functions support 'formatted' warning messages with up to
+ * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter
+ * is introduced by @, where 'number' starts at 1. This follows the
+ * standard established by X/Open for internationalizable error messages.
+ */
+void
+png_warning_parameter(png_warning_parameters p, int number,
+ png_const_charp string)
+{
+ if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)
+ (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);
+}
+void
+png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
+ png_alloc_size_t value)
+{
+ char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
+ png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
+}
+
+void
+png_warning_parameter_signed(png_warning_parameters p, int number, int format,
+ png_int_32 value)
+{
+ png_alloc_size_t u;
+ png_charp str;
+ char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
+
+ /* Avoid overflow by doing the negate in a png_alloc_size_t: */
+ u = (png_alloc_size_t)value;
+ if (value < 0)
+ u = ~u + 1;
+
+ str = PNG_FORMAT_NUMBER(buffer, format, u);
+
+ if (value < 0 && str > buffer)
+ *--str = '-';
+
+ png_warning_parameter(p, number, str);
+}
+
+void
+png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
+ png_const_charp message)
+{
+ /* The internal buffer is just 192 bytes - enough for all our messages,
+ * overflow doesn't happen because this code checks! If someone figures
+ * out how to send us a message longer than 192 bytes, all that will
+ * happen is that the message will be truncated appropriately.
+ */
+ size_t i = 0; /* Index in the msg[] buffer: */
+ char msg[192];
+
+ /* Each iteration through the following loop writes at most one character
+ * to msg[i++] then returns here to validate that there is still space for
+ * the trailing '\0'. It may (in the case of a parameter) read more than
+ * one character from message[]; it must check for '\0' and continue to the
+ * test if it finds the end of string.
+ */
+ while (i<(sizeof msg)-1 && *message != '\0')
+ {
+ /* '@' at end of string is now just printed (previously it was skipped);
+ * it is an error in the calling code to terminate the string with @.
+ */
+ if (p != NULL && *message == '@' && message[1] != '\0')
+ {
+ int parameter_char = *++message; /* Consume the '@' */
+ static const char valid_parameters[] = "123456789";
+ int parameter = 0;
+
+ /* Search for the parameter digit, the index in the string is the
+ * parameter to use.
+ */
+ while (valid_parameters[parameter] != parameter_char &&
+ valid_parameters[parameter] != '\0')
+ ++parameter;
+
+ /* If the parameter digit is out of range it will just get printed. */
+ if (parameter < PNG_WARNING_PARAMETER_COUNT)
+ {
+ /* Append this parameter */
+ png_const_charp parm = p[parameter];
+ png_const_charp pend = p[parameter] + (sizeof p[parameter]);
+
+ /* No need to copy the trailing '\0' here, but there is no guarantee
+ * that parm[] has been initialized, so there is no guarantee of a
+ * trailing '\0':
+ */
+ while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
+ msg[i++] = *parm++;
+
+ /* Consume the parameter digit too: */
+ ++message;
+ continue;
+ }
+
+ /* else not a parameter and there is a character after the @ sign; just
+ * copy that. This is known not to be '\0' because of the test above.
+ */
+ }
+
+ /* At this point *message can't be '\0', even in the bad parameter case
+ * above where there is a lone '@' at the end of the message string.
+ */
+ msg[i++] = *message++;
+ }
+
+ /* i is always less than (sizeof msg), so: */
+ msg[i] = '\0';
+
+ /* And this is the formatted message. It may be larger than
+ * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these
+ * are not (currently) formatted.
+ */
+ png_warning(png_ptr, msg);
+}
+#endif /* WARNINGS */
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+void PNGAPI
+png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
+{
+ if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
+ {
+# ifdef PNG_READ_SUPPORTED
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
+ png_ptr->chunk_name != 0)
+ png_chunk_warning(png_ptr, error_message);
+ else
+# endif
+ png_warning(png_ptr, error_message);
+ }
+
+ else
+ {
+# ifdef PNG_READ_SUPPORTED
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
+ png_ptr->chunk_name != 0)
+ png_chunk_error(png_ptr, error_message);
+ else
+# endif
+ png_error(png_ptr, error_message);
+ }
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(error_message)
+# endif
+}
+
+void /* PRIVATE */
+png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
+{
+ if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0)
+ png_warning(png_ptr, error_message);
+ else
+ png_error(png_ptr, error_message);
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(error_message)
+# endif
+}
+
+void /* PRIVATE */
+png_app_error(png_const_structrp png_ptr, png_const_charp error_message)
+{
+ if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0)
+ png_warning(png_ptr, error_message);
+ else
+ png_error(png_ptr, error_message);
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(error_message)
+# endif
+}
+#endif /* BENIGN_ERRORS */
+
+#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */
+#if defined(PNG_WARNINGS_SUPPORTED) || \
+ (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED))
/* These utilities are used internally to build an error message that relates
* to the current chunk. The chunk name comes from png_ptr->chunk_name,
- * this is used to prefix the message. The message is limited in length
- * to 63 bytes, the name characters are output as hex digits wrapped in []
+ * which is used to prefix the message. The message is limited in length
+ * to 63 bytes. The name characters are output as hex digits wrapped in []
* if the character is invalid.
*/
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
-static PNG_CONST char png_digit[16] = {
+static const char png_digit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
-#define PNG_MAX_ERROR_TEXT 64
-
-#if !defined(PNG_NO_WARNINGS) || !defined(PNG_NO_ERROR_TEXT)
static void /* PRIVATE */
-png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
- error_message)
+png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
+ error_message)
{
- int iout = 0, iin = 0;
+ png_uint_32 chunk_name = png_ptr->chunk_name;
+ int iout = 0, ishift = 24;
- while (iin < 4)
+ while (ishift >= 0)
{
- int c = png_ptr->chunk_name[iin++];
- if (isnonalpha(c))
+ int c = (int)(chunk_name >> ishift) & 0xff;
+
+ ishift -= 8;
+ if (isnonalpha(c) != 0)
{
- buffer[iout++] = '[';
+ buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;
buffer[iout++] = png_digit[(c & 0xf0) >> 4];
buffer[iout++] = png_digit[c & 0x0f];
- buffer[iout++] = ']';
+ buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;
}
+
else
{
- buffer[iout++] = (png_byte)c;
+ buffer[iout++] = (char)c;
}
}
if (error_message == NULL)
buffer[iout] = '\0';
+
else
{
+ int iin = 0;
+
buffer[iout++] = ':';
buffer[iout++] = ' ';
- png_memcpy(buffer+iout, error_message, PNG_MAX_ERROR_TEXT);
- buffer[iout+PNG_MAX_ERROR_TEXT-1] = '\0';
+
+ while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')
+ buffer[iout++] = error_message[iin++];
+
+ /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */
+ buffer[iout] = '\0';
}
}
+#endif /* WARNINGS || ERROR_TEXT */
+
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
+PNG_FUNCTION(void,PNGAPI
+png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),
+ PNG_NORETURN)
+{
+ char msg[18+PNG_MAX_ERROR_TEXT];
+ if (png_ptr == NULL)
+ png_error(png_ptr, error_message);
+
+ else
+ {
+ png_format_buffer(png_ptr, msg, error_message);
+ png_error(png_ptr, msg);
+ }
+}
+#endif /* READ && ERROR_TEXT */
+
+#ifdef PNG_WARNINGS_SUPPORTED
+void PNGAPI
+png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
+{
+ char msg[18+PNG_MAX_ERROR_TEXT];
+ if (png_ptr == NULL)
+ png_warning(png_ptr, warning_message);
+
+ else
+ {
+ png_format_buffer(png_ptr, msg, warning_message);
+ png_warning(png_ptr, msg);
+ }
+}
+#endif /* WARNINGS */
#ifdef PNG_READ_SUPPORTED
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
void PNGAPI
-png_chunk_error(png_structp png_ptr, png_const_charp error_message)
+png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
+ error_message)
{
- char msg[18+PNG_MAX_ERROR_TEXT];
- if (png_ptr == NULL)
- png_error(png_ptr, error_message);
+ if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
+ png_chunk_warning(png_ptr, error_message);
+
else
+ png_chunk_error(png_ptr, error_message);
+
+# ifndef PNG_ERROR_TEXT_SUPPORTED
+ PNG_UNUSED(error_message)
+# endif
+}
+#endif
+#endif /* READ */
+
+void /* PRIVATE */
+png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
+{
+# ifndef PNG_WARNINGS_SUPPORTED
+ PNG_UNUSED(message)
+# endif
+
+ /* This is always supported, but for just read or just write it
+ * unconditionally does the right thing.
+ */
+# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
+# endif
+
+# ifdef PNG_READ_SUPPORTED
+ {
+ if (error < PNG_CHUNK_ERROR)
+ png_chunk_warning(png_ptr, message);
+
+ else
+ png_chunk_benign_error(png_ptr, message);
+ }
+# endif
+
+# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
+ else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
+# endif
+
+# ifdef PNG_WRITE_SUPPORTED
+ {
+ if (error < PNG_CHUNK_WRITE_ERROR)
+ png_app_warning(png_ptr, message);
+
+ else
+ png_app_error(png_ptr, message);
+ }
+# endif
+}
+
+#ifdef PNG_ERROR_TEXT_SUPPORTED
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_FUNCTION(void,
+png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
+{
+# define fixed_message "fixed point overflow in "
+# define fixed_message_ln ((sizeof fixed_message)-1)
+ unsigned int iin;
+ char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
+ memcpy(msg, fixed_message, fixed_message_ln);
+ iin = 0;
+ if (name != NULL)
+ while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
+ {
+ msg[fixed_message_ln + iin] = name[iin];
+ ++iin;
+ }
+ msg[fixed_message_ln + iin] = 0;
+ png_error(png_ptr, msg);
+}
+#endif
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* This API only exists if ANSI-C style error handling is used,
+ * otherwise it is necessary for png_default_error to be overridden.
+ */
+jmp_buf* PNGAPI
+png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
+ size_t jmp_buf_size)
+{
+ /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value
+ * and it must not change after that. Libpng doesn't care how big the
+ * buffer is, just that it doesn't change.
+ *
+ * If the buffer size is no *larger* than the size of jmp_buf when libpng is
+ * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0
+ * semantics that this call will not fail. If the size is larger, however,
+ * the buffer is allocated and this may fail, causing the function to return
+ * NULL.
+ */
+ if (png_ptr == NULL)
+ return NULL;
+
+ if (png_ptr->jmp_buf_ptr == NULL)
{
- png_format_buffer(png_ptr, msg, error_message);
- png_error(png_ptr, msg);
+ png_ptr->jmp_buf_size = 0; /* not allocated */
+
+ if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))
+ png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;
+
+ else
+ {
+ png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,
+ png_malloc_warn(png_ptr, jmp_buf_size));
+
+ if (png_ptr->jmp_buf_ptr == NULL)
+ return NULL; /* new NULL return on OOM */
+
+ png_ptr->jmp_buf_size = jmp_buf_size;
+ }
+ }
+
+ else /* Already allocated: check the size */
+ {
+ size_t size = png_ptr->jmp_buf_size;
+
+ if (size == 0)
+ {
+ size = (sizeof png_ptr->jmp_buf_local);
+ if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)
+ {
+ /* This is an internal error in libpng: somehow we have been left
+ * with a stack allocated jmp_buf when the application regained
+ * control. It's always possible to fix this up, but for the moment
+ * this is a png_error because that makes it easy to detect.
+ */
+ png_error(png_ptr, "Libpng jmp_buf still allocated");
+ /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */
+ }
+ }
+
+ if (size != jmp_buf_size)
+ {
+ png_warning(png_ptr, "Application jmp_buf size changed");
+ return NULL; /* caller will probably crash: no choice here */
+ }
+ }
+
+ /* Finally fill in the function, now we have a satisfactory buffer. It is
+ * valid to change the function on every call.
+ */
+ png_ptr->longjmp_fn = longjmp_fn;
+ return png_ptr->jmp_buf_ptr;
+}
+
+void /* PRIVATE */
+png_free_jmpbuf(png_structrp png_ptr)
+{
+ if (png_ptr != NULL)
+ {
+ jmp_buf *jb = png_ptr->jmp_buf_ptr;
+
+ /* A size of 0 is used to indicate a local, stack, allocation of the
+ * pointer; used here and in png.c
+ */
+ if (jb != NULL && png_ptr->jmp_buf_size > 0)
+ {
+
+ /* This stuff is so that a failure to free the error control structure
+ * does not leave libpng in a state with no valid error handling: the
+ * free always succeeds, if there is an error it gets ignored.
+ */
+ if (jb != &png_ptr->jmp_buf_local)
+ {
+ /* Make an internal, libpng, jmp_buf to return here */
+ jmp_buf free_jmp_buf;
+
+ if (!setjmp(free_jmp_buf))
+ {
+ png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */
+ png_ptr->jmp_buf_size = 0; /* stack allocation */
+ png_ptr->longjmp_fn = longjmp;
+ png_free(png_ptr, jb); /* Return to setjmp on error */
+ }
+ }
+ }
+
+ /* *Always* cancel everything out: */
+ png_ptr->jmp_buf_size = 0;
+ png_ptr->jmp_buf_ptr = NULL;
+ png_ptr->longjmp_fn = 0;
}
}
-#endif /* PNG_READ_SUPPORTED */
-#endif /* !defined(PNG_NO_WARNINGS) || !defined(PNG_NO_ERROR_TEXT) */
-
-#ifndef PNG_NO_WARNINGS
-void PNGAPI
-png_chunk_warning(png_structp png_ptr, png_const_charp warning_message)
-{
- char msg[18+PNG_MAX_ERROR_TEXT];
- if (png_ptr == NULL)
- png_warning(png_ptr, warning_message);
- else
- {
- png_format_buffer(png_ptr, msg, warning_message);
- png_warning(png_ptr, msg);
- }
-}
-#endif /* PNG_NO_WARNINGS */
-
+#endif
/* This is the default error handling function. Note that replacements for
* this function MUST NOT RETURN, or the program will likely crash. This
* function is used by default, or if the program supplies NULL for the
* error function pointer in png_set_error_fn().
*/
-static void /* PRIVATE */
-png_default_error(png_structp png_ptr, png_const_charp error_message)
+static PNG_FUNCTION(void /* PRIVATE */,
+png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
+ PNG_NORETURN)
{
-#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_CONSOLE_IO_SUPPORTED
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- if (*error_message == '#')
+ /* Check on NULL only added in 1.5.4 */
+ if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
{
- int offset;
- char error_number[16];
- for (offset=0; offset<15; offset++)
- {
- error_number[offset] = *(error_message+offset+1);
- if (*(error_message+offset) == ' ')
- break;
- }
- if((offset > 1) && (offset < 15))
- {
- error_number[offset-1]='\0';
- fprintf(stderr, "libpng error no. %s: %s\n", error_number,
- error_message+offset);
- }
- else
- fprintf(stderr, "libpng error: %s, offset=%d\n", error_message,offset);
+ /* Strip "#nnnn " from beginning of error message. */
+ int offset;
+ char error_number[16];
+ for (offset = 0; offset<15; offset++)
+ {
+ error_number[offset] = error_message[offset + 1];
+ if (error_message[offset] == ' ')
+ break;
+ }
+
+ if ((offset > 1) && (offset < 15))
+ {
+ error_number[offset - 1] = '\0';
+ fprintf(stderr, "libpng error no. %s: %s",
+ error_number, error_message + offset + 1);
+ fprintf(stderr, PNG_STRING_NEWLINE);
+ }
+
+ else
+ {
+ fprintf(stderr, "libpng error: %s, offset=%d",
+ error_message, offset);
+ fprintf(stderr, PNG_STRING_NEWLINE);
+ }
}
else
#endif
- fprintf(stderr, "libpng error: %s\n", error_message);
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
- if (png_ptr)
{
-# ifdef USE_FAR_KEYWORD
- {
- jmp_buf jmpbuf;
- png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf));
- longjmp(jmpbuf, 1);
- }
-# else
- longjmp(png_ptr->jmpbuf, 1);
-# endif
+ fprintf(stderr, "libpng error: %s", error_message ? error_message :
+ "undefined");
+ fprintf(stderr, PNG_STRING_NEWLINE);
}
#else
- PNG_ABORT();
-#endif
-#ifdef PNG_NO_CONSOLE_IO
- error_message = error_message; /* make compiler happy */
+ PNG_UNUSED(error_message) /* Make compiler happy */
#endif
+ png_longjmp(png_ptr, 1);
}
-#ifndef PNG_NO_WARNINGS
+PNG_FUNCTION(void,PNGAPI
+png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&
+ png_ptr->jmp_buf_ptr != NULL)
+ png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(val)
+#endif
+
+ /* If control reaches this point, png_longjmp() must not return. The only
+ * choice is to terminate the whole process (or maybe the thread); to do
+ * this the ANSI-C abort() function is used unless a different method is
+ * implemented by overriding the default configuration setting for
+ * PNG_ABORT().
+ */
+ PNG_ABORT();
+}
+
+#ifdef PNG_WARNINGS_SUPPORTED
/* This function is called when there is a warning, but the library thinks
* it can continue anyway. Replacement functions don't have to do anything
* here if you don't want them to. In the default configuration, png_ptr is
* not used, but it is passed in case it may be useful.
*/
static void /* PRIVATE */
-png_default_warning(png_structp png_ptr, png_const_charp warning_message)
+png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
{
-#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_CONSOLE_IO_SUPPORTED
# ifdef PNG_ERROR_NUMBERS_SUPPORTED
- if (*warning_message == '#')
+ if (*warning_message == PNG_LITERAL_SHARP)
{
- int offset;
- char warning_number[16];
- for (offset=0; offset<15; offset++)
- {
- warning_number[offset]=*(warning_message+offset+1);
- if (*(warning_message+offset) == ' ')
+ int offset;
+ char warning_number[16];
+ for (offset = 0; offset < 15; offset++)
+ {
+ warning_number[offset] = warning_message[offset + 1];
+ if (warning_message[offset] == ' ')
break;
- }
- if((offset > 1) && (offset < 15))
- {
- warning_number[offset-1]='\0';
- fprintf(stderr, "libpng warning no. %s: %s\n", warning_number,
- warning_message+offset);
- }
- else
- fprintf(stderr, "libpng warning: %s\n", warning_message);
+ }
+
+ if ((offset > 1) && (offset < 15))
+ {
+ warning_number[offset + 1] = '\0';
+ fprintf(stderr, "libpng warning no. %s: %s",
+ warning_number, warning_message + offset);
+ fprintf(stderr, PNG_STRING_NEWLINE);
+ }
+
+ else
+ {
+ fprintf(stderr, "libpng warning: %s",
+ warning_message);
+ fprintf(stderr, PNG_STRING_NEWLINE);
+ }
}
else
# endif
- fprintf(stderr, "libpng warning: %s\n", warning_message);
+
+ {
+ fprintf(stderr, "libpng warning: %s", warning_message);
+ fprintf(stderr, PNG_STRING_NEWLINE);
+ }
#else
- warning_message = warning_message; /* make compiler happy */
+ PNG_UNUSED(warning_message) /* Make compiler happy */
#endif
- png_ptr = png_ptr; /* make compiler happy */
+ PNG_UNUSED(png_ptr) /* Make compiler happy */
}
-#endif /* PNG_NO_WARNINGS */
+#endif /* WARNINGS */
/* This function is called when the application wants to use another method
* of handling errors and warnings. Note that the error function MUST NOT
* return to the calling routine or serious problems will occur. The return
- * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1)
+ * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
*/
void PNGAPI
-png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warning_fn)
+png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn)
{
if (png_ptr == NULL)
return;
+
png_ptr->error_ptr = error_ptr;
png_ptr->error_fn = error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
png_ptr->warning_fn = warning_fn;
+#else
+ PNG_UNUSED(warning_fn)
+#endif
}
@@ -321,23 +853,105 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
* pointer before png_write_destroy and png_read_destroy are called.
*/
png_voidp PNGAPI
-png_get_error_ptr(png_structp png_ptr)
+png_get_error_ptr(png_const_structrp png_ptr)
{
if (png_ptr == NULL)
return NULL;
- return ((png_voidp)png_ptr->error_ptr);
+
+ return (png_voidp)png_ptr->error_ptr;
}
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
void PNGAPI
-png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
+png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
{
- if(png_ptr != NULL)
+ if (png_ptr != NULL)
{
- png_ptr->flags &=
- ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
+ png_ptr->flags &=
+ ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
+ PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
}
}
#endif
-#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
+ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+ /* Currently the above both depend on SETJMP_SUPPORTED, however it would be
+ * possible to implement without setjmp support just so long as there is some
+ * way to handle the error return here:
+ */
+PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI
+png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message),
+ PNG_NORETURN)
+{
+ png_const_structrp png_ptr = png_nonconst_ptr;
+ png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
+
+ /* An error is always logged here, overwriting anything (typically a warning)
+ * that is already there:
+ */
+ if (image != NULL)
+ {
+ png_safecat(image->message, (sizeof image->message), 0, error_message);
+ image->warning_or_error |= PNG_IMAGE_ERROR;
+
+ /* Retrieve the jmp_buf from within the png_control, making this work for
+ * C++ compilation too is pretty tricky: C++ wants a pointer to the first
+ * element of a jmp_buf, but C doesn't tell us the type of that.
+ */
+ if (image->opaque != NULL && image->opaque->error_buf != NULL)
+ longjmp(png_control_jmp_buf(image->opaque), 1);
+
+ /* Missing longjmp buffer, the following is to help debugging: */
+ {
+ size_t pos = png_safecat(image->message, (sizeof image->message), 0,
+ "bad longjmp: ");
+ png_safecat(image->message, (sizeof image->message), pos,
+ error_message);
+ }
+ }
+
+ /* Here on an internal programming error. */
+ abort();
+}
+
+#ifdef PNG_WARNINGS_SUPPORTED
+void /* PRIVATE */ PNGCBAPI
+png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
+{
+ png_const_structrp png_ptr = png_nonconst_ptr;
+ png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
+
+ /* A warning is only logged if there is no prior warning or error. */
+ if (image->warning_or_error == 0)
+ {
+ png_safecat(image->message, (sizeof image->message), 0, warning_message);
+ image->warning_or_error |= PNG_IMAGE_WARNING;
+ }
+}
+#endif
+
+int /* PRIVATE */
+png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
+{
+ 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)
+ {
+ image->opaque->error_buf = safe_jmpbuf;
+ result = function(arg);
+ image->opaque->error_buf = saved_error_buf;
+ return result;
+ }
+
+ /* On png_error, return via longjmp, pop the jmpbuf, and free the image. */
+ image->opaque->error_buf = saved_error_buf;
+ png_image_free(image);
+ return 0;
+}
+#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngget.c b/PDF/src/pngget.c
index 0b2a69515..1084b268f 100644
--- a/PDF/src/pngget.c
+++ b/PDF/src/pngget.c
@@ -1,615 +1,915 @@
/* pngget.c - retrieval of values from info struct
*
- * Last changed in libpng 1.2.15 January 5, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
png_uint_32 PNGAPI
-png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 flag)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->valid & flag);
- else
- return(0);
+ {
+#ifdef PNG_READ_tRNS_SUPPORTED
+ /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the
+ * 'valid' flag for the detection of duplicate chunks. Do not report a
+ * valid tRNS chunk in this case.
+ */
+ if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
+ return 0;
+#endif
+
+ return info_ptr->valid & flag;
+ }
+
+ return 0;
}
-png_uint_32 PNGAPI
-png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+size_t PNGAPI
+png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->rowbytes);
- else
- return(0);
+ return info_ptr->rowbytes;
+
+ return 0;
}
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
+#ifdef PNG_INFO_IMAGE_SUPPORTED
png_bytepp PNGAPI
-png_get_rows(png_structp png_ptr, png_infop info_ptr)
+png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->row_pointers);
- else
- return(0);
+ return info_ptr->row_pointers;
+
+ return 0;
}
#endif
#ifdef PNG_EASY_ACCESS_SUPPORTED
-/* easy access to info, added in libpng-0.99 */
+/* Easy access to info, added in libpng-0.99 */
png_uint_32 PNGAPI
-png_get_image_width(png_structp png_ptr, png_infop info_ptr)
+png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->width;
- }
- return (0);
+
+ return 0;
}
png_uint_32 PNGAPI
-png_get_image_height(png_structp png_ptr, png_infop info_ptr)
+png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->height;
- }
- return (0);
+
+ return 0;
}
png_byte PNGAPI
-png_get_bit_depth(png_structp png_ptr, png_infop info_ptr)
+png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->bit_depth;
- }
- return (0);
+
+ return 0;
}
png_byte PNGAPI
-png_get_color_type(png_structp png_ptr, png_infop info_ptr)
+png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->color_type;
- }
- return (0);
+
+ return 0;
}
png_byte PNGAPI
-png_get_filter_type(png_structp png_ptr, png_infop info_ptr)
+png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->filter_type;
- }
- return (0);
+
+ return 0;
}
png_byte PNGAPI
-png_get_interlace_type(png_structp png_ptr, png_infop info_ptr)
+png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->interlace_type;
- }
- return (0);
+
+ return 0;
}
png_byte PNGAPI
-png_get_compression_type(png_structp png_ptr, png_infop info_ptr)
+png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- {
return info_ptr->compression_type;
- }
- return (0);
+
+ return 0;
}
png_uint_32 PNGAPI
-png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
+ info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_pHYs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pHYs)
+#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_x_pixels_per_meter");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter");
- if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
- return (0);
- else return (info_ptr->x_pixels_per_unit);
+ if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
+ return info_ptr->x_pixels_per_unit;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
png_uint_32 PNGAPI
-png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
+ info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_pHYs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pHYs)
+#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_y_pixels_per_meter");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter");
- if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
- return (0);
- else return (info_ptr->y_pixels_per_unit);
+ if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
+ return info_ptr->y_pixels_per_unit;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
png_uint_32 PNGAPI
-png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_pHYs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pHYs)
+#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixels_per_meter");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter");
- if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER ||
- info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit)
- return (0);
- else return (info_ptr->x_pixels_per_unit);
+ if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER &&
+ info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)
+ return info_ptr->x_pixels_per_unit;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
#ifdef PNG_FLOATING_POINT_SUPPORTED
float PNGAPI
-png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr)
+png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp
+ info_ptr)
+{
+#ifdef PNG_READ_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixel_aspect_ratio");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_pHYs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pHYs)
- {
- png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio");
- if (info_ptr->x_pixels_per_unit == 0)
- return ((float)0.0);
- else
- return ((float)((float)info_ptr->y_pixels_per_unit
- /(float)info_ptr->x_pixels_per_unit));
+ if (info_ptr->x_pixels_per_unit != 0)
+ return (float)info_ptr->y_pixels_per_unit
+ / (float)info_ptr->x_pixels_per_unit;
}
#else
- return (0.0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return ((float)0.0);
+
+ return (float)0.0;
+}
+#endif
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_fixed_point PNGAPI
+png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,
+ png_const_inforp info_ptr)
+{
+#ifdef PNG_READ_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixel_aspect_ratio_fixed");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0 &&
+ info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 &&
+ info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX &&
+ info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX)
+ {
+ png_fixed_point res;
+
+ /* The following casts work because a PNG 4 byte integer only has a valid
+ * range of 0..2^31-1; otherwise the cast might overflow.
+ */
+ if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1,
+ (png_int_32)info_ptr->x_pixels_per_unit) != 0)
+ return res;
+ }
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
+#endif
+
+ return 0;
}
#endif
png_int_32 PNGAPI
-png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr)
+png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_oFFs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_oFFs)
+#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_x_offset_microns");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
- if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
- return (0);
- else return (info_ptr->x_offset);
+ if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
+ return info_ptr->x_offset;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
png_int_32 PNGAPI
-png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr)
+png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_oFFs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_oFFs)
+#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_y_offset_microns");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
- if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
- return (0);
- else return (info_ptr->y_offset);
+ if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
+ return info_ptr->y_offset;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
png_int_32 PNGAPI
-png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_oFFs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_oFFs)
+#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_x_offset_pixels");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
- if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
- return (0);
- else return (info_ptr->x_offset);
+ if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
+ return info_ptr->x_offset;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
png_int_32 PNGAPI
-png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- if (png_ptr != NULL && info_ptr != NULL)
-#if defined(PNG_oFFs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_oFFs)
+#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_y_offset_pixels");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
- if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
- return (0);
- else return (info_ptr->y_offset);
+ if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
+ return info_ptr->y_offset;
}
#else
- return (0);
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
- return (0);
+
+ return 0;
}
-#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
-png_uint_32 PNGAPI
-png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+#ifdef PNG_INCH_CONVERSIONS_SUPPORTED
+static png_uint_32
+ppi_from_ppm(png_uint_32 ppm)
{
- return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr)
- *.0254 +.5));
+#if 0
+ /* The conversion is *(2.54/100), in binary (32 digits):
+ * .00000110100000001001110101001001
+ */
+ png_uint_32 t1001, t1101;
+ ppm >>= 1; /* .1 */
+ t1001 = ppm + (ppm >> 3); /* .1001 */
+ t1101 = t1001 + (ppm >> 1); /* .1101 */
+ ppm >>= 20; /* .000000000000000000001 */
+ t1101 += t1101 >> 15; /* .1101000000000001101 */
+ t1001 >>= 11; /* .000000000001001 */
+ t1001 += t1001 >> 12; /* .000000000001001000000001001 */
+ ppm += t1001; /* .000000000001001000001001001 */
+ ppm += t1101; /* .110100000001001110101001001 */
+ return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */
+#else
+ /* The argument is a PNG unsigned integer, so it is not permitted
+ * to be bigger than 2^31.
+ */
+ png_fixed_point result;
+ if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127,
+ 5000) != 0)
+ return (png_uint_32)result;
+
+ /* Overflow. */
+ return 0;
+#endif
}
png_uint_32 PNGAPI
-png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr)
- *.0254 +.5));
+ return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr));
}
png_uint_32 PNGAPI
-png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
- *.0254 +.5));
+ return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr));
}
+png_uint_32 PNGAPI
+png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)
+{
+ return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr));
+}
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+static png_fixed_point
+png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns)
+{
+ /* Convert from meters * 1,000,000 to inches * 100,000, meters to
+ * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127.
+ * 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 PNGAPI
+png_get_x_offset_inches_fixed(png_const_structrp png_ptr,
+ png_const_inforp info_ptr)
+{
+ return png_fixed_inches_from_microns(png_ptr,
+ png_get_x_offset_microns(png_ptr, info_ptr));
+}
+#endif
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_fixed_point PNGAPI
+png_get_y_offset_inches_fixed(png_const_structrp png_ptr,
+ png_const_inforp info_ptr)
+{
+ return png_fixed_inches_from_microns(png_ptr,
+ png_get_y_offset_microns(png_ptr, info_ptr));
+}
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
float PNGAPI
-png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr)
+png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- return ((float)png_get_x_offset_microns(png_ptr, info_ptr)
- *.00003937);
+ /* To avoid the overflow do the conversion directly in floating
+ * point.
+ */
+ return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937);
}
+#endif
+#ifdef PNG_FLOATING_POINT_SUPPORTED
float PNGAPI
-png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr)
+png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
- return ((float)png_get_y_offset_microns(png_ptr, info_ptr)
- *.00003937);
+ /* To avoid the overflow do the conversion directly in floating
+ * point.
+ */
+ return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937);
}
+#endif
-#if defined(PNG_pHYs_SUPPORTED)
+#ifdef PNG_pHYs_SUPPORTED
png_uint_32 PNGAPI
-png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
{
png_uint_32 retval = 0;
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ png_debug1(1, "in %s retrieval function", "pHYs");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "pHYs");
if (res_x != NULL)
{
*res_x = info_ptr->x_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
+
if (res_y != NULL)
{
*res_y = info_ptr->y_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
+
if (unit_type != NULL)
{
*unit_type = (int)info_ptr->phys_unit_type;
retval |= PNG_INFO_pHYs;
- if(*unit_type == 1)
+
+ if (*unit_type == 1)
{
if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);
if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);
}
}
}
- return (retval);
+
+ return retval;
}
-#endif /* PNG_pHYs_SUPPORTED */
-#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
+#endif /* pHYs */
+#endif /* INCH_CONVERSIONS */
/* png_get_channels really belongs in here, too, but it's been around longer */
-#endif /* PNG_EASY_ACCESS_SUPPORTED */
+#endif /* EASY_ACCESS */
+
png_byte PNGAPI
-png_get_channels(png_structp png_ptr, png_infop info_ptr)
+png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->channels);
- else
- return (0);
+ return info_ptr->channels;
+
+ return 0;
}
-png_bytep PNGAPI
-png_get_signature(png_structp png_ptr, png_infop info_ptr)
+#ifdef PNG_READ_SUPPORTED
+png_const_bytep PNGAPI
+png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->signature);
- else
- return (NULL);
-}
+ return info_ptr->signature;
-#if defined(PNG_bKGD_SUPPORTED)
+ return NULL;
+}
+#endif
+
+#ifdef PNG_bKGD_SUPPORTED
png_uint_32 PNGAPI
-png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
- png_color_16p *background)
+png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_color_16p *background)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)
- && background != NULL)
+ png_debug1(1, "in %s retrieval function", "bKGD");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_bKGD) != 0 &&
+ background != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "bKGD");
*background = &(info_ptr->background);
- return (PNG_INFO_bKGD);
+ return PNG_INFO_bKGD;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_cHRM_SUPPORTED
+/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the
+ * same time to correct the rgb grayscale coefficient defaults obtained from the
+ * cHRM chunk in 1.5.4
+ */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
-png_get_cHRM(png_structp png_ptr, png_infop 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)
+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)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ 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.
+ */
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "cHRM");
if (white_x != NULL)
- *white_x = (double)info_ptr->x_white;
+ *white_x = png_float(png_ptr,
+ info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");
if (white_y != NULL)
- *white_y = (double)info_ptr->y_white;
+ *white_y = png_float(png_ptr,
+ info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y");
if (red_x != NULL)
- *red_x = (double)info_ptr->x_red;
+ *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx,
+ "cHRM red X");
if (red_y != NULL)
- *red_y = (double)info_ptr->y_red;
+ *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy,
+ "cHRM red Y");
if (green_x != NULL)
- *green_x = (double)info_ptr->x_green;
+ *green_x = png_float(png_ptr,
+ info_ptr->colorspace.end_points_xy.greenx, "cHRM green X");
if (green_y != NULL)
- *green_y = (double)info_ptr->y_green;
+ *green_y = png_float(png_ptr,
+ info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y");
if (blue_x != NULL)
- *blue_x = (double)info_ptr->x_blue;
+ *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex,
+ "cHRM blue X");
if (blue_y != NULL)
- *blue_y = (double)info_ptr->y_blue;
- return (PNG_INFO_cHRM);
+ *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,
+ "cHRM blue Y");
+ return PNG_INFO_cHRM;
}
- return (0);
+
+ return 0;
}
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
+
png_uint_32 PNGAPI
-png_get_cHRM_fixed(png_structp png_ptr, png_infop 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_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ double *red_X, double *red_Y, double *red_Z, double *green_X,
+ double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
+ double *blue_Z)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ 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)
+ {
+ if (red_X != NULL)
+ *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_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");
+ if (red_Z != NULL)
+ *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_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");
+ if (green_Y != NULL)
+ *green_Y = png_float(png_ptr,
+ info_ptr->colorspace.end_points_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");
+ if (blue_X != NULL)
+ *blue_X = png_float(png_ptr,
+ info_ptr->colorspace.end_points_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");
+ if (blue_Z != NULL)
+ *blue_Z = png_float(png_ptr,
+ info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");
+ return PNG_INFO_cHRM;
+ }
+
+ return 0;
+}
+# endif
+
+# ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+ png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+ png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+ png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+ png_fixed_point *int_blue_Z)
+{
+ 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)
+ {
+ 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;
+ return PNG_INFO_cHRM;
+ }
+
+ return 0;
+}
+
+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_debug1(1, "in %s retrieval function", "cHRM");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "cHRM");
if (white_x != NULL)
- *white_x = info_ptr->int_x_white;
+ *white_x = info_ptr->colorspace.end_points_xy.whitex;
if (white_y != NULL)
- *white_y = info_ptr->int_y_white;
+ *white_y = info_ptr->colorspace.end_points_xy.whitey;
if (red_x != NULL)
- *red_x = info_ptr->int_x_red;
+ *red_x = info_ptr->colorspace.end_points_xy.redx;
if (red_y != NULL)
- *red_y = info_ptr->int_y_red;
+ *red_y = info_ptr->colorspace.end_points_xy.redy;
if (green_x != NULL)
- *green_x = info_ptr->int_x_green;
+ *green_x = info_ptr->colorspace.end_points_xy.greenx;
if (green_y != NULL)
- *green_y = info_ptr->int_y_green;
+ *green_y = info_ptr->colorspace.end_points_xy.greeny;
if (blue_x != NULL)
- *blue_x = info_ptr->int_x_blue;
+ *blue_x = info_ptr->colorspace.end_points_xy.bluex;
if (blue_y != NULL)
- *blue_y = info_ptr->int_y_blue;
- return (PNG_INFO_cHRM);
+ *blue_y = info_ptr->colorspace.end_points_xy.bluey;
+ return PNG_INFO_cHRM;
}
- return (0);
+
+ return 0;
}
-#endif
+# endif
#endif
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_gAMA_SUPPORTED
+# ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
-png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_fixed_point *file_gamma)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
- && file_gamma != NULL)
+ png_debug1(1, "in %s retrieval function", "gAMA");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
+ file_gamma != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "gAMA");
- *file_gamma = (double)info_ptr->gamma;
- return (PNG_INFO_gAMA);
+ *file_gamma = info_ptr->colorspace.gamma;
+ return PNG_INFO_gAMA;
}
- return (0);
+
+ return 0;
}
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
+# endif
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
-png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr,
- png_fixed_point *int_file_gamma)
+png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ double *file_gamma)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
- && int_file_gamma != NULL)
+ png_debug1(1, "in %s retrieval function", "gAMA(float)");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
+ file_gamma != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "gAMA");
- *int_file_gamma = info_ptr->int_gamma;
- return (PNG_INFO_gAMA);
+ *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,
+ "png_get_gAMA");
+ return PNG_INFO_gAMA;
}
- return (0);
+
+ return 0;
}
-#endif
+# endif
#endif
-#if defined(PNG_sRGB_SUPPORTED)
+#ifdef PNG_sRGB_SUPPORTED
png_uint_32 PNGAPI
-png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent)
+png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ int *file_srgb_intent)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)
- && file_srgb_intent != NULL)
+ 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)
{
- png_debug1(1, "in %s retrieval function\n", "sRGB");
- *file_srgb_intent = (int)info_ptr->srgb_intent;
- return (PNG_INFO_sRGB);
+ *file_srgb_intent = info_ptr->colorspace.rendering_intent;
+ return PNG_INFO_sRGB;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_iCCP_SUPPORTED)
+#ifdef PNG_iCCP_SUPPORTED
png_uint_32 PNGAPI
-png_get_iCCP(png_structp png_ptr, png_infop info_ptr,
- png_charpp name, int *compression_type,
- png_charpp profile, png_uint_32 *proflen)
+png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_charpp name, int *compression_type,
+ png_bytepp profile, png_uint_32 *proflen)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)
- && name != NULL && profile != NULL && proflen != NULL)
+ png_debug1(1, "in %s retrieval function", "iCCP");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_iCCP) != 0 &&
+ name != NULL && profile != NULL && proflen != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "iCCP");
*name = info_ptr->iccp_name;
*profile = info_ptr->iccp_profile;
- /* compression_type is a dummy so the API won't have to change
- if we introduce multiple compression types later. */
- *proflen = (int)info_ptr->iccp_proflen;
- *compression_type = (int)info_ptr->iccp_compression;
- return (PNG_INFO_iCCP);
+ *proflen = png_get_uint_32(info_ptr->iccp_profile);
+ /* This is somewhat irrelevant since the profile data returned has
+ * actually been uncompressed.
+ */
+ if (compression_type != NULL)
+ *compression_type = PNG_COMPRESSION_TYPE_BASE;
+ return PNG_INFO_iCCP;
}
- return (0);
+
+ return 0;
+
}
#endif
-#if defined(PNG_sPLT_SUPPORTED)
-png_uint_32 PNGAPI
-png_get_sPLT(png_structp png_ptr, png_infop info_ptr,
- png_sPLT_tpp spalettes)
+#ifdef PNG_sPLT_SUPPORTED
+int PNGAPI
+png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_sPLT_tpp spalettes)
{
+ png_debug1(1, "in %s retrieval function", "sPLT");
+
if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
{
- *spalettes = info_ptr->splt_palettes;
- return ((png_uint_32)info_ptr->splt_palettes_num);
+ *spalettes = info_ptr->splt_palettes;
+ return info_ptr->splt_palettes_num;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_hIST_SUPPORTED)
+#ifdef PNG_eXIf_SUPPORTED
png_uint_32 PNGAPI
-png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_bytep *exif)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)
- && hist != NULL)
+ png_warning(png_ptr, "png_get_eXIf does not work; use png_get_eXIf_1");
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(exif)
+ return 0;
+}
+
+png_uint_32 PNGAPI
+png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 *num_exif, png_bytep *exif)
+{
+ png_debug1(1, "in %s retrieval function", "eXIf");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL)
+ {
+ *num_exif = info_ptr->num_exif;
+ *exif = info_ptr->exif;
+ return PNG_INFO_eXIf;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef PNG_hIST_SUPPORTED
+png_uint_32 PNGAPI
+png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_uint_16p *hist)
+{
+ png_debug1(1, "in %s retrieval function", "hIST");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "hIST");
*hist = info_ptr->hist;
- return (PNG_INFO_hIST);
+ return PNG_INFO_hIST;
}
- return (0);
+
+ return 0;
}
#endif
png_uint_32 PNGAPI
-png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 *width, png_uint_32 *height, int *bit_depth,
- int *color_type, int *interlace_type, int *compression_type,
- int *filter_type)
-
+png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+ int *color_type, int *interlace_type, int *compression_type,
+ int *filter_type)
{
- if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL &&
- bit_depth != NULL && color_type != NULL)
- {
- png_debug1(1, "in %s retrieval function\n", "IHDR");
- *width = info_ptr->width;
- *height = info_ptr->height;
- *bit_depth = info_ptr->bit_depth;
- if (info_ptr->bit_depth < 1 || info_ptr->bit_depth > 16)
- png_error(png_ptr, "Invalid bit depth");
- *color_type = info_ptr->color_type;
- if (info_ptr->color_type > 6)
- png_error(png_ptr, "Invalid color type");
- if (compression_type != NULL)
- *compression_type = info_ptr->compression_type;
- if (filter_type != NULL)
- *filter_type = info_ptr->filter_type;
- if (interlace_type != NULL)
- *interlace_type = info_ptr->interlace_type;
+ png_debug1(1, "in %s retrieval function", "IHDR");
- /* check for potential overflow of rowbytes */
- if (*width == 0 || *width > PNG_UINT_31_MAX)
- png_error(png_ptr, "Invalid image width");
- if (*height == 0 || *height > PNG_UINT_31_MAX)
- png_error(png_ptr, "Invalid image height");
- if (info_ptr->width > (PNG_UINT_32_MAX
- >> 3) /* 8-byte RGBA pixels */
- - 64 /* bigrowbuf hack */
- - 1 /* filter byte */
- - 7*8 /* rounding of width to multiple of 8 pixels */
- - 8) /* extra max_pixel_depth pad */
- {
- png_warning(png_ptr,
- "Width too large for libpng to process image data.");
- }
- return (1);
- }
- return (0);
+ if (png_ptr == NULL || info_ptr == NULL)
+ return 0;
+
+ if (width != NULL)
+ *width = info_ptr->width;
+
+ if (height != NULL)
+ *height = info_ptr->height;
+
+ if (bit_depth != NULL)
+ *bit_depth = info_ptr->bit_depth;
+
+ if (color_type != NULL)
+ *color_type = info_ptr->color_type;
+
+ if (compression_type != NULL)
+ *compression_type = info_ptr->compression_type;
+
+ if (filter_type != NULL)
+ *filter_type = info_ptr->filter_type;
+
+ if (interlace_type != NULL)
+ *interlace_type = info_ptr->interlace_type;
+
+ /* This is redundant if we can be sure that the info_ptr values were all
+ * assigned in png_set_IHDR(). We do the check anyhow in case an
+ * application has ignored our advice not to mess with the members
+ * of info_ptr directly.
+ */
+ png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
+ info_ptr->compression_type, info_ptr->filter_type);
+
+ return 1;
}
-#if defined(PNG_oFFs_SUPPORTED)
+#ifdef PNG_oFFs_SUPPORTED
png_uint_32 PNGAPI
-png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
- png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)
+png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)
- && offset_x != NULL && offset_y != NULL && unit_type != NULL)
+ png_debug1(1, "in %s retrieval function", "oFFs");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_oFFs) != 0 &&
+ offset_x != NULL && offset_y != NULL && unit_type != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "oFFs");
*offset_x = info_ptr->x_offset;
*offset_y = info_ptr->y_offset;
*unit_type = (int)info_ptr->offset_unit_type;
- return (PNG_INFO_oFFs);
+ return PNG_INFO_oFFs;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_pCAL_SUPPORTED)
+#ifdef PNG_pCAL_SUPPORTED
png_uint_32 PNGAPI
-png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
- png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
- png_charp *units, png_charpp *params)
+png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+ png_charp *units, png_charpp *params)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)
- && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
- nparams != NULL && units != NULL && params != NULL)
+ png_debug1(1, "in %s retrieval function", "pCAL");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pCAL) != 0 &&
+ purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+ nparams != NULL && units != NULL && params != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "pCAL");
*purpose = info_ptr->pcal_purpose;
*X0 = info_ptr->pcal_X0;
*X1 = info_ptr->pcal_X1;
@@ -617,285 +917,351 @@ png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
*nparams = (int)info_ptr->pcal_nparams;
*units = info_ptr->pcal_units;
*params = info_ptr->pcal_params;
- return (PNG_INFO_pCAL);
+ return PNG_INFO_pCAL;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_sCAL_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_sCAL_SUPPORTED
+# ifdef PNG_FIXED_POINT_SUPPORTED
+# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
png_uint_32 PNGAPI
-png_get_sCAL(png_structp png_ptr, png_infop info_ptr,
- int *unit, double *width, double *height)
+png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ int *unit, png_fixed_point *width, png_fixed_point *height)
{
- if (png_ptr != NULL && info_ptr != NULL &&
- (info_ptr->valid & PNG_INFO_sCAL))
- {
- *unit = info_ptr->scal_unit;
- *width = info_ptr->scal_pixel_width;
- *height = info_ptr->scal_pixel_height;
- return (PNG_INFO_sCAL);
- }
- return(0);
-}
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-png_uint_32 PNGAPI
-png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr,
- int *unit, png_charpp width, png_charpp height)
-{
- if (png_ptr != NULL && info_ptr != NULL &&
- (info_ptr->valid & PNG_INFO_sCAL))
- {
- *unit = info_ptr->scal_unit;
- *width = info_ptr->scal_s_width;
- *height = info_ptr->scal_s_height;
- return (PNG_INFO_sCAL);
- }
- return(0);
-}
-#endif
-#endif
-#endif
+ png_debug1(1, "in %s retrieval function", "sCAL");
-#if defined(PNG_pHYs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL) != 0)
+ {
+ *unit = info_ptr->scal_unit;
+ /*TODO: make this work without FP support; the API is currently eliminated
+ * if neither floating point APIs nor internal floating point arithmetic
+ * are enabled.
+ */
+ *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width");
+ *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height),
+ "sCAL height");
+ return PNG_INFO_sCAL;
+ }
+
+ return 0;
+}
+# endif /* FLOATING_ARITHMETIC */
+# endif /* FIXED_POINT */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
-png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ int *unit, double *width, double *height)
+{
+ png_debug1(1, "in %s retrieval function", "sCAL(float)");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL) != 0)
+ {
+ *unit = info_ptr->scal_unit;
+ *width = atof(info_ptr->scal_s_width);
+ *height = atof(info_ptr->scal_s_height);
+ return PNG_INFO_sCAL;
+ }
+
+ return 0;
+}
+# endif /* FLOATING POINT */
+png_uint_32 PNGAPI
+png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ int *unit, png_charpp width, png_charpp height)
+{
+ png_debug1(1, "in %s retrieval function", "sCAL(str)");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL) != 0)
+ {
+ *unit = info_ptr->scal_unit;
+ *width = info_ptr->scal_s_width;
+ *height = info_ptr->scal_s_height;
+ return PNG_INFO_sCAL;
+ }
+
+ return 0;
+}
+#endif /* sCAL */
+
+#ifdef PNG_pHYs_SUPPORTED
+png_uint_32 PNGAPI
+png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
{
png_uint_32 retval = 0;
+ png_debug1(1, "in %s retrieval function", "pHYs");
+
if (png_ptr != NULL && info_ptr != NULL &&
- (info_ptr->valid & PNG_INFO_pHYs))
+ (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "pHYs");
if (res_x != NULL)
{
*res_x = info_ptr->x_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
+
if (res_y != NULL)
{
*res_y = info_ptr->y_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
+
if (unit_type != NULL)
{
*unit_type = (int)info_ptr->phys_unit_type;
retval |= PNG_INFO_pHYs;
}
}
- return (retval);
+
+ return retval;
}
-#endif
+#endif /* pHYs */
png_uint_32 PNGAPI
-png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
- int *num_palette)
+png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_colorp *palette, int *num_palette)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE)
- && palette != NULL)
+ png_debug1(1, "in %s retrieval function", "PLTE");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "PLTE");
*palette = info_ptr->palette;
*num_palette = info_ptr->num_palette;
- png_debug1(3, "num_palette = %d\n", *num_palette);
- return (PNG_INFO_PLTE);
+ png_debug1(3, "num_palette = %d", *num_palette);
+ return PNG_INFO_PLTE;
}
- return (0);
+
+ return 0;
}
-#if defined(PNG_sBIT_SUPPORTED)
+#ifdef PNG_sBIT_SUPPORTED
png_uint_32 PNGAPI
-png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_color_8p *sig_bit)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)
- && sig_bit != NULL)
+ png_debug1(1, "in %s retrieval function", "sBIT");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "sBIT");
*sig_bit = &(info_ptr->sig_bit);
- return (PNG_INFO_sBIT);
+ return PNG_INFO_sBIT;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_TEXT_SUPPORTED)
-png_uint_32 PNGAPI
-png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
- int *num_text)
+#ifdef PNG_TEXT_SUPPORTED
+int PNGAPI
+png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_textp *text_ptr, int *num_text)
{
if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
{
- png_debug1(1, "in %s retrieval function\n",
- (png_ptr->chunk_name[0] == '\0' ? "text"
- : (png_const_charp)png_ptr->chunk_name));
+ png_debug1(1, "in text retrieval function, chunk typeid = 0x%lx",
+ (unsigned long)png_ptr->chunk_name);
+
if (text_ptr != NULL)
*text_ptr = info_ptr->text;
+
if (num_text != NULL)
*num_text = info_ptr->num_text;
- return ((png_uint_32)info_ptr->num_text);
+
+ return info_ptr->num_text;
}
+
if (num_text != NULL)
- *num_text = 0;
- return(0);
+ *num_text = 0;
+
+ return 0;
}
#endif
-#if defined(PNG_tIME_SUPPORTED)
+#ifdef PNG_tIME_SUPPORTED
png_uint_32 PNGAPI
-png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_timep *mod_time)
{
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)
- && mod_time != NULL)
+ png_debug1(1, "in %s retrieval function", "tIME");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL)
{
- png_debug1(1, "in %s retrieval function\n", "tIME");
*mod_time = &(info_ptr->mod_time);
- return (PNG_INFO_tIME);
+ return PNG_INFO_tIME;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_tRNS_SUPPORTED)
+#ifdef PNG_tRNS_SUPPORTED
png_uint_32 PNGAPI
-png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
- png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)
{
png_uint_32 retval = 0;
- if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+
+ png_debug1(1, "in %s retrieval function", "tRNS");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_tRNS) != 0)
{
- png_debug1(1, "in %s retrieval function\n", "tRNS");
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (trans != NULL)
- {
- *trans = info_ptr->trans;
- retval |= PNG_INFO_tRNS;
- }
- if (trans_values != NULL)
- *trans_values = &(info_ptr->trans_values);
+ if (trans_alpha != NULL)
+ {
+ *trans_alpha = info_ptr->trans_alpha;
+ retval |= PNG_INFO_tRNS;
+ }
+
+ if (trans_color != NULL)
+ *trans_color = &(info_ptr->trans_color);
}
+
else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */
{
- if (trans_values != NULL)
- {
- *trans_values = &(info_ptr->trans_values);
- retval |= PNG_INFO_tRNS;
- }
- if(trans != NULL)
- *trans = NULL;
+ if (trans_color != NULL)
+ {
+ *trans_color = &(info_ptr->trans_color);
+ retval |= PNG_INFO_tRNS;
+ }
+
+ if (trans_alpha != NULL)
+ *trans_alpha = NULL;
}
- if(num_trans != NULL)
+
+ if (num_trans != NULL)
{
*num_trans = info_ptr->num_trans;
retval |= PNG_INFO_tRNS;
}
}
- return (retval);
+
+ return retval;
}
#endif
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-png_uint_32 PNGAPI
-png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
- png_unknown_chunkpp unknowns)
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+int PNGAPI
+png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_unknown_chunkpp unknowns)
{
if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)
{
- *unknowns = info_ptr->unknown_chunks;
- return ((png_uint_32)info_ptr->unknown_chunks_num);
+ *unknowns = info_ptr->unknown_chunks;
+ return info_ptr->unknown_chunks_num;
}
- return (0);
+
+ return 0;
}
#endif
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
png_byte PNGAPI
-png_get_rgb_to_gray_status (png_structp png_ptr)
+png_get_rgb_to_gray_status(png_const_structrp png_ptr)
{
- return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0);
+ return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0);
}
#endif
-#if defined(PNG_USER_CHUNKS_SUPPORTED)
+#ifdef PNG_USER_CHUNKS_SUPPORTED
png_voidp PNGAPI
-png_get_user_chunk_ptr(png_structp png_ptr)
+png_get_user_chunk_ptr(png_const_structrp png_ptr)
{
- return (png_ptr? png_ptr->user_chunk_ptr : NULL);
+ return (png_ptr ? png_ptr->user_chunk_ptr : NULL);
}
#endif
+size_t PNGAPI
+png_get_compression_buffer_size(png_const_structrp png_ptr)
+{
+ if (png_ptr == NULL)
+ return 0;
+
#ifdef PNG_WRITE_SUPPORTED
-png_uint_32 PNGAPI
-png_get_compression_buffer_size(png_structp png_ptr)
-{
- return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L);
-}
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
#endif
+ {
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+ return png_ptr->IDAT_read_size;
+#else
+ return PNG_IDAT_READ_SIZE;
+#endif
+ }
-#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
-#ifndef PNG_1_0_X
-/* this function was added to libpng 1.2.0 and should exist by default */
-png_uint_32 PNGAPI
-png_get_asm_flags (png_structp png_ptr)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- return (png_ptr? 0L: 0L);
+#ifdef PNG_WRITE_SUPPORTED
+ else
+ return png_ptr->zbuffer_size;
+#endif
}
-/* this function was added to libpng 1.2.0 and should exist by default */
-png_uint_32 PNGAPI
-png_get_asm_flagmask (int flag_select)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- flag_select=flag_select;
- return 0L;
-}
-
- /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
-/* this function was added to libpng 1.2.0 */
-png_uint_32 PNGAPI
-png_get_mmx_flagmask (int flag_select, int *compilerID)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- flag_select=flag_select;
- *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */
- return 0L;
-}
-
-/* this function was added to libpng 1.2.0 */
-png_byte PNGAPI
-png_get_mmx_bitdepth_threshold (png_structp png_ptr)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- return (png_ptr? 0: 0);
-}
-
-/* this function was added to libpng 1.2.0 */
-png_uint_32 PNGAPI
-png_get_mmx_rowbytes_threshold (png_structp png_ptr)
-{
- /* obsolete, to be removed from libpng-1.4.0 */
- return (png_ptr? 0L: 0L);
-}
-#endif /* ?PNG_1_0_X */
-#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
-
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
-/* these functions were added to libpng 1.2.6 */
+/* These functions were added to libpng 1.2.6 and were enabled
+ * by default in libpng-1.4.0 */
png_uint_32 PNGAPI
-png_get_user_width_max (png_structp png_ptr)
+png_get_user_width_max(png_const_structrp png_ptr)
{
- return (png_ptr? png_ptr->user_width_max : 0);
+ return (png_ptr ? png_ptr->user_width_max : 0);
}
+
png_uint_32 PNGAPI
-png_get_user_height_max (png_structp png_ptr)
+png_get_user_height_max(png_const_structrp png_ptr)
{
- return (png_ptr? png_ptr->user_height_max : 0);
+ return (png_ptr ? png_ptr->user_height_max : 0);
}
-#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
+/* This function was added to libpng 1.4.0 */
+png_uint_32 PNGAPI
+png_get_chunk_cache_max(png_const_structrp png_ptr)
+{
+ return (png_ptr ? png_ptr->user_chunk_cache_max : 0);
+}
-#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+/* This function was added to libpng 1.4.1 */
+png_alloc_size_t PNGAPI
+png_get_chunk_malloc_max(png_const_structrp png_ptr)
+{
+ return (png_ptr ? png_ptr->user_chunk_malloc_max : 0);
+}
+#endif /* SET_USER_LIMITS */
+
+/* These functions were added to libpng 1.4.0 */
+#ifdef PNG_IO_STATE_SUPPORTED
+png_uint_32 PNGAPI
+png_get_io_state(png_const_structrp png_ptr)
+{
+ return png_ptr->io_state;
+}
+
+png_uint_32 PNGAPI
+png_get_io_chunk_type(png_const_structrp png_ptr)
+{
+ return png_ptr->chunk_name;
+}
+#endif /* IO_STATE */
+
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+# ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+int PNGAPI
+png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return png_ptr->num_palette_max;
+
+ return -1;
+}
+# endif
+#endif
+
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngmem.c b/PDF/src/pngmem.c
index 248060f38..09ed9c1c9 100644
--- a/PDF/src/pngmem.c
+++ b/PDF/src/pngmem.c
@@ -1,11 +1,14 @@
/* pngmem.c - stub functions for memory allocation
*
- * Last changed in libpng 1.2.13 November 13, 2006
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2006 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* This file provides a location for all memory allocation. Users who
* need special memory handling are expected to supply replacement
@@ -14,569 +17,239 @@
* identify the replacement functions.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-
-/* Borland DOS special memory handler */
-#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
-/* if you change this, be sure to change the one in png.h also */
-
-/* Allocate memory for a png_struct. The malloc and memset can be replaced
- by a single call to calloc() if this is thought to improve performance. */
-png_voidp /* PRIVATE */
-png_create_struct(int type)
-{
-#ifdef PNG_USER_MEM_SUPPORTED
- return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
-}
-
-/* Alternate version of png_create_struct, for use with user-defined malloc. */
-png_voidp /* PRIVATE */
-png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
-{
-#endif /* PNG_USER_MEM_SUPPORTED */
- png_size_t size;
- png_voidp struct_ptr;
-
- if (type == PNG_STRUCT_INFO)
- size = png_sizeof(png_info);
- else if (type == PNG_STRUCT_PNG)
- size = png_sizeof(png_struct);
- else
- return (png_get_copyright(NULL));
-
-#ifdef PNG_USER_MEM_SUPPORTED
- if(malloc_fn != NULL)
- {
- png_struct dummy_struct;
- png_structp png_ptr = &dummy_struct;
- png_ptr->mem_ptr=mem_ptr;
- struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size);
- }
- else
-#endif /* PNG_USER_MEM_SUPPORTED */
- struct_ptr = (png_voidp)farmalloc(size);
- if (struct_ptr != NULL)
- png_memset(struct_ptr, 0, size);
- return (struct_ptr);
-}
-
-/* Free memory allocated by a png_create_struct() call */
+/* Free a png_struct */
void /* PRIVATE */
-png_destroy_struct(png_voidp struct_ptr)
+png_destroy_png_struct(png_structrp png_ptr)
{
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
-}
-
-/* Free memory allocated by a png_create_struct() call */
-void /* PRIVATE */
-png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
- png_voidp mem_ptr)
-{
-#endif
- if (struct_ptr != NULL)
+ if (png_ptr != NULL)
{
-#ifdef PNG_USER_MEM_SUPPORTED
- if(free_fn != NULL)
- {
- png_struct dummy_struct;
- png_structp png_ptr = &dummy_struct;
- png_ptr->mem_ptr=mem_ptr;
- (*(free_fn))(png_ptr, struct_ptr);
- return;
- }
-#endif /* PNG_USER_MEM_SUPPORTED */
- farfree (struct_ptr);
+ /* png_free might call png_error and may certainly call
+ * png_get_mem_ptr, so fake a temporary png_struct to support this.
+ */
+ png_struct dummy_struct = *png_ptr;
+ memset(png_ptr, 0, (sizeof *png_ptr));
+ png_free(&dummy_struct, png_ptr);
+
+# ifdef PNG_SETJMP_SUPPORTED
+ /* We may have a jmp_buf left to deallocate. */
+ png_free_jmpbuf(&dummy_struct);
+# endif
}
}
/* Allocate memory. For reasonable files, size should never exceed
- * 64K. However, zlib may allocate more then 64K if you don't tell
- * it not to. See zconf.h and png.h for more information. zlib does
+ * 64K. However, zlib may allocate more than 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
* need to allocate exactly 64K, so whatever you call here must
* have the ability to do that.
- *
- * Borland seems to have a problem in DOS mode for exactly 64K.
- * It gives you a segment with an offset of 8 (perhaps to store its
- * memory stuff). zlib doesn't like this at all, so we have to
- * detect and deal with it. This code should not be needed in
- * Windows or OS/2 modes, and only in 16 bit mode. This code has
- * been updated by Alexander Lehmann for version 0.89 to waste less
- * memory.
- *
- * Note that we can't use png_size_t for the "size" declaration,
- * since on some systems a png_size_t is a 16-bit quantity, and as a
- * result, we would be truncating potentially larger memory requests
- * (which should cause a fatal error) and introducing major problems.
*/
-
-png_voidp PNGAPI
-png_malloc(png_structp png_ptr, png_uint_32 size)
+PNG_FUNCTION(png_voidp,PNGAPI
+png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
{
png_voidp ret;
- if (png_ptr == NULL || size == 0)
- return (NULL);
+ ret = png_malloc(png_ptr, size);
-#ifdef PNG_USER_MEM_SUPPORTED
- if(png_ptr->malloc_fn != NULL)
- ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
- else
- ret = (png_malloc_default(png_ptr, size));
- if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out of memory!");
- return (ret);
+ if (ret != NULL)
+ memset(ret, 0, size);
+
+ return ret;
}
-png_voidp PNGAPI
-png_malloc_default(png_structp png_ptr, png_uint_32 size)
+/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of
+ * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED.
+ * Checking and error handling must happen outside this routine; it returns NULL
+ * if the allocation cannot be done (for any reason.)
+ */
+PNG_FUNCTION(png_voidp /* PRIVATE */,
+png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),
+ PNG_ALLOCATED)
+{
+ /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS
+ * allocators have also been removed in 1.6.0, so any 16-bit system now has
+ * 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
+
+ /* Some compilers complain that this is always true. However, it
+ * can be false when integer overflow happens.
+ */
+ if (size > 0 && size <= PNG_SIZE_MAX
+# ifdef PNG_MAX_MALLOC_64K
+ && size <= 65536U
+# endif
+ )
+ {
+#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
+#endif
+ return malloc((size_t)size); /* checked for truncation above */
+ }
+
+ else
+ return NULL;
+}
+
+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\
+ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)
+/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7
+ * that arises because of the checks in png_realloc_array that are repeated in
+ * png_malloc_array.
+ */
+static png_voidp
+png_malloc_array_checked(png_const_structrp png_ptr, int nelements,
+ size_t element_size)
+{
+ png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */
+
+ if (req <= PNG_SIZE_MAX/element_size)
+ return png_malloc_base(png_ptr, req * element_size);
+
+ /* The failure case when the request is too large */
+ return NULL;
+}
+
+PNG_FUNCTION(png_voidp /* PRIVATE */,
+png_malloc_array,(png_const_structrp png_ptr, int nelements,
+ size_t element_size),PNG_ALLOCATED)
+{
+ if (nelements <= 0 || element_size == 0)
+ png_error(png_ptr, "internal error: array alloc");
+
+ return png_malloc_array_checked(png_ptr, nelements, element_size);
+}
+
+PNG_FUNCTION(png_voidp /* PRIVATE */,
+png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array,
+ int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED)
+{
+ /* These are internal errors: */
+ if (add_elements <= 0 || element_size == 0 || old_elements < 0 ||
+ (old_array == NULL && old_elements > 0))
+ png_error(png_ptr, "internal error: array realloc");
+
+ /* Check for overflow on the elements count (so the caller does not have to
+ * check.)
+ */
+ if (add_elements <= INT_MAX - old_elements)
+ {
+ png_voidp new_array = png_malloc_array_checked(png_ptr,
+ old_elements+add_elements, element_size);
+
+ if (new_array != NULL)
+ {
+ /* Because png_malloc_array worked the size calculations below cannot
+ * overflow.
+ */
+ if (old_elements > 0)
+ memcpy(new_array, old_array, element_size*(unsigned)old_elements);
+
+ memset((char*)new_array + element_size*(unsigned)old_elements, 0,
+ element_size*(unsigned)add_elements);
+
+ return new_array;
+ }
+ }
+
+ return NULL; /* error */
+}
+#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */
+
+/* Various functions that have different error handling are derived from this.
+ * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate
+ * function png_malloc_default is also provided.
+ */
+PNG_FUNCTION(png_voidp,PNGAPI
+png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
{
png_voidp ret;
-#endif /* PNG_USER_MEM_SUPPORTED */
- if (png_ptr == NULL || size == 0)
- return (NULL);
+ if (png_ptr == NULL)
+ return NULL;
-#ifdef PNG_MAX_MALLOC_64K
- if (size > (png_uint_32)65536L)
- {
- png_warning(png_ptr, "Cannot Allocate > 64K");
- ret = NULL;
- }
- else
-#endif
+ ret = png_malloc_base(png_ptr, size);
- if (size != (size_t)size)
- ret = NULL;
- else if (size == (png_uint_32)65536L)
- {
- if (png_ptr->offset_table == NULL)
- {
- /* try to see if we need to do any of this fancy stuff */
- ret = farmalloc(size);
- if (ret == NULL || ((png_size_t)ret & 0xffff))
- {
- int num_blocks;
- png_uint_32 total_size;
- png_bytep table;
- int i;
- png_byte huge * hptr;
-
- if (ret != NULL)
- {
- farfree(ret);
- ret = NULL;
- }
-
- if(png_ptr->zlib_window_bits > 14)
- num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
- else
- num_blocks = 1;
- if (png_ptr->zlib_mem_level >= 7)
- num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
- else
- num_blocks++;
-
- total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
-
- table = farmalloc(total_size);
-
- if (table == NULL)
- {
-#ifndef PNG_USER_MEM_SUPPORTED
- if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
- else
- png_warning(png_ptr, "Out Of Memory.");
-#endif
- return (NULL);
- }
-
- if ((png_size_t)table & 0xfff0)
- {
-#ifndef PNG_USER_MEM_SUPPORTED
- if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr,
- "Farmalloc didn't return normalized pointer");
- else
- png_warning(png_ptr,
- "Farmalloc didn't return normalized pointer");
-#endif
- return (NULL);
- }
-
- png_ptr->offset_table = table;
- png_ptr->offset_table_ptr = farmalloc(num_blocks *
- png_sizeof (png_bytep));
-
- if (png_ptr->offset_table_ptr == NULL)
- {
-#ifndef PNG_USER_MEM_SUPPORTED
- if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */
- else
- png_warning(png_ptr, "Out Of memory.");
-#endif
- return (NULL);
- }
-
- hptr = (png_byte huge *)table;
- if ((png_size_t)hptr & 0xf)
- {
- hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
- hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */
- }
- for (i = 0; i < num_blocks; i++)
- {
- png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
- hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */
- }
-
- png_ptr->offset_table_number = num_blocks;
- png_ptr->offset_table_count = 0;
- png_ptr->offset_table_count_free = 0;
- }
- }
-
- if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
- {
-#ifndef PNG_USER_MEM_SUPPORTED
- if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */
- else
- png_warning(png_ptr, "Out of Memory.");
-#endif
- return (NULL);
- }
-
- ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
- }
- else
- ret = farmalloc(size);
-
-#ifndef PNG_USER_MEM_SUPPORTED
if (ret == NULL)
- {
- if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
- else
- png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */
- }
-#endif
+ png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */
- return (ret);
+ return ret;
}
-/* free a pointer allocated by png_malloc(). In the default
- configuration, png_ptr is not used, but is passed in case it
- is needed. If ptr is NULL, return without taking any action. */
-void PNGAPI
-png_free(png_structp png_ptr, png_voidp ptr)
-{
- if (png_ptr == NULL || ptr == NULL)
- return;
-
#ifdef PNG_USER_MEM_SUPPORTED
- if (png_ptr->free_fn != NULL)
- {
- (*(png_ptr->free_fn))(png_ptr, ptr);
- return;
- }
- else png_free_default(png_ptr, ptr);
-}
-
-void PNGAPI
-png_free_default(png_structp png_ptr, png_voidp ptr)
-{
-#endif /* PNG_USER_MEM_SUPPORTED */
-
- if(png_ptr == NULL) return;
-
- if (png_ptr->offset_table != NULL)
- {
- int i;
-
- for (i = 0; i < png_ptr->offset_table_count; i++)
- {
- if (ptr == png_ptr->offset_table_ptr[i])
- {
- ptr = NULL;
- png_ptr->offset_table_count_free++;
- break;
- }
- }
- if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
- {
- farfree(png_ptr->offset_table);
- farfree(png_ptr->offset_table_ptr);
- png_ptr->offset_table = NULL;
- png_ptr->offset_table_ptr = NULL;
- }
- }
-
- if (ptr != NULL)
- {
- farfree(ptr);
- }
-}
-
-#else /* Not the Borland DOS special memory handler */
-
-/* Allocate memory for a png_struct or a png_info. The malloc and
- memset can be replaced by a single call to calloc() if this is thought
- to improve performance noticably. */
-png_voidp /* PRIVATE */
-png_create_struct(int type)
-{
-#ifdef PNG_USER_MEM_SUPPORTED
- return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
-}
-
-/* Allocate memory for a png_struct or a png_info. The malloc and
- memset can be replaced by a single call to calloc() if this is thought
- to improve performance noticably. */
-png_voidp /* PRIVATE */
-png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
-{
-#endif /* PNG_USER_MEM_SUPPORTED */
- png_size_t size;
- png_voidp struct_ptr;
-
- if (type == PNG_STRUCT_INFO)
- size = png_sizeof(png_info);
- else if (type == PNG_STRUCT_PNG)
- size = png_sizeof(png_struct);
- else
- return (NULL);
-
-#ifdef PNG_USER_MEM_SUPPORTED
- if(malloc_fn != NULL)
- {
- png_struct dummy_struct;
- png_structp png_ptr = &dummy_struct;
- png_ptr->mem_ptr=mem_ptr;
- struct_ptr = (*(malloc_fn))(png_ptr, size);
- if (struct_ptr != NULL)
- png_memset(struct_ptr, 0, size);
- return (struct_ptr);
- }
-#endif /* PNG_USER_MEM_SUPPORTED */
-
-#if defined(__TURBOC__) && !defined(__FLAT__)
- struct_ptr = (png_voidp)farmalloc(size);
-#else
-# if defined(_MSC_VER) && defined(MAXSEG_64K)
- struct_ptr = (png_voidp)halloc(size,1);
-# else
- struct_ptr = (png_voidp)malloc(size);
-# endif
-#endif
- if (struct_ptr != NULL)
- png_memset(struct_ptr, 0, size);
-
- return (struct_ptr);
-}
-
-
-/* Free memory allocated by a png_create_struct() call */
-void /* PRIVATE */
-png_destroy_struct(png_voidp struct_ptr)
-{
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
-}
-
-/* Free memory allocated by a png_create_struct() call */
-void /* PRIVATE */
-png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
- png_voidp mem_ptr)
-{
-#endif /* PNG_USER_MEM_SUPPORTED */
- if (struct_ptr != NULL)
- {
-#ifdef PNG_USER_MEM_SUPPORTED
- if(free_fn != NULL)
- {
- png_struct dummy_struct;
- png_structp png_ptr = &dummy_struct;
- png_ptr->mem_ptr=mem_ptr;
- (*(free_fn))(png_ptr, struct_ptr);
- return;
- }
-#endif /* PNG_USER_MEM_SUPPORTED */
-#if defined(__TURBOC__) && !defined(__FLAT__)
- farfree(struct_ptr);
-#else
-# if defined(_MSC_VER) && defined(MAXSEG_64K)
- hfree(struct_ptr);
-# else
- free(struct_ptr);
-# endif
-#endif
- }
-}
-
-/* Allocate memory. For reasonable files, size should never exceed
- 64K. However, zlib may allocate more then 64K if you don't tell
- it not to. See zconf.h and png.h for more information. zlib does
- need to allocate exactly 64K, so whatever you call here must
- have the ability to do that. */
-
-png_voidp PNGAPI
-png_malloc(png_structp png_ptr, png_uint_32 size)
+PNG_FUNCTION(png_voidp,PNGAPI
+png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size),
+ PNG_ALLOCATED PNG_DEPRECATED)
{
png_voidp ret;
-#ifdef PNG_USER_MEM_SUPPORTED
- if (png_ptr == NULL || size == 0)
- return (NULL);
+ if (png_ptr == NULL)
+ return NULL;
- if(png_ptr->malloc_fn != NULL)
- ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
- else
- ret = (png_malloc_default(png_ptr, size));
- if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out of Memory!");
- return (ret);
+ /* Passing 'NULL' here bypasses the application provided memory handler. */
+ ret = png_malloc_base(NULL/*use malloc*/, size);
+
+ if (ret == NULL)
+ png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */
+
+ return ret;
}
+#endif /* USER_MEM */
-png_voidp PNGAPI
-png_malloc_default(png_structp png_ptr, png_uint_32 size)
+/* This function was added at libpng version 1.2.3. The png_malloc_warn()
+ * function will issue a png_warning and return NULL instead of issuing a
+ * png_error, if it fails to allocate the requested memory.
+ */
+PNG_FUNCTION(png_voidp,PNGAPI
+png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size),
+ PNG_ALLOCATED)
{
- png_voidp ret;
-#endif /* PNG_USER_MEM_SUPPORTED */
-
- if (png_ptr == NULL || size == 0)
- return (NULL);
-
-#ifdef PNG_MAX_MALLOC_64K
- if (size > (png_uint_32)65536L)
+ if (png_ptr != NULL)
{
-#ifndef PNG_USER_MEM_SUPPORTED
- if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Cannot Allocate > 64K");
- else
-#endif
- return NULL;
+ png_voidp ret = png_malloc_base(png_ptr, size);
+
+ if (ret != NULL)
+ return ret;
+
+ png_warning(png_ptr, "Out of memory");
}
-#endif
- /* Check for overflow */
-#if defined(__TURBOC__) && !defined(__FLAT__)
- if (size != (unsigned long)size)
- ret = NULL;
- else
- ret = farmalloc(size);
-#else
-# if defined(_MSC_VER) && defined(MAXSEG_64K)
- if (size != (unsigned long)size)
- ret = NULL;
- else
- ret = halloc(size, 1);
-# else
- if (size != (size_t)size)
- ret = NULL;
- else
- ret = malloc((size_t)size);
-# endif
-#endif
-
-#ifndef PNG_USER_MEM_SUPPORTED
- if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
- png_error(png_ptr, "Out of Memory");
-#endif
-
- return (ret);
+ return NULL;
}
/* Free a pointer allocated by png_malloc(). If ptr is NULL, return
- without taking any action. */
+ * without taking any action.
+ */
void PNGAPI
-png_free(png_structp png_ptr, png_voidp ptr)
+png_free(png_const_structrp png_ptr, png_voidp ptr)
{
if (png_ptr == NULL || ptr == NULL)
return;
#ifdef PNG_USER_MEM_SUPPORTED
if (png_ptr->free_fn != NULL)
- {
- (*(png_ptr->free_fn))(png_ptr, ptr);
- return;
- }
- else png_free_default(png_ptr, ptr);
+ png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr);
+
+ else
+ png_free_default(png_ptr, ptr);
}
-void PNGAPI
-png_free_default(png_structp png_ptr, png_voidp ptr)
+
+PNG_FUNCTION(void,PNGAPI
+png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED)
{
if (png_ptr == NULL || ptr == NULL)
return;
+#endif /* USER_MEM */
-#endif /* PNG_USER_MEM_SUPPORTED */
-
-#if defined(__TURBOC__) && !defined(__FLAT__)
- farfree(ptr);
-#else
-# if defined(_MSC_VER) && defined(MAXSEG_64K)
- hfree(ptr);
-# else
free(ptr);
-# endif
-#endif
-}
-
-#endif /* Not Borland DOS special memory handler */
-
-#if defined(PNG_1_0_X)
-# define png_malloc_warn png_malloc
-#else
-/* This function was added at libpng version 1.2.3. The png_malloc_warn()
- * function will set up png_malloc() to issue a png_warning and return NULL
- * instead of issuing a png_error, if it fails to allocate the requested
- * memory.
- */
-png_voidp PNGAPI
-png_malloc_warn(png_structp png_ptr, png_uint_32 size)
-{
- png_voidp ptr;
- png_uint_32 save_flags;
- if(png_ptr == NULL) return (NULL);
-
- save_flags=png_ptr->flags;
- png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
- ptr = (png_voidp)png_malloc((png_structp)png_ptr, size);
- png_ptr->flags=save_flags;
- return(ptr);
-}
-#endif
-
-png_voidp PNGAPI
-png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
- png_uint_32 length)
-{
- png_size_t size;
-
- size = (png_size_t)length;
- if ((png_uint_32)size != length)
- png_error(png_ptr,"Overflow in png_memcpy_check.");
-
- return(png_memcpy (s1, s2, size));
-}
-
-png_voidp PNGAPI
-png_memset_check (png_structp png_ptr, png_voidp s1, int value,
- png_uint_32 length)
-{
- png_size_t size;
-
- size = (png_size_t)length;
- if ((png_uint_32)size != length)
- png_error(png_ptr,"Overflow in png_memset_check.");
-
- return (png_memset (s1, value, size));
-
}
#ifdef PNG_USER_MEM_SUPPORTED
@@ -584,13 +257,14 @@ png_memset_check (png_structp png_ptr, png_voidp s1, int value,
* of allocating and freeing memory.
*/
void PNGAPI
-png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
+png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr
malloc_fn, png_free_ptr free_fn)
{
- if(png_ptr != NULL) {
- png_ptr->mem_ptr = mem_ptr;
- png_ptr->malloc_fn = malloc_fn;
- png_ptr->free_fn = free_fn;
+ if (png_ptr != NULL)
+ {
+ png_ptr->mem_ptr = mem_ptr;
+ png_ptr->malloc_fn = malloc_fn;
+ png_ptr->free_fn = free_fn;
}
}
@@ -599,10 +273,12 @@ png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
* pointer before png_write_destroy and png_read_destroy are called.
*/
png_voidp PNGAPI
-png_get_mem_ptr(png_structp png_ptr)
+png_get_mem_ptr(png_const_structrp png_ptr)
{
- if(png_ptr == NULL) return (NULL);
- return ((png_voidp)png_ptr->mem_ptr);
+ if (png_ptr == NULL)
+ return NULL;
+
+ return png_ptr->mem_ptr;
}
-#endif /* PNG_USER_MEM_SUPPORTED */
-#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+#endif /* USER_MEM */
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngpread.c b/PDF/src/pngpread.c
index c5ad75c33..ffab19c08 100644
--- a/PDF/src/pngpread.c
+++ b/PDF/src/pngpread.c
@@ -1,34 +1,44 @@
/* pngpread.c - read a png file in push mode
*
- * Last changed in libpng 1.2.23 [November 6, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-/* push model modes */
+/* Push model modes */
#define PNG_READ_SIG_MODE 0
#define PNG_READ_CHUNK_MODE 1
#define PNG_READ_IDAT_MODE 2
-#define PNG_SKIP_MODE 3
#define PNG_READ_tEXt_MODE 4
#define PNG_READ_zTXt_MODE 5
#define PNG_READ_DONE_MODE 6
#define PNG_READ_iTXt_MODE 7
#define PNG_ERROR_MODE 8
+#define PNG_PUSH_SAVE_BUFFER_IF_FULL \
+if (png_ptr->push_length + 4 > png_ptr->buffer_size) \
+ { png_push_save_buffer(png_ptr); return; }
+#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \
+if (png_ptr->buffer_size < N) \
+ { png_push_save_buffer(png_ptr); return; }
+
void PNGAPI
-png_process_data(png_structp png_ptr, png_infop info_ptr,
- png_bytep buffer, png_size_t buffer_size)
+png_process_data(png_structrp png_ptr, png_inforp info_ptr,
+ png_bytep buffer, size_t buffer_size)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
png_push_restore_buffer(png_ptr, buffer, buffer_size);
while (png_ptr->buffer_size)
@@ -37,13 +47,55 @@ png_process_data(png_structp png_ptr, png_infop info_ptr,
}
}
+size_t PNGAPI
+png_process_data_pause(png_structrp png_ptr, int save)
+{
+ if (png_ptr != NULL)
+ {
+ /* It's easiest for the caller if we do the save; then the caller doesn't
+ * have to supply the same data again:
+ */
+ if (save != 0)
+ png_push_save_buffer(png_ptr);
+ else
+ {
+ /* This includes any pending saved bytes: */
+ size_t remaining = png_ptr->buffer_size;
+ png_ptr->buffer_size = 0;
+
+ /* So subtract the saved buffer size, unless all the data
+ * is actually 'saved', in which case we just return 0
+ */
+ if (png_ptr->save_buffer_size < remaining)
+ return remaining - png_ptr->save_buffer_size;
+ }
+ }
+
+ return 0;
+}
+
+png_uint_32 PNGAPI
+png_process_data_skip(png_structrp png_ptr)
+{
+/* TODO: Deprecate and remove this API.
+ * Somewhere the implementation of this seems to have been lost,
+ * or abandoned. It was only to support some internal back-door access
+ * to png_struct) in libpng-1.4.x.
+ */
+ png_app_warning(png_ptr,
+"png_process_data_skip is not implemented in any current version of libpng");
+ return 0;
+}
+
/* What we do with the incoming data depends on what we were previously
* doing before we ran out of data...
*/
void /* PRIVATE */
-png_process_some_data(png_structp png_ptr, png_infop info_ptr)
+png_process_some_data(png_structrp png_ptr, png_inforp info_ptr)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
switch (png_ptr->process_mode)
{
case PNG_READ_SIG_MODE:
@@ -51,42 +103,19 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
png_push_read_sig(png_ptr, info_ptr);
break;
}
+
case PNG_READ_CHUNK_MODE:
{
png_push_read_chunk(png_ptr, info_ptr);
break;
}
+
case PNG_READ_IDAT_MODE:
{
png_push_read_IDAT(png_ptr);
break;
}
-#if defined(PNG_READ_tEXt_SUPPORTED)
- case PNG_READ_tEXt_MODE:
- {
- png_push_read_tEXt(png_ptr, info_ptr);
- break;
- }
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- case PNG_READ_zTXt_MODE:
- {
- png_push_read_zTXt(png_ptr, info_ptr);
- break;
- }
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- case PNG_READ_iTXt_MODE:
- {
- png_push_read_iTXt(png_ptr, info_ptr);
- break;
- }
-#endif
- case PNG_SKIP_MODE:
- {
- png_push_crc_finish(png_ptr);
- break;
- }
+
default:
{
png_ptr->buffer_size = 0;
@@ -102,10 +131,10 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
* routine.
*/
void /* PRIVATE */
-png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
+png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)
{
- png_size_t num_checked = png_ptr->sig_bytes,
- num_to_check = 8 - num_checked;
+ size_t num_checked = png_ptr->sig_bytes; /* SAFE, does not exceed 8 */
+ size_t num_to_check = 8 - num_checked;
if (png_ptr->buffer_size < num_to_check)
{
@@ -113,14 +142,15 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
}
png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),
- num_to_check);
- png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes+num_to_check);
+ num_to_check);
+ png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);
- if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
{
if (num_checked < 4 &&
- png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
png_error(png_ptr, "Not a PNG file");
+
else
png_error(png_ptr, "PNG file corrupted by ASCII conversion");
}
@@ -134,463 +164,304 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
}
void /* PRIVATE */
-png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
+png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IHDR;
- PNG_CONST PNG_IDAT;
- PNG_CONST PNG_IEND;
- PNG_CONST PNG_PLTE;
-#if defined(PNG_READ_bKGD_SUPPORTED)
- PNG_CONST PNG_bKGD;
+ png_uint_32 chunk_name;
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ int keep; /* unknown handling method */
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- PNG_CONST PNG_cHRM;
-#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
- PNG_CONST PNG_gAMA;
-#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
- PNG_CONST PNG_hIST;
-#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
- PNG_CONST PNG_iCCP;
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- PNG_CONST PNG_iTXt;
-#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- PNG_CONST PNG_oFFs;
-#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- PNG_CONST PNG_pCAL;
-#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- PNG_CONST PNG_pHYs;
-#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- PNG_CONST PNG_sBIT;
-#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- PNG_CONST PNG_sCAL;
-#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- PNG_CONST PNG_sRGB;
-#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- PNG_CONST PNG_sPLT;
-#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- PNG_CONST PNG_tEXt;
-#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- PNG_CONST PNG_tIME;
-#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- PNG_CONST PNG_tRNS;
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- PNG_CONST PNG_zTXt;
-#endif
-#endif /* PNG_USE_LOCAL_ARRAYS */
- /* First we make sure we have enough data for the 4 byte chunk name
- * and the 4 byte chunk length before proceeding with decoding the
+
+ /* First we make sure we have enough data for the 4-byte chunk name
+ * and the 4-byte chunk length before proceeding with decoding the
* chunk data. To fully decode each of these chunks, we also make
- * sure we have enough data in the buffer for the 4 byte CRC at the
+ * sure we have enough data in the buffer for the 4-byte CRC at the
* end of every chunk (except IDAT, which is handled separately).
*/
- if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)
{
png_byte chunk_length[4];
+ png_byte chunk_tag[4];
- if (png_ptr->buffer_size < 8)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
+ 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_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ 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->mode |= PNG_HAVE_CHUNK_HEADER;
}
- if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- if(png_ptr->mode & PNG_AFTER_IDAT)
- png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+ chunk_name = png_ptr->chunk_name;
- if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ if (chunk_name == png_IDAT)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+
+ /* If we reach an IDAT chunk, this means we have read all of the
+ * header chunks, and we can start reading the image (or if this
+ * is called after the image has been read - we have an error).
+ */
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_error(png_ptr, "Missing IHDR before IDAT");
+
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ (png_ptr->mode & PNG_HAVE_PLTE) == 0)
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
+ if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0)
+ if (png_ptr->push_length == 0)
+ return;
+
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+ png_benign_error(png_ptr, "Too many IDATs found");
+ }
+
+ 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);
}
- else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+
+ else if (chunk_name == png_IEND)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
png_ptr->process_mode = PNG_READ_DONE_MODE;
png_push_have_end(png_ptr, info_ptr);
}
+
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
- else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- png_ptr->mode |= PNG_HAVE_IDAT;
- png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
- if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
+ png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep);
+
+ if (chunk_name == png_PLTE)
png_ptr->mode |= PNG_HAVE_PLTE;
- else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- {
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before IDAT");
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
- png_error(png_ptr, "Missing PLTE before IDAT");
- }
}
#endif
- else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+
+ else if (chunk_name == png_PLTE)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
}
- else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+
+ else if (chunk_name == png_IDAT)
{
- /* If we reach an IDAT chunk, this means we have read all of the
- * header chunks, and we can start reading the image (or if this
- * is called after the image has been read - we have an error).
- */
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before IDAT");
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
- png_error(png_ptr, "Missing PLTE before IDAT");
-
- if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
- if (png_ptr->push_length == 0)
- return;
-
- if (png_ptr->mode & PNG_AFTER_IDAT)
- png_error(png_ptr, "Too many IDAT's found");
- }
-
png_ptr->idat_size = png_ptr->push_length;
- png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->process_mode = PNG_READ_IDAT_MODE;
png_push_have_info(png_ptr, info_ptr);
- png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.avail_out =
+ (uInt) PNG_ROWBYTES(png_ptr->pixel_depth,
+ png_ptr->iwidth) + 1;
png_ptr->zstream.next_out = png_ptr->row_buf;
return;
}
-#if defined(PNG_READ_gAMA_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+
+#ifdef PNG_READ_gAMA_SUPPORTED
+ else if (png_ptr->chunk_name == png_gAMA)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+#ifdef PNG_READ_sBIT_SUPPORTED
+ else if (png_ptr->chunk_name == png_sBIT)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+#ifdef PNG_READ_cHRM_SUPPORTED
+ else if (png_ptr->chunk_name == png_cHRM)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+#ifdef PNG_READ_eXIf_SUPPORTED
+ else if (png_ptr->chunk_name == png_eXIf)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ 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
-#if defined(PNG_READ_iCCP_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+#ifdef PNG_READ_iCCP_SUPPORTED
+ else if (png_ptr->chunk_name == png_iCCP)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+#ifdef PNG_READ_sPLT_SUPPORTED
+ else if (chunk_name == png_sPLT)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+#ifdef PNG_READ_tRNS_SUPPORTED
+ else if (chunk_name == png_tRNS)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_bKGD_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+#ifdef PNG_READ_bKGD_SUPPORTED
+ else if (chunk_name == png_bKGD)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+#ifdef PNG_READ_hIST_SUPPORTED
+ else if (chunk_name == png_hIST)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+#ifdef PNG_READ_pHYs_SUPPORTED
+ else if (chunk_name == png_pHYs)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+#ifdef PNG_READ_oFFs_SUPPORTED
+ else if (chunk_name == png_oFFs)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+
+#ifdef PNG_READ_pCAL_SUPPORTED
+ else if (chunk_name == png_pCAL)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+#ifdef PNG_READ_sCAL_SUPPORTED
+ else if (chunk_name == png_sCAL)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+#ifdef PNG_READ_tIME_SUPPORTED
+ else if (chunk_name == png_tIME)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
}
+
#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+#ifdef PNG_READ_tEXt_SUPPORTED
+ else if (chunk_name == png_tEXt)
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
- }
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
- }
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ 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
{
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
+ png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
}
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
}
-void /* PRIVATE */
-png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
-{
- png_ptr->process_mode = PNG_SKIP_MODE;
- png_ptr->skip_length = skip;
-}
-
-void /* PRIVATE */
-png_push_crc_finish(png_structp png_ptr)
-{
- if (png_ptr->skip_length && png_ptr->save_buffer_size)
- {
- png_size_t save_size;
-
- if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
- save_size = (png_size_t)png_ptr->skip_length;
- else
- save_size = png_ptr->save_buffer_size;
-
- png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
-
- png_ptr->skip_length -= save_size;
- png_ptr->buffer_size -= save_size;
- png_ptr->save_buffer_size -= save_size;
- png_ptr->save_buffer_ptr += save_size;
- }
- if (png_ptr->skip_length && png_ptr->current_buffer_size)
- {
- png_size_t save_size;
-
- if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
- save_size = (png_size_t)png_ptr->skip_length;
- else
- save_size = png_ptr->current_buffer_size;
-
- png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
-
- png_ptr->skip_length -= save_size;
- png_ptr->buffer_size -= save_size;
- png_ptr->current_buffer_size -= save_size;
- png_ptr->current_buffer_ptr += save_size;
- }
- if (!png_ptr->skip_length)
- {
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_crc_finish(png_ptr, 0);
- png_ptr->process_mode = PNG_READ_CHUNK_MODE;
- }
-}
-
-void PNGAPI
-png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
+void PNGCBAPI
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length)
{
png_bytep ptr;
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
ptr = buffer;
- if (png_ptr->save_buffer_size)
+ if (png_ptr->save_buffer_size != 0)
{
- png_size_t save_size;
+ size_t save_size;
if (length < png_ptr->save_buffer_size)
save_size = length;
+
else
save_size = png_ptr->save_buffer_size;
- png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
+ memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
length -= save_size;
ptr += save_size;
png_ptr->buffer_size -= save_size;
png_ptr->save_buffer_size -= save_size;
png_ptr->save_buffer_ptr += save_size;
}
- if (length && png_ptr->current_buffer_size)
+ if (length != 0 && png_ptr->current_buffer_size != 0)
{
- png_size_t save_size;
+ size_t save_size;
if (length < png_ptr->current_buffer_size)
save_size = length;
+
else
save_size = png_ptr->current_buffer_size;
- png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
+ memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
png_ptr->buffer_size -= save_size;
png_ptr->current_buffer_size -= save_size;
png_ptr->current_buffer_ptr += save_size;
@@ -598,46 +469,57 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
}
void /* PRIVATE */
-png_push_save_buffer(png_structp png_ptr)
+png_push_save_buffer(png_structrp png_ptr)
{
- if (png_ptr->save_buffer_size)
+ if (png_ptr->save_buffer_size != 0)
{
if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
{
- png_size_t i,istop;
+ size_t i, istop;
png_bytep sp;
png_bytep dp;
istop = png_ptr->save_buffer_size;
for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
- i < istop; i++, sp++, dp++)
+ i < istop; i++, sp++, dp++)
{
*dp = *sp;
}
}
}
if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
- png_ptr->save_buffer_max)
+ png_ptr->save_buffer_max)
{
- png_size_t new_max;
+ size_t new_max;
png_bytep old_buffer;
if (png_ptr->save_buffer_size > PNG_SIZE_MAX -
- (png_ptr->current_buffer_size + 256))
+ (png_ptr->current_buffer_size + 256))
{
- png_error(png_ptr, "Potential overflow of save_buffer");
+ png_error(png_ptr, "Potential overflow of save_buffer");
}
+
new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
old_buffer = png_ptr->save_buffer;
- png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)new_max);
- png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,
+ (size_t)new_max);
+
+ if (png_ptr->save_buffer == NULL)
+ {
+ png_free(png_ptr, old_buffer);
+ png_error(png_ptr, "Insufficient memory for save_buffer");
+ }
+
+ if (old_buffer)
+ memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ else if (png_ptr->save_buffer_size)
+ png_error(png_ptr, "save_buffer error");
png_free(png_ptr, old_buffer);
png_ptr->save_buffer_max = new_max;
}
if (png_ptr->current_buffer_size)
{
- png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+ memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
png_ptr->save_buffer_size += png_ptr->current_buffer_size;
png_ptr->current_buffer_size = 0;
@@ -647,8 +529,8 @@ png_push_save_buffer(png_structp png_ptr)
}
void /* PRIVATE */
-png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
- png_size_t buffer_length)
+png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer,
+ size_t buffer_length)
{
png_ptr->current_buffer = buffer;
png_ptr->current_buffer_size = buffer_length;
@@ -657,219 +539,303 @@ png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
}
void /* PRIVATE */
-png_push_read_IDAT(png_structp png_ptr)
+png_push_read_IDAT(png_structrp png_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IDAT;
-#endif
- if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)
{
png_byte chunk_length[4];
+ png_byte chunk_tag[4];
- if (png_ptr->buffer_size < 8)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
+ /* TODO: this code can be commoned up with the same code in push_read */
+ 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_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_crc_read(png_ptr, chunk_tag, 4);
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
- if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ if (png_ptr->chunk_name != png_IDAT)
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
png_error(png_ptr, "Not enough compressed data");
+
return;
}
png_ptr->idat_size = png_ptr->push_length;
}
- if (png_ptr->idat_size && png_ptr->save_buffer_size)
- {
- png_size_t save_size;
- if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
- {
- save_size = (png_size_t)png_ptr->idat_size;
- /* check for overflow */
- if((png_uint_32)save_size != png_ptr->idat_size)
- png_error(png_ptr, "save_size overflowed in pngpread");
- }
+ if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+ {
+ size_t save_size = png_ptr->save_buffer_size;
+ png_uint_32 idat_size = png_ptr->idat_size;
+
+ /* We want the smaller of 'idat_size' and 'current_buffer_size', but they
+ * are of different types and we don't know which variable has the fewest
+ * bits. Carefully select the smaller and cast it to the type of the
+ * larger - this cannot overflow. Do not cast in the following test - it
+ * will break on either 16-bit or 64-bit platforms.
+ */
+ if (idat_size < save_size)
+ save_size = (size_t)idat_size;
+
else
- save_size = png_ptr->save_buffer_size;
+ idat_size = (png_uint_32)save_size;
png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
- png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
- png_ptr->idat_size -= save_size;
+
+ png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= idat_size;
png_ptr->buffer_size -= save_size;
png_ptr->save_buffer_size -= save_size;
png_ptr->save_buffer_ptr += save_size;
}
- if (png_ptr->idat_size && png_ptr->current_buffer_size)
- {
- png_size_t save_size;
- if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
- {
- save_size = (png_size_t)png_ptr->idat_size;
- /* check for overflow */
- if((png_uint_32)save_size != png_ptr->idat_size)
- png_error(png_ptr, "save_size overflowed in pngpread");
- }
+ if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0)
+ {
+ size_t save_size = png_ptr->current_buffer_size;
+ png_uint_32 idat_size = png_ptr->idat_size;
+
+ /* We want the smaller of 'idat_size' and 'current_buffer_size', but they
+ * are of different types and we don't know which variable has the fewest
+ * bits. Carefully select the smaller and cast it to the type of the
+ * larger - this cannot overflow.
+ */
+ if (idat_size < save_size)
+ save_size = (size_t)idat_size;
+
else
- save_size = png_ptr->current_buffer_size;
+ idat_size = (png_uint_32)save_size;
png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
- png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
- png_ptr->idat_size -= save_size;
+ png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= idat_size;
png_ptr->buffer_size -= save_size;
png_ptr->current_buffer_size -= save_size;
png_ptr->current_buffer_ptr += save_size;
}
- if (!png_ptr->idat_size)
- {
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
+ if (png_ptr->idat_size == 0)
+ {
+ PNG_PUSH_SAVE_BUFFER_IF_LT(4)
png_crc_finish(png_ptr, 0);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->zowner = 0;
}
}
void /* PRIVATE */
-png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
- png_size_t buffer_length)
+png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
+ size_t buffer_length)
{
- int ret;
-
- if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)
- png_error(png_ptr, "Extra compression data");
+ /* The caller checks for a non-zero buffer length. */
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+ */
png_ptr->zstream.next_in = buffer;
+ /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */
png_ptr->zstream.avail_in = (uInt)buffer_length;
- for(;;)
- {
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret != Z_OK)
- {
- if (ret == Z_STREAM_END)
- {
- if (png_ptr->zstream.avail_in)
- png_error(png_ptr, "Extra compressed data");
- if (!(png_ptr->zstream.avail_out))
- {
- png_push_process_row(png_ptr);
- }
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
- else if (ret == Z_BUF_ERROR)
- break;
- else
- png_error(png_ptr, "Decompression Error");
- }
- if (!(png_ptr->zstream.avail_out))
+ /* Keep going until the decompressed data is all processed
+ * or the stream marked as finished.
+ */
+ while (png_ptr->zstream.avail_in > 0 &&
+ (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ {
+ int ret;
+
+ /* We have data for zlib, but we must check that zlib
+ * has someplace to put the results. It doesn't matter
+ * if we don't expect any results -- it may be the input
+ * data is just the LZ end code.
+ */
+ if (!(png_ptr->zstream.avail_out > 0))
{
- if ((
-#if defined(PNG_READ_INTERLACING_SUPPORTED)
- png_ptr->interlaced && png_ptr->pass > 6) ||
- (!png_ptr->interlaced &&
-#endif
- png_ptr->row_number == png_ptr->num_rows))
- {
- if (png_ptr->zstream.avail_in)
- png_warning(png_ptr, "Too much data in IDAT chunks");
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
- png_push_process_row(png_ptr);
- png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */
+ png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,
+ png_ptr->iwidth) + 1);
+
png_ptr->zstream.next_out = png_ptr->row_buf;
}
- else
- break;
+
+ /* Using Z_SYNC_FLUSH here means that an unterminated
+ * LZ stream (a stream with a missing end code) can still
+ * be handled, otherwise (Z_NO_FLUSH) a future zlib
+ * implementation might defer output and therefore
+ * change the current behavior (see comments in inflate.c
+ * for why this doesn't happen at present with zlib 1.2.5).
+ */
+ ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH);
+
+ /* Check for any failure before proceeding. */
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ /* Terminate the decompression. */
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+ png_ptr->zowner = 0;
+
+ /* This may be a truncated stream (missing or
+ * damaged end code). Treat that as a warning.
+ */
+ if (png_ptr->row_number >= png_ptr->num_rows ||
+ png_ptr->pass > 6)
+ png_warning(png_ptr, "Truncated compressed data in IDAT");
+
+ else
+ {
+ if (ret == Z_DATA_ERROR)
+ png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch");
+ else
+ png_error(png_ptr, "Decompression error in IDAT");
+ }
+
+ /* Skip the check on unprocessed input */
+ return;
+ }
+
+ /* Did inflate output any data? */
+ if (png_ptr->zstream.next_out != png_ptr->row_buf)
+ {
+ /* Is this unexpected data after the last row?
+ * If it is, artificially terminate the LZ output
+ * here.
+ */
+ if (png_ptr->row_number >= png_ptr->num_rows ||
+ png_ptr->pass > 6)
+ {
+ /* Extra data. */
+ png_warning(png_ptr, "Extra compressed data in IDAT");
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+ png_ptr->zowner = 0;
+
+ /* Do no more processing; skip the unprocessed
+ * input check below.
+ */
+ return;
+ }
+
+ /* Do we have a complete row? */
+ if (png_ptr->zstream.avail_out == 0)
+ png_push_process_row(png_ptr);
+ }
+
+ /* And check for the end of the stream. */
+ if (ret == Z_STREAM_END)
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
}
+
+ /* All the data should have been processed, if anything
+ * is left at this point we have bytes of IDAT data
+ * after the zlib end code.
+ */
+ if (png_ptr->zstream.avail_in > 0)
+ png_warning(png_ptr, "Extra compression data in IDAT");
}
void /* PRIVATE */
-png_push_process_row(png_structp png_ptr)
+png_push_process_row(png_structrp png_ptr)
{
- png_ptr->row_info.color_type = png_ptr->color_type;
- png_ptr->row_info.width = png_ptr->iwidth;
- png_ptr->row_info.channels = png_ptr->channels;
- png_ptr->row_info.bit_depth = png_ptr->bit_depth;
- png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ /* 1.5.6: row_info moved out of png_struct to a local here. */
+ png_row_info row_info;
- png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
- png_ptr->row_info.width);
+ row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */
+ row_info.color_type = png_ptr->color_type;
+ row_info.bit_depth = png_ptr->bit_depth;
+ row_info.channels = png_ptr->channels;
+ row_info.pixel_depth = png_ptr->pixel_depth;
+ row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
- png_read_filter_row(png_ptr, &(png_ptr->row_info),
- png_ptr->row_buf + 1, png_ptr->prev_row + 1,
- (int)(png_ptr->row_buf[0]));
+ if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)
+ {
+ if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)
+ png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,
+ png_ptr->prev_row + 1, png_ptr->row_buf[0]);
+ else
+ png_error(png_ptr, "bad adaptive filter value");
+ }
- png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
- png_ptr->rowbytes + 1);
+ /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before
+ * 1.5.6, while the buffer really is this big in current versions of libpng
+ * it may not be in the future, so this was changed just to copy the
+ * interlaced row count:
+ */
+ memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);
- if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA))
- png_do_read_transformations(png_ptr);
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+ if (png_ptr->transformations != 0)
+ png_do_read_transformations(png_ptr, &row_info);
+#endif
-#if defined(PNG_READ_INTERLACING_SUPPORTED)
- /* blow up interlaced rows to full size */
- if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ /* The transformed pixel depth should match the depth now in row_info. */
+ if (png_ptr->transformed_pixel_depth == 0)
+ {
+ png_ptr->transformed_pixel_depth = row_info.pixel_depth;
+ if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)
+ png_error(png_ptr, "progressive row overflow");
+ }
+
+ else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)
+ png_error(png_ptr, "internal progressive row size calculation error");
+
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ /* Expand interlaced rows to full size */
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0)
{
if (png_ptr->pass < 6)
-/* old interface (pre-1.0.9):
- png_do_read_interlace(&(png_ptr->row_info),
- png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
- */
- png_do_read_interlace(png_ptr);
+ png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,
+ png_ptr->transformations);
- switch (png_ptr->pass)
- {
+ switch (png_ptr->pass)
+ {
case 0:
{
int i;
for (i = 0; i < 8 && png_ptr->pass == 0; i++)
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
- png_read_push_finish_row(png_ptr); /* updates png_ptr->pass */
+ png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */
}
- if (png_ptr->pass == 2) /* pass 1 might be empty */
+
+ if (png_ptr->pass == 2) /* Pass 1 might be empty */
{
for (i = 0; i < 4 && png_ptr->pass == 2; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
+
if (png_ptr->pass == 4 && png_ptr->height <= 4)
{
for (i = 0; i < 2 && png_ptr->pass == 4; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
+
if (png_ptr->pass == 6 && png_ptr->height <= 4)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
+
break;
}
+
case 1:
{
int i;
@@ -878,99 +844,123 @@ png_push_process_row(png_structp png_ptr)
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
}
- if (png_ptr->pass == 2) /* skip top 4 generated rows */
+
+ if (png_ptr->pass == 2) /* Skip top 4 generated rows */
{
for (i = 0; i < 4 && png_ptr->pass == 2; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
+
break;
}
+
case 2:
{
int i;
+
for (i = 0; i < 4 && png_ptr->pass == 2; i++)
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
}
+
for (i = 0; i < 4 && png_ptr->pass == 2; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
- if (png_ptr->pass == 4) /* pass 3 might be empty */
+
+ if (png_ptr->pass == 4) /* Pass 3 might be empty */
{
for (i = 0; i < 2 && png_ptr->pass == 4; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
+
break;
}
+
case 3:
{
int i;
+
for (i = 0; i < 4 && png_ptr->pass == 3; i++)
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
}
- if (png_ptr->pass == 4) /* skip top two generated rows */
+
+ if (png_ptr->pass == 4) /* Skip top two generated rows */
{
for (i = 0; i < 2 && png_ptr->pass == 4; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
+
break;
}
+
case 4:
{
int i;
+
for (i = 0; i < 2 && png_ptr->pass == 4; i++)
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
}
+
for (i = 0; i < 2 && png_ptr->pass == 4; i++)
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
- if (png_ptr->pass == 6) /* pass 5 might be empty */
+
+ if (png_ptr->pass == 6) /* Pass 5 might be empty */
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
+
break;
}
+
case 5:
{
int i;
+
for (i = 0; i < 2 && png_ptr->pass == 5; i++)
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
}
- if (png_ptr->pass == 6) /* skip top generated row */
+
+ if (png_ptr->pass == 6) /* Skip top generated row */
{
- png_push_have_row(png_ptr, png_bytep_NULL);
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
+
break;
}
+
+ default:
case 6:
{
png_push_have_row(png_ptr, png_ptr->row_buf + 1);
png_read_push_finish_row(png_ptr);
+
if (png_ptr->pass != 6)
break;
- png_push_have_row(png_ptr, png_bytep_NULL);
+
+ png_push_have_row(png_ptr, NULL);
png_read_push_finish_row(png_ptr);
}
}
@@ -984,26 +974,26 @@ png_push_process_row(png_structp png_ptr)
}
void /* PRIVATE */
-png_read_push_finish_row(png_structp png_ptr)
+png_read_push_finish_row(png_structrp png_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* start of interlace block */
- PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+ /* Start of interlace block */
+ static const png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
- /* offset to next interlace block */
- PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+ /* 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 */
- PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 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 */
- PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+ /* 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
- PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+ static const png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
*/
#endif
@@ -1011,565 +1001,91 @@ png_read_push_finish_row(png_structp png_ptr)
if (png_ptr->row_number < png_ptr->num_rows)
return;
- if (png_ptr->interlaced)
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ if (png_ptr->interlaced != 0)
{
png_ptr->row_number = 0;
- png_memset_check(png_ptr, png_ptr->prev_row, 0,
- png_ptr->rowbytes + 1);
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
do
{
png_ptr->pass++;
if ((png_ptr->pass == 1 && png_ptr->width < 5) ||
(png_ptr->pass == 3 && png_ptr->width < 3) ||
(png_ptr->pass == 5 && png_ptr->width < 2))
- png_ptr->pass++;
+ png_ptr->pass++;
if (png_ptr->pass > 7)
png_ptr->pass--;
+
if (png_ptr->pass >= 7)
break;
png_ptr->iwidth = (png_ptr->width +
- png_pass_inc[png_ptr->pass] - 1 -
- png_pass_start[png_ptr->pass]) /
- png_pass_inc[png_ptr->pass];
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
- png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
- png_ptr->iwidth) + 1;
-
- if (png_ptr->transformations & PNG_INTERLACE)
+ if ((png_ptr->transformations & PNG_INTERLACE) != 0)
break;
png_ptr->num_rows = (png_ptr->height +
- png_pass_yinc[png_ptr->pass] - 1 -
- png_pass_ystart[png_ptr->pass]) /
- png_pass_yinc[png_ptr->pass];
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
} while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);
}
-}
-
-#if defined(PNG_READ_tEXt_SUPPORTED)
-void /* PRIVATE */
-png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- png_error(png_ptr, "Out of place tEXt");
- info_ptr = info_ptr; /* to quiet some compiler warnings */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- png_ptr->skip_length = 0; /* This may not be necessary */
-
- if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
- {
- png_warning(png_ptr, "tEXt chunk too large to fit in memory");
- png_ptr->skip_length = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_uint_32)(length+1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_tEXt_MODE;
+#endif /* READ_INTERLACING */
}
void /* PRIVATE */
-png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
-{
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
- else
- text_size = png_ptr->current_text_left;
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp text;
- png_charp key;
- int ret;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
-#if defined(PNG_MAX_MALLOC_64K)
- if (png_ptr->skip_length)
- return;
-#endif
-
- key = png_ptr->current_text;
-
- for (text = key; *text; text++)
- /* empty loop */ ;
-
- if (text < key + png_ptr->current_text_size)
- text++;
-
- text_ptr = (png_textp)png_malloc(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr->key = key;
-#ifdef PNG_iTXt_SUPPORTED
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
-#endif
- text_ptr->text = text;
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, key);
- png_free(png_ptr, text_ptr);
- png_ptr->current_text = NULL;
-
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store text chunk.");
- }
-}
-#endif
-
-#if defined(PNG_READ_zTXt_SUPPORTED)
-void /* PRIVATE */
-png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- png_error(png_ptr, "Out of place zTXt");
- info_ptr = info_ptr; /* to quiet some compiler warnings */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- /* We can't handle zTXt chunks > 64K, since we don't have enough space
- * to be able to store the uncompressed data. Actually, the threshold
- * is probably around 32K, but it isn't as definite as 64K is.
- */
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr, "zTXt chunk too large to fit in memory");
- png_push_crc_skip(png_ptr, length);
- return;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_uint_32)(length+1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_zTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
-{
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
- else
- text_size = png_ptr->current_text_left;
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp text;
- png_charp key;
- int ret;
- png_size_t text_size, key_size;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
- key = png_ptr->current_text;
-
- for (text = key; *text; text++)
- /* empty loop */ ;
-
- /* zTXt can't have zero text */
- if (text >= key + png_ptr->current_text_size)
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- return;
- }
-
- text++;
-
- if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- return;
- }
-
- text++;
-
- png_ptr->zstream.next_in = (png_bytep )text;
- png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
- (text - key));
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-
- key_size = text - key;
- text_size = 0;
- text = NULL;
- ret = Z_STREAM_END;
-
- while (png_ptr->zstream.avail_in)
- {
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret != Z_OK && ret != Z_STREAM_END)
- {
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- png_free(png_ptr, text);
- return;
- }
- if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
- {
- if (text == NULL)
- {
- text = (png_charp)png_malloc(png_ptr,
- (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
- + key_size + 1));
- png_memcpy(text + key_size, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
- png_memcpy(text, key, key_size);
- text_size = key_size + png_ptr->zbuf_size -
- png_ptr->zstream.avail_out;
- *(text + text_size) = '\0';
- }
- else
- {
- png_charp tmp;
-
- tmp = text;
- text = (png_charp)png_malloc(png_ptr, text_size +
- (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
- + 1));
- png_memcpy(text, tmp, text_size);
- png_free(png_ptr, tmp);
- png_memcpy(text + text_size, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
- text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
- *(text + text_size) = '\0';
- }
- if (ret != Z_STREAM_END)
- {
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- }
- }
- else
- {
- break;
- }
-
- if (ret == Z_STREAM_END)
- break;
- }
-
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
-
- if (ret != Z_STREAM_END)
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- png_free(png_ptr, text);
- return;
- }
-
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- key = text;
- text += key_size;
-
- text_ptr = (png_textp)png_malloc(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
- text_ptr->key = key;
-#ifdef PNG_iTXt_SUPPORTED
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
-#endif
- text_ptr->text = text;
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, key);
- png_free(png_ptr, text_ptr);
-
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store text chunk.");
- }
-}
-#endif
-
-#if defined(PNG_READ_iTXt_SUPPORTED)
-void /* PRIVATE */
-png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- png_error(png_ptr, "Out of place iTXt");
- info_ptr = info_ptr; /* to quiet some compiler warnings */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- png_ptr->skip_length = 0; /* This may not be necessary */
-
- if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
- {
- png_warning(png_ptr, "iTXt chunk too large to fit in memory");
- png_ptr->skip_length = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_uint_32)(length+1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_iTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr)
-{
-
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
- else
- text_size = png_ptr->current_text_left;
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp key;
- int comp_flag;
- png_charp lang;
- png_charp lang_key;
- png_charp text;
- int ret;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
-#if defined(PNG_MAX_MALLOC_64K)
- if (png_ptr->skip_length)
- return;
-#endif
-
- key = png_ptr->current_text;
-
- for (lang = key; *lang; lang++)
- /* empty loop */ ;
-
- if (lang < key + png_ptr->current_text_size - 3)
- lang++;
-
- comp_flag = *lang++;
- lang++; /* skip comp_type, always zero */
-
- for (lang_key = lang; *lang_key; lang_key++)
- /* empty loop */ ;
- lang_key++; /* skip NUL separator */
-
- text=lang_key;
- if (lang_key < key + png_ptr->current_text_size - 1)
- {
- for (; *text; text++)
- /* empty loop */ ;
- }
-
- if (text < key + png_ptr->current_text_size)
- text++;
-
- text_ptr = (png_textp)png_malloc(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- text_ptr->compression = comp_flag + 2;
- text_ptr->key = key;
- text_ptr->lang = lang;
- text_ptr->lang_key = lang_key;
- text_ptr->text = text;
- text_ptr->text_length = 0;
- text_ptr->itxt_length = png_strlen(text);
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_ptr->current_text = NULL;
-
- png_free(png_ptr, text_ptr);
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store iTXt chunk.");
- }
-}
-#endif
-
-/* This function is called when we haven't found a handler for this
- * chunk. If there isn't a problem with the chunk itself (ie a bad chunk
- * name or a critical chunk), the chunk is (currently) silently ignored.
- */
-void /* PRIVATE */
-png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- png_uint_32 skip=0;
- png_check_chunk_name(png_ptr, png_ptr->chunk_name);
-
- if (!(png_ptr->chunk_name[0] & 0x20))
- {
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
- if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS
-#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
- && png_ptr->read_user_chunk_fn == NULL
-#endif
- )
-#endif
- png_chunk_error(png_ptr, "unknown critical chunk");
-
- info_ptr = info_ptr; /* to quiet some compiler warnings */
- }
-
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
- if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
- {
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr, "unknown chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
- png_memcpy((png_charp)png_ptr->unknown_chunk.name,
- (png_charp)png_ptr->chunk_name,
- png_sizeof(png_ptr->unknown_chunk.name));
- png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]='\0';
-
- png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
- png_ptr->unknown_chunk.size = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
-#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
- if(png_ptr->read_user_chunk_fn != NULL)
- {
- /* callback to user unknown chunk handler */
- int ret;
- ret = (*(png_ptr->read_user_chunk_fn))
- (png_ptr, &png_ptr->unknown_chunk);
- if (ret < 0)
- png_chunk_error(png_ptr, "error in user chunk");
- if (ret == 0)
- {
- if (!(png_ptr->chunk_name[0] & 0x20))
- if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS)
- png_chunk_error(png_ptr, "unknown critical chunk");
- png_set_unknown_chunks(png_ptr, info_ptr,
- &png_ptr->unknown_chunk, 1);
- }
- }
-#else
- png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
-#endif
- png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
- }
- else
-#endif
- skip=length;
- png_push_crc_skip(png_ptr, skip);
-}
-
-void /* PRIVATE */
-png_push_have_info(png_structp png_ptr, png_infop info_ptr)
+png_push_have_info(png_structrp png_ptr, png_inforp info_ptr)
{
if (png_ptr->info_fn != NULL)
(*(png_ptr->info_fn))(png_ptr, info_ptr);
}
void /* PRIVATE */
-png_push_have_end(png_structp png_ptr, png_infop info_ptr)
+png_push_have_end(png_structrp png_ptr, png_inforp info_ptr)
{
if (png_ptr->end_fn != NULL)
(*(png_ptr->end_fn))(png_ptr, info_ptr);
}
void /* PRIVATE */
-png_push_have_row(png_structp png_ptr, png_bytep row)
+png_push_have_row(png_structrp png_ptr, png_bytep row)
{
if (png_ptr->row_fn != NULL)
(*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
- (int)png_ptr->pass);
+ (int)png_ptr->pass);
}
+#ifdef PNG_READ_INTERLACING_SUPPORTED
void PNGAPI
-png_progressive_combine_row (png_structp png_ptr,
- png_bytep old_row, png_bytep new_row)
+png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row,
+ png_const_bytep new_row)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST int FARDATA png_pass_dsp_mask[7] =
- {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
-#endif
- if(png_ptr == NULL) return;
- if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */
- png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
+ if (png_ptr == NULL)
+ return;
+
+ /* new_row is a flag here - if it is NULL then the app callback was called
+ * from an empty row (see the calls to png_struct::row_fn below), otherwise
+ * it must be png_ptr->row_buf+1
+ */
+ if (new_row != NULL)
+ png_combine_row(png_ptr, old_row, 1/*blocky display*/);
}
+#endif /* READ_INTERLACING */
void PNGAPI
-png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
- png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
- png_progressive_end_ptr end_fn)
+png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
png_ptr->info_fn = info_fn;
png_ptr->row_fn = row_fn;
png_ptr->end_fn = end_fn;
@@ -1578,9 +1094,11 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
}
png_voidp PNGAPI
-png_get_progressive_ptr(png_structp png_ptr)
+png_get_progressive_ptr(png_const_structrp png_ptr)
{
- if(png_ptr == NULL) return (NULL);
+ if (png_ptr == NULL)
+ return NULL;
+
return png_ptr->io_ptr;
}
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#endif /* PROGRESSIVE_READ */
diff --git a/PDF/src/pngread.c b/PDF/src/pngread.c
index 5de5e5635..07a39df6e 100644
--- a/PDF/src/pngread.c
+++ b/PDF/src/pngread.c
@@ -1,312 +1,85 @@
/* pngread.c - read a PNG file
*
- * Last changed in libpng 1.2.24 December 14, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * 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 an application calls directly to
* read a PNG file or stream.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
+# include
+#endif
-#if defined(PNG_READ_SUPPORTED)
+#ifdef PNG_READ_SUPPORTED
/* Create a PNG structure for reading, and allocate any memory needed. */
-png_structp PNGAPI
-png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn)
+PNG_FUNCTION(png_structp,PNGAPI
+png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
{
-
-#ifdef PNG_USER_MEM_SUPPORTED
- return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
- warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
+#ifndef PNG_USER_MEM_SUPPORTED
+ png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
+ error_fn, warn_fn, NULL, NULL, NULL);
+#else
+ return png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL);
}
-/* Alternate create PNG structure for reading, and allocate any memory needed. */
-png_structp PNGAPI
-png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
- png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+/* Alternate create PNG structure for reading, and allocate any memory
+ * needed.
+ */
+PNG_FUNCTION(png_structp,PNGAPI
+png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
{
-#endif /* PNG_USER_MEM_SUPPORTED */
+ png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
+ error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
+#endif /* USER_MEM */
- png_structp png_ptr;
-
-#ifdef PNG_SETJMP_SUPPORTED
-#ifdef USE_FAR_KEYWORD
- jmp_buf jmpbuf;
-#endif
-#endif
-
- int i;
-
- png_debug(1, "in png_create_read_struct\n");
-#ifdef PNG_USER_MEM_SUPPORTED
- png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
- (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
-#else
- png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
-#endif
- if (png_ptr == NULL)
- return (NULL);
-
- /* added at libpng-1.2.6 */
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
- png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
-#else
- if (setjmp(png_ptr->jmpbuf))
-#endif
+ if (png_ptr != NULL)
{
- png_free(png_ptr, png_ptr->zbuf);
- png_ptr->zbuf=NULL;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)png_ptr,
- (png_free_ptr)free_fn, (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)png_ptr);
-#endif
- return (NULL);
- }
-#ifdef USE_FAR_KEYWORD
- png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
-#endif
-#endif
+ png_ptr->mode = PNG_IS_READ_STRUCT;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
-#endif
+ /* Added in libpng-1.6.0; this can be used to detect a read structure if
+ * required (it will be zero in a write structure.)
+ */
+# ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+ png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE;
+# endif
- png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED
+ png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
- i=0;
- do
- {
- if(user_png_ver[i] != png_libpng_ver[i])
- png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
- } while (png_libpng_ver[i++]);
+ /* In stable builds only warn if an application error can be completely
+ * handled.
+ */
+# if PNG_RELEASE_BUILD
+ png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
+# endif
+# endif
- if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
- {
- /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
- * we must recompile any applications that use any older library version.
- * For versions after libpng 1.0, we will be compatible, so we need
- * only check the first digit.
- */
- if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
- (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
- (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char msg[80];
- if (user_png_ver)
- {
- png_snprintf(msg, 80,
- "Application was compiled with png.h from libpng-%.20s",
- user_png_ver);
- png_warning(png_ptr, msg);
- }
- png_snprintf(msg, 80,
- "Application is running with png.c from libpng-%.20s",
- png_libpng_ver);
- png_warning(png_ptr, msg);
-#endif
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "Incompatible libpng version in application and library");
- }
+ /* TODO: delay this, it can be done in png_init_io (if the app doesn't
+ * do it itself) avoiding setting the default function if it is not
+ * required.
+ */
+ png_set_read_fn(png_ptr, NULL, NULL);
}
- /* initialize zbuf - compression buffer */
- png_ptr->zbuf_size = PNG_ZBUF_SIZE;
- png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)png_ptr->zbuf_size);
- png_ptr->zstream.zalloc = png_zalloc;
- png_ptr->zstream.zfree = png_zfree;
- png_ptr->zstream.opaque = (voidpf)png_ptr;
-
- switch (inflateInit(&png_ptr->zstream))
- {
- case Z_OK: /* Do nothing */ break;
- case Z_MEM_ERROR:
- case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
- case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
- default: png_error(png_ptr, "Unknown zlib error");
- }
-
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-
- png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL);
-
-#ifdef PNG_SETJMP_SUPPORTED
-/* Applications that neglect to set up their own setjmp() and then encounter
- a png_error() will longjmp here. Since the jmpbuf is then meaningless we
- abort instead of returning. */
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
- PNG_ABORT();
- png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
-#else
- if (setjmp(png_ptr->jmpbuf))
- PNG_ABORT();
-#endif
-#endif
- return (png_ptr);
+ return png_ptr;
}
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-/* Initialize PNG structure for reading, and allocate any memory needed.
- This interface is deprecated in favour of the png_create_read_struct(),
- and it will disappear as of libpng-1.3.0. */
-#undef png_read_init
-void PNGAPI
-png_read_init(png_structp png_ptr)
-{
- /* We only come here via pre-1.0.7-compiled applications */
- png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
-}
-void PNGAPI
-png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver,
- png_size_t png_struct_size, png_size_t png_info_size)
-{
- /* We only come here via pre-1.0.12-compiled applications */
- if(png_ptr == NULL) return;
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- if(png_sizeof(png_struct) > png_struct_size ||
- png_sizeof(png_info) > png_info_size)
- {
- char msg[80];
- png_ptr->warning_fn=NULL;
- if (user_png_ver)
- {
- png_snprintf(msg, 80,
- "Application was compiled with png.h from libpng-%.20s",
- user_png_ver);
- png_warning(png_ptr, msg);
- }
- png_snprintf(msg, 80,
- "Application is running with png.c from libpng-%.20s",
- png_libpng_ver);
- png_warning(png_ptr, msg);
- }
-#endif
- if(png_sizeof(png_struct) > png_struct_size)
- {
- png_ptr->error_fn=NULL;
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "The png struct allocated by the application for reading is too small.");
- }
- if(png_sizeof(png_info) > png_info_size)
- {
- png_ptr->error_fn=NULL;
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "The info struct allocated by application for reading is too small.");
- }
- png_read_init_3(&png_ptr, user_png_ver, png_struct_size);
-}
-#endif /* PNG_1_0_X || PNG_1_2_X */
-
-void PNGAPI
-png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
- png_size_t png_struct_size)
-{
-#ifdef PNG_SETJMP_SUPPORTED
- jmp_buf tmp_jmp; /* to save current jump buffer */
-#endif
-
- int i=0;
-
- png_structp png_ptr=*ptr_ptr;
-
- if(png_ptr == NULL) return;
-
- do
- {
- if(user_png_ver[i] != png_libpng_ver[i])
- {
-#ifdef PNG_LEGACY_SUPPORTED
- png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-#else
- png_ptr->warning_fn=NULL;
- png_warning(png_ptr,
- "Application uses deprecated png_read_init() and should be recompiled.");
- break;
-#endif
- }
- } while (png_libpng_ver[i++]);
-
- png_debug(1, "in png_read_init_3\n");
-
-#ifdef PNG_SETJMP_SUPPORTED
- /* save jump buffer and error functions */
- png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
-#endif
-
- if(png_sizeof(png_struct) > png_struct_size)
- {
- png_destroy_struct(png_ptr);
- *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
- png_ptr = *ptr_ptr;
- }
-
- /* reset all variables to 0 */
- png_memset(png_ptr, 0, png_sizeof (png_struct));
-
-#ifdef PNG_SETJMP_SUPPORTED
- /* restore jump buffer */
- png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
-#endif
-
- /* added at libpng-1.2.6 */
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
- png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
-#endif
-
- /* initialize zbuf - compression buffer */
- png_ptr->zbuf_size = PNG_ZBUF_SIZE;
- png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)png_ptr->zbuf_size);
- png_ptr->zstream.zalloc = png_zalloc;
- png_ptr->zstream.zfree = png_zfree;
- png_ptr->zstream.opaque = (voidpf)png_ptr;
-
- switch (inflateInit(&png_ptr->zstream))
- {
- case Z_OK: /* Do nothing */ break;
- case Z_MEM_ERROR:
- case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
- case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
- default: png_error(png_ptr, "Unknown zlib error");
- }
-
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-
- png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL);
-}
-
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the information before the actual image data. This has been
* changed in v0.90 to allow reading a file that already has the magic
* bytes read from the stream. You can tell libpng how many bytes have
@@ -316,302 +89,372 @@ png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
* read if it is determined that this isn't a valid PNG file.
*/
void PNGAPI
-png_read_info(png_structp png_ptr, png_infop info_ptr)
+png_read_info(png_structrp png_ptr, png_inforp info_ptr)
{
- if(png_ptr == NULL) return;
- png_debug(1, "in png_read_info\n");
- /* If we haven't checked all of the PNG signature bytes, do so now. */
- if (png_ptr->sig_bytes < 8)
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ int keep;
+#endif
+
+ png_debug(1, "in png_read_info");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* Read and check the PNG file signature. */
+ png_read_sig(png_ptr, info_ptr);
+
+ for (;;)
{
- png_size_t num_checked = png_ptr->sig_bytes,
- num_to_check = 8 - num_checked;
+ png_uint_32 length = png_read_chunk_header(png_ptr);
+ png_uint_32 chunk_name = png_ptr->chunk_name;
- png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
- png_ptr->sig_bytes = 8;
-
- if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ /* IDAT logic needs to happen here to simplify getting the two flags
+ * right.
+ */
+ if (chunk_name == png_IDAT)
{
- if (num_checked < 4 &&
- png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
- png_error(png_ptr, "Not a PNG file");
- else
- png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "Missing IHDR before IDAT");
+
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ (png_ptr->mode & PNG_HAVE_PLTE) == 0)
+ png_chunk_error(png_ptr, "Missing PLTE before IDAT");
+
+ else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+ png_chunk_benign_error(png_ptr, "Too many IDATs found");
+
+ png_ptr->mode |= PNG_HAVE_IDAT;
}
- if (num_checked < 3)
- png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
- }
- for(;;)
- {
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IHDR;
- PNG_CONST PNG_IDAT;
- PNG_CONST PNG_IEND;
- PNG_CONST PNG_PLTE;
-#if defined(PNG_READ_bKGD_SUPPORTED)
- PNG_CONST PNG_bKGD;
-#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- PNG_CONST PNG_cHRM;
-#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
- PNG_CONST PNG_gAMA;
-#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
- PNG_CONST PNG_hIST;
-#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
- PNG_CONST PNG_iCCP;
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- PNG_CONST PNG_iTXt;
-#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- PNG_CONST PNG_oFFs;
-#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- PNG_CONST PNG_pCAL;
-#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- PNG_CONST PNG_pHYs;
-#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- PNG_CONST PNG_sBIT;
-#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- PNG_CONST PNG_sCAL;
-#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- PNG_CONST PNG_sPLT;
-#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- PNG_CONST PNG_sRGB;
-#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- PNG_CONST PNG_tEXt;
-#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- PNG_CONST PNG_tIME;
-#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- PNG_CONST PNG_tRNS;
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- PNG_CONST PNG_zTXt;
-#endif
-#endif /* PNG_USE_LOCAL_ARRAYS */
- png_byte chunk_length[4];
- png_uint_32 length;
-
- png_read_data(png_ptr, chunk_length, 4);
- length = png_get_uint_31(png_ptr,chunk_length);
-
- png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
-
- png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name,
- length);
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
+ {
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+ 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 (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- if(png_ptr->mode & PNG_AFTER_IDAT)
- png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
-
- if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ if (chunk_name == png_IHDR)
png_handle_IHDR(png_ptr, info_ptr, length);
- else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+
+ else if (chunk_name == png_IEND)
png_handle_IEND(png_ptr, info_ptr, length);
+
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
- else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
{
- if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- png_ptr->mode |= PNG_HAVE_IDAT;
- png_handle_unknown(png_ptr, info_ptr, length);
- if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_unknown(png_ptr, info_ptr, length, keep);
+
+ if (chunk_name == png_PLTE)
png_ptr->mode |= PNG_HAVE_PLTE;
- else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+
+ else if (chunk_name == png_IDAT)
{
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before IDAT");
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
- png_error(png_ptr, "Missing PLTE before IDAT");
+ png_ptr->idat_size = 0; /* It has been consumed */
break;
}
}
#endif
- else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ else if (chunk_name == png_PLTE)
png_handle_PLTE(png_ptr, info_ptr, length);
- else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- {
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before IDAT");
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
- png_error(png_ptr, "Missing PLTE before IDAT");
+ else if (chunk_name == png_IDAT)
+ {
png_ptr->idat_size = length;
- png_ptr->mode |= PNG_HAVE_IDAT;
break;
}
-#if defined(PNG_READ_bKGD_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+
+#ifdef PNG_READ_bKGD_SUPPORTED
+ else if (chunk_name == png_bKGD)
png_handle_bKGD(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+
+#ifdef PNG_READ_cHRM_SUPPORTED
+ else if (chunk_name == png_cHRM)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+
+#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
-#if defined(PNG_READ_hIST_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+
+#ifdef PNG_READ_hIST_SUPPORTED
+ else if (chunk_name == png_hIST)
png_handle_hIST(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+
+#ifdef PNG_READ_oFFs_SUPPORTED
+ else if (chunk_name == png_oFFs)
png_handle_oFFs(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+
+#ifdef PNG_READ_pCAL_SUPPORTED
+ else if (chunk_name == png_pCAL)
png_handle_pCAL(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+
+#ifdef PNG_READ_sCAL_SUPPORTED
+ else if (chunk_name == png_sCAL)
png_handle_sCAL(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+
+#ifdef PNG_READ_pHYs_SUPPORTED
+ else if (chunk_name == png_pHYs)
png_handle_pHYs(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+
+#ifdef PNG_READ_sBIT_SUPPORTED
+ else if (chunk_name == png_sBIT)
png_handle_sBIT(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+
+#ifdef PNG_READ_sRGB_SUPPORTED
+ else if (chunk_name == png_sRGB)
png_handle_sRGB(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+
+#ifdef PNG_READ_iCCP_SUPPORTED
+ else if (chunk_name == png_iCCP)
png_handle_iCCP(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+
+#ifdef PNG_READ_sPLT_SUPPORTED
+ else if (chunk_name == png_sPLT)
png_handle_sPLT(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+
+#ifdef PNG_READ_tEXt_SUPPORTED
+ else if (chunk_name == png_tEXt)
png_handle_tEXt(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+
+#ifdef PNG_READ_tIME_SUPPORTED
+ else if (chunk_name == png_tIME)
png_handle_tIME(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+
+#ifdef PNG_READ_tRNS_SUPPORTED
+ else if (chunk_name == png_tRNS)
png_handle_tRNS(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+
+#ifdef PNG_READ_zTXt_SUPPORTED
+ else if (chunk_name == png_zTXt)
png_handle_zTXt(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+
+#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_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
}
}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+#endif /* SEQUENTIAL_READ */
-/* optional call to update the users info_ptr structure */
+/* Optional call to update the users info_ptr structure */
void PNGAPI
-png_read_update_info(png_structp png_ptr, png_infop info_ptr)
+png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
{
- png_debug(1, "in png_read_update_info\n");
- if(png_ptr == NULL) return;
- if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
- png_read_start_row(png_ptr);
- else
- png_warning(png_ptr,
- "Ignoring extra png_read_update_info() call; row buffer not reallocated");
- png_read_transform_info(png_ptr, info_ptr);
+ png_debug(1, "in png_read_update_info");
+
+ if (png_ptr != NULL)
+ {
+ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
+ {
+ png_read_start_row(png_ptr);
+
+# ifdef PNG_READ_TRANSFORMS_SUPPORTED
+ png_read_transform_info(png_ptr, info_ptr);
+# else
+ PNG_UNUSED(info_ptr)
+# endif
+ }
+
+ /* New in 1.6.0 this avoids the bug of doing the initializations twice */
+ else
+ png_app_error(png_ptr,
+ "png_read_update_info/png_start_read_image: duplicate call");
+ }
}
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Initialize palette, background, etc, after transformations
* are set, but before any reading takes place. This allows
* the user to obtain a gamma-corrected palette, for example.
* If the user doesn't call this, we will do it ourselves.
*/
void PNGAPI
-png_start_read_image(png_structp png_ptr)
+png_start_read_image(png_structrp png_ptr)
{
- png_debug(1, "in png_start_read_image\n");
- if(png_ptr == NULL) return;
- if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
- png_read_start_row(png_ptr);
-}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+ png_debug(1, "in png_start_read_image");
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-void PNGAPI
-png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
+ if (png_ptr != NULL)
+ {
+ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
+ png_read_start_row(png_ptr);
+
+ /* New in 1.6.0 this avoids the bug of doing the initializations twice */
+ else
+ png_app_error(png_ptr,
+ "png_start_read_image/png_read_update_info: duplicate call");
+ }
+}
+#endif /* SEQUENTIAL_READ */
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+/* Undoes intrapixel differencing,
+ * NOTE: this is apparently only supported in the 'sequential' reader.
+ */
+static void
+png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IDAT;
- PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55,
- 0xff};
- PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
-#endif
- int ret;
- if(png_ptr == NULL) return;
- png_debug2(1, "in png_read_row (row %lu, pass %d)\n",
- png_ptr->row_number, png_ptr->pass);
- if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_debug(1, "in png_do_read_intrapixel");
+
+ if (
+ (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff);
+ *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff);
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1);
+ png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
+ png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
+ png_uint_32 red = (s0 + s1 + 65536) & 0xffff;
+ png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;
+ *(rp ) = (png_byte)((red >> 8) & 0xff);
+ *(rp + 1) = (png_byte)(red & 0xff);
+ *(rp + 4) = (png_byte)((blue >> 8) & 0xff);
+ *(rp + 5) = (png_byte)(blue & 0xff);
+ }
+ }
+ }
+}
+#endif /* MNG_FEATURES */
+
+void PNGAPI
+png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
+{
+ png_row_info row_info;
+
+ if (png_ptr == NULL)
+ return;
+
+ png_debug2(1, "in png_read_row (row %lu, pass %d)",
+ (unsigned long)png_ptr->row_number, png_ptr->pass);
+
+ /* png_read_start_row sets the information (in particular iwidth) for this
+ * interlace pass.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
png_read_start_row(png_ptr);
+
+ /* 1.5.6: row_info moved out of png_struct to a local here. */
+ row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */
+ row_info.color_type = png_ptr->color_type;
+ row_info.bit_depth = png_ptr->bit_depth;
+ row_info.channels = png_ptr->channels;
+ row_info.pixel_depth = png_ptr->pixel_depth;
+ row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
+
+#ifdef PNG_WARNINGS_SUPPORTED
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{
- /* check for transforms that have been set but were defined out */
+ /* Check for transforms that have been set but were defined out */
#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_MONO)
- png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
+ png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined");
#endif
+
#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
- if (png_ptr->transformations & PNG_FILLER)
- png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_FILLER) != 0)
+ png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined");
#endif
-#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined.");
+
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
+ !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined");
#endif
+
#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
- if (png_ptr->transformations & PNG_PACK)
- png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_PACK) != 0)
+ png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined");
#endif
+
#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
- if (png_ptr->transformations & PNG_SHIFT)
- png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_SHIFT) != 0)
+ png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined");
#endif
+
#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
- if (png_ptr->transformations & PNG_BGR)
- png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_BGR) != 0)
+ png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined");
#endif
+
#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_BYTES)
- png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
+ png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined");
#endif
}
+#endif /* WARNINGS */
-#if defined(PNG_READ_INTERLACING_SUPPORTED)
- /* if interlaced and we do not need a new row, combine row and return */
- if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ /* If interlaced and we do not need a new row, combine row and return.
+ * Notice that the pixels we have from previous rows have been transformed
+ * already; we can only combine like with like (transformed or
+ * untransformed) and, because of the libpng API for interlaced images, this
+ * means we must transform before de-interlacing.
+ */
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0)
{
switch (png_ptr->pass)
{
@@ -619,64 +462,70 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
if (png_ptr->row_number & 0x07)
{
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
png_read_finish_row(png_ptr);
return;
}
break;
+
case 1:
if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
{
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
png_read_finish_row(png_ptr);
return;
}
break;
+
case 2:
if ((png_ptr->row_number & 0x07) != 4)
{
if (dsp_row != NULL && (png_ptr->row_number & 4))
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
png_read_finish_row(png_ptr);
return;
}
break;
+
case 3:
if ((png_ptr->row_number & 3) || png_ptr->width < 3)
{
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
png_read_finish_row(png_ptr);
return;
}
break;
+
case 4:
if ((png_ptr->row_number & 3) != 2)
{
if (dsp_row != NULL && (png_ptr->row_number & 2))
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
png_read_finish_row(png_ptr);
return;
}
break;
+
case 5:
if ((png_ptr->row_number & 1) || png_ptr->width < 2)
{
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
png_read_finish_row(png_ptr);
return;
}
break;
+
+ default:
case 6:
- if (!(png_ptr->row_number & 1))
+ if ((png_ptr->row_number & 1) == 0)
{
png_read_finish_row(png_ptr);
return;
@@ -686,117 +535,92 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
}
#endif
- if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
png_error(png_ptr, "Invalid attempt to read row data");
- png_ptr->zstream.next_out = png_ptr->row_buf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
- do
+ /* Fill the row with IDAT data: */
+ png_ptr->row_buf[0]=255; /* to force error if no data was found */
+ png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1);
+
+ if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)
{
- if (!(png_ptr->zstream.avail_in))
- {
- while (!png_ptr->idat_size)
- {
- png_byte chunk_length[4];
+ if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)
+ png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,
+ png_ptr->prev_row + 1, png_ptr->row_buf[0]);
+ else
+ png_error(png_ptr, "bad adaptive filter value");
+ }
- png_crc_finish(png_ptr, 0);
+ /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before
+ * 1.5.6, while the buffer really is this big in current versions of libpng
+ * it may not be in the future, so this was changed just to copy the
+ * interlaced count:
+ */
+ memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);
- png_read_data(png_ptr, chunk_length, 4);
- png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length);
-
- png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
- if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- png_error(png_ptr, "Not enough image data");
- }
- png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_in = png_ptr->zbuf;
- if (png_ptr->zbuf_size > png_ptr->idat_size)
- png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
- png_crc_read(png_ptr, png_ptr->zbuf,
- (png_size_t)png_ptr->zstream.avail_in);
- png_ptr->idat_size -= png_ptr->zstream.avail_in;
- }
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret == Z_STREAM_END)
- {
- if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
- png_ptr->idat_size)
- png_error(png_ptr, "Extra compressed data");
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
- if (ret != Z_OK)
- png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
- "Decompression error");
-
- } while (png_ptr->zstream.avail_out);
-
- png_ptr->row_info.color_type = png_ptr->color_type;
- png_ptr->row_info.width = png_ptr->iwidth;
- png_ptr->row_info.channels = png_ptr->channels;
- png_ptr->row_info.bit_depth = png_ptr->bit_depth;
- png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
- png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
- png_ptr->row_info.width);
-
- if(png_ptr->row_buf[0])
- png_read_filter_row(png_ptr, &(png_ptr->row_info),
- png_ptr->row_buf + 1, png_ptr->prev_row + 1,
- (int)(png_ptr->row_buf[0]));
-
- png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
- png_ptr->rowbytes + 1);
-
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
- (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
{
/* Intrapixel differencing */
- png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1);
}
#endif
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+ if (png_ptr->transformations
+# ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ || png_ptr->num_palette_max >= 0
+# endif
+ )
+ png_do_read_transformations(png_ptr, &row_info);
+#endif
- if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA))
- png_do_read_transformations(png_ptr);
+ /* The transformed pixel depth should match the depth now in row_info. */
+ if (png_ptr->transformed_pixel_depth == 0)
+ {
+ png_ptr->transformed_pixel_depth = row_info.pixel_depth;
+ if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)
+ png_error(png_ptr, "sequential row overflow");
+ }
-#if defined(PNG_READ_INTERLACING_SUPPORTED)
- /* blow up interlaced rows to full size */
- if (png_ptr->interlaced &&
- (png_ptr->transformations & PNG_INTERLACE))
+ else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)
+ png_error(png_ptr, "internal sequential row size calculation error");
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ /* Expand interlaced rows to full size */
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0)
{
if (png_ptr->pass < 6)
-/* old interface (pre-1.0.9):
- png_do_read_interlace(&(png_ptr->row_info),
- png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
- */
- png_do_read_interlace(png_ptr);
+ png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,
+ png_ptr->transformations);
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row,
- png_pass_dsp_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, dsp_row, 1/*display*/);
+
if (row != NULL)
- png_combine_row(png_ptr, row,
- png_pass_mask[png_ptr->pass]);
+ png_combine_row(png_ptr, row, 0/*row*/);
}
+
else
#endif
{
if (row != NULL)
- png_combine_row(png_ptr, row, 0xff);
+ png_combine_row(png_ptr, row, -1/*ignored*/);
+
if (dsp_row != NULL)
- png_combine_row(png_ptr, dsp_row, 0xff);
+ png_combine_row(png_ptr, dsp_row, -1/*ignored*/);
}
png_read_finish_row(png_ptr);
if (png_ptr->read_row_fn != NULL)
(*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
-}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+}
+#endif /* SEQUENTIAL_READ */
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read one or more rows of image data. If the image is interlaced,
* and png_set_interlace_handling() has been called, the rows need to
* contain the contents of the rows from the previous pass. If the
@@ -822,15 +646,18 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
*/
void PNGAPI
-png_read_rows(png_structp png_ptr, png_bytepp row,
- png_bytepp display_row, png_uint_32 num_rows)
+png_read_rows(png_structrp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows)
{
png_uint_32 i;
png_bytepp rp;
png_bytepp dp;
- png_debug(1, "in png_read_rows\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_read_rows");
+
+ if (png_ptr == NULL)
+ return;
+
rp = row;
dp = display_row;
if (rp != NULL && dp != NULL)
@@ -841,24 +668,26 @@ png_read_rows(png_structp png_ptr, png_bytepp row,
png_read_row(png_ptr, rptr, dptr);
}
- else if(rp != NULL)
+
+ else if (rp != NULL)
for (i = 0; i < num_rows; i++)
{
png_bytep rptr = *rp;
- png_read_row(png_ptr, rptr, png_bytep_NULL);
+ png_read_row(png_ptr, rptr, NULL);
rp++;
}
- else if(dp != NULL)
+
+ else if (dp != NULL)
for (i = 0; i < num_rows; i++)
{
png_bytep dptr = *dp;
- png_read_row(png_ptr, png_bytep_NULL, dptr);
+ png_read_row(png_ptr, NULL, dptr);
dp++;
}
}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+#endif /* SEQUENTIAL_READ */
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the entire image. If the image has an alpha channel or a tRNS
* chunk, and you have called png_handle_alpha()[*], you will need to
* initialize the image to the current image that PNG will be overlaying.
@@ -872,567 +701,523 @@ png_read_rows(png_structp png_ptr, png_bytepp row,
* [*] png_handle_alpha() does not exist yet, as of this version of libpng
*/
void PNGAPI
-png_read_image(png_structp png_ptr, png_bytepp image)
+png_read_image(png_structrp png_ptr, png_bytepp image)
{
- png_uint_32 i,image_height;
+ png_uint_32 i, image_height;
int pass, j;
png_bytepp rp;
- png_debug(1, "in png_read_image\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_read_image");
+
+ if (png_ptr == NULL)
+ return;
#ifdef PNG_READ_INTERLACING_SUPPORTED
- pass = png_set_interlace_handling(png_ptr);
+ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
+ {
+ pass = png_set_interlace_handling(png_ptr);
+ /* And make sure transforms are initialized. */
+ png_start_read_image(png_ptr);
+ }
+ else
+ {
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) == 0)
+ {
+ /* Caller called png_start_read_image or png_read_update_info without
+ * first turning on the PNG_INTERLACE transform. We can fix this here,
+ * but the caller should do it!
+ */
+ png_warning(png_ptr, "Interlace handling should be turned on when "
+ "using png_read_image");
+ /* Make sure this is set correctly */
+ png_ptr->num_rows = png_ptr->height;
+ }
+
+ /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in
+ * the above error case.
+ */
+ pass = png_set_interlace_handling(png_ptr);
+ }
#else
if (png_ptr->interlaced)
png_error(png_ptr,
- "Cannot read interlaced image -- interlace handler disabled.");
+ "Cannot read interlaced image -- interlace handler disabled");
+
pass = 1;
#endif
-
image_height=png_ptr->height;
- png_ptr->num_rows = image_height; /* Make sure this is set correctly */
for (j = 0; j < pass; j++)
{
rp = image;
for (i = 0; i < image_height; i++)
{
- png_read_row(png_ptr, *rp, png_bytep_NULL);
+ png_read_row(png_ptr, *rp, NULL);
rp++;
}
}
}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+#endif /* SEQUENTIAL_READ */
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the end of the PNG file. Will not read past the end of the
* file, will verify the end is accurate, and will read any comments
* or time information at the end of the file, if info is not NULL.
*/
void PNGAPI
-png_read_end(png_structp png_ptr, png_infop info_ptr)
+png_read_end(png_structrp png_ptr, png_inforp info_ptr)
{
- png_byte chunk_length[4];
- png_uint_32 length;
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ int keep;
+#endif
- png_debug(1, "in png_read_end\n");
- if(png_ptr == NULL) return;
- png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+ png_debug(1, "in png_read_end");
+
+ if (png_ptr == NULL)
+ return;
+
+ /* If png_read_end is called in the middle of reading the rows there may
+ * still be pending IDAT data and an owned zstream. Deal with this here.
+ */
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0)
+#endif
+ png_read_finish_IDAT(png_ptr);
+
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Report invalid palette index; added at libng-1.5.10 */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= png_ptr->num_palette)
+ png_benign_error(png_ptr, "Read palette index exceeding num_palette");
+#endif
do
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IHDR;
- PNG_CONST PNG_IDAT;
- PNG_CONST PNG_IEND;
- PNG_CONST PNG_PLTE;
-#if defined(PNG_READ_bKGD_SUPPORTED)
- PNG_CONST PNG_bKGD;
-#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- PNG_CONST PNG_cHRM;
-#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
- PNG_CONST PNG_gAMA;
-#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
- PNG_CONST PNG_hIST;
-#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
- PNG_CONST PNG_iCCP;
-#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- PNG_CONST PNG_iTXt;
-#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- PNG_CONST PNG_oFFs;
-#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- PNG_CONST PNG_pCAL;
-#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- PNG_CONST PNG_pHYs;
-#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- PNG_CONST PNG_sBIT;
-#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- PNG_CONST PNG_sCAL;
-#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- PNG_CONST PNG_sPLT;
-#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- PNG_CONST PNG_sRGB;
-#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- PNG_CONST PNG_tEXt;
-#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- PNG_CONST PNG_tIME;
-#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- PNG_CONST PNG_tRNS;
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- PNG_CONST PNG_zTXt;
-#endif
-#endif /* PNG_USE_LOCAL_ARRAYS */
+ png_uint_32 length = png_read_chunk_header(png_ptr);
+ png_uint_32 chunk_name = png_ptr->chunk_name;
- png_read_data(png_ptr, chunk_length, 4);
- length = png_get_uint_31(png_ptr,chunk_length);
+ if (chunk_name != png_IDAT)
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
- png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
-
- png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
-
- if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
- png_handle_IHDR(png_ptr, info_ptr, length);
- else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ if (chunk_name == png_IEND)
png_handle_IEND(png_ptr, info_ptr, length);
+
+ else if (chunk_name == png_IHDR)
+ png_handle_IHDR(png_ptr, info_ptr, length);
+
+ else if (info_ptr == NULL)
+ png_crc_finish(png_ptr, length);
+
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
- else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
{
- if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ if (chunk_name == png_IDAT)
{
- if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
- png_error(png_ptr, "Too many IDAT's found");
+ if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
+ || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)
+ png_benign_error(png_ptr, ".Too many IDATs found");
}
- png_handle_unknown(png_ptr, info_ptr, length);
- if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_unknown(png_ptr, info_ptr, length, keep);
+ if (chunk_name == png_PLTE)
png_ptr->mode |= PNG_HAVE_PLTE;
}
#endif
- else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+
+ else if (chunk_name == png_IDAT)
{
/* Zero length IDATs are legal after the last IDAT has been
- * read, but not after other chunks have been read.
+ * read, but not after other chunks have been read. 1.6 does not
+ * always read all the deflate data; specifically it cannot be relied
+ * upon to read the Adler32 at the end. If it doesn't ignore IDAT
+ * chunks which are longer than zero as well:
*/
- if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
- png_error(png_ptr, "Too many IDAT's found");
+ if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
+ || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)
+ png_benign_error(png_ptr, "..Too many IDATs found");
+
png_crc_finish(png_ptr, length);
}
- else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ else if (chunk_name == png_PLTE)
png_handle_PLTE(png_ptr, info_ptr, length);
-#if defined(PNG_READ_bKGD_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+
+#ifdef PNG_READ_bKGD_SUPPORTED
+ else if (chunk_name == png_bKGD)
png_handle_bKGD(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+
+#ifdef PNG_READ_cHRM_SUPPORTED
+ else if (chunk_name == png_cHRM)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_gAMA_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+
+#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
-#if defined(PNG_READ_hIST_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+
+#ifdef PNG_READ_hIST_SUPPORTED
+ else if (chunk_name == png_hIST)
png_handle_hIST(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+
+#ifdef PNG_READ_oFFs_SUPPORTED
+ else if (chunk_name == png_oFFs)
png_handle_oFFs(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+
+#ifdef PNG_READ_pCAL_SUPPORTED
+ else if (chunk_name == png_pCAL)
png_handle_pCAL(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+
+#ifdef PNG_READ_sCAL_SUPPORTED
+ else if (chunk_name == png_sCAL)
png_handle_sCAL(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+
+#ifdef PNG_READ_pHYs_SUPPORTED
+ else if (chunk_name == png_pHYs)
png_handle_pHYs(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+
+#ifdef PNG_READ_sBIT_SUPPORTED
+ else if (chunk_name == png_sBIT)
png_handle_sBIT(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+
+#ifdef PNG_READ_sRGB_SUPPORTED
+ else if (chunk_name == png_sRGB)
png_handle_sRGB(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_iCCP_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+
+#ifdef PNG_READ_iCCP_SUPPORTED
+ else if (chunk_name == png_iCCP)
png_handle_iCCP(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_sPLT_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+
+#ifdef PNG_READ_sPLT_SUPPORTED
+ else if (chunk_name == png_sPLT)
png_handle_sPLT(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+
+#ifdef PNG_READ_tEXt_SUPPORTED
+ else if (chunk_name == png_tEXt)
png_handle_tEXt(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+
+#ifdef PNG_READ_tIME_SUPPORTED
+ else if (chunk_name == png_tIME)
png_handle_tIME(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+
+#ifdef PNG_READ_tRNS_SUPPORTED
+ else if (chunk_name == png_tRNS)
png_handle_tRNS(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+
+#ifdef PNG_READ_zTXt_SUPPORTED
+ else if (chunk_name == png_zTXt)
png_handle_zTXt(png_ptr, info_ptr, length);
#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
- else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+
+#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);
- } while (!(png_ptr->mode & PNG_HAVE_IEND));
+ png_handle_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+ } while ((png_ptr->mode & PNG_HAVE_IEND) == 0);
}
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+#endif /* SEQUENTIAL_READ */
-/* free all memory used by the read */
-void PNGAPI
-png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
- png_infopp end_info_ptr_ptr)
+/* Free all memory used in the read struct */
+static void
+png_read_destroy(png_structrp png_ptr)
{
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL, end_info_ptr = NULL;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_free_ptr free_fn = NULL;
- png_voidp mem_ptr = NULL;
+ png_debug(1, "in png_read_destroy");
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ png_destroy_gamma_table(png_ptr);
#endif
- png_debug(1, "in png_destroy_read_struct\n");
- if (png_ptr_ptr != NULL)
- {
- png_ptr = *png_ptr_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- free_fn = png_ptr->free_fn;
- mem_ptr = png_ptr->mem_ptr;
-#endif
- }
-
- if (info_ptr_ptr != NULL)
- info_ptr = *info_ptr_ptr;
-
- if (end_info_ptr_ptr != NULL)
- end_info_ptr = *end_info_ptr_ptr;
-
- png_read_destroy(png_ptr, info_ptr, end_info_ptr);
-
- if (info_ptr != NULL)
- {
-#if defined(PNG_TEXT_SUPPORTED)
- png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
-#endif
-
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
- (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)info_ptr);
-#endif
- *info_ptr_ptr = NULL;
- }
-
- if (end_info_ptr != NULL)
- {
-#if defined(PNG_READ_TEXT_SUPPORTED)
- png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1);
-#endif
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn,
- (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)end_info_ptr);
-#endif
- *end_info_ptr_ptr = NULL;
- }
-
- if (png_ptr != NULL)
- {
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
- (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)png_ptr);
-#endif
- *png_ptr_ptr = NULL;
- }
-}
-
-/* free all memory used by the read (old method) */
-void /* PRIVATE */
-png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
-{
-#ifdef PNG_SETJMP_SUPPORTED
- jmp_buf tmp_jmp;
-#endif
- png_error_ptr error_fn;
- png_error_ptr warning_fn;
- png_voidp error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_free_ptr free_fn;
-#endif
-
- png_debug(1, "in png_read_destroy\n");
- if (info_ptr != NULL)
- png_info_destroy(png_ptr, info_ptr);
-
- if (end_info_ptr != NULL)
- png_info_destroy(png_ptr, end_info_ptr);
-
- png_free(png_ptr, png_ptr->zbuf);
png_free(png_ptr, png_ptr->big_row_buf);
- png_free(png_ptr, png_ptr->prev_row);
-#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_ptr->big_row_buf = NULL;
+ png_free(png_ptr, png_ptr->big_prev_row);
+ png_ptr->big_prev_row = NULL;
+ png_free(png_ptr, png_ptr->read_buffer);
+ png_ptr->read_buffer = NULL;
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
png_free(png_ptr, png_ptr->palette_lookup);
- png_free(png_ptr, png_ptr->dither_index);
+ png_ptr->palette_lookup = NULL;
+ png_free(png_ptr, png_ptr->quantize_index);
+ png_ptr->quantize_index = NULL;
#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- png_free(png_ptr, png_ptr->gamma_table);
-#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- png_free(png_ptr, png_ptr->gamma_from_1);
- png_free(png_ptr, png_ptr->gamma_to_1);
-#endif
-#ifdef PNG_FREE_ME_SUPPORTED
- if (png_ptr->free_me & PNG_FREE_PLTE)
+
+ if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
+ {
png_zfree(png_ptr, png_ptr->palette);
+ png_ptr->palette = NULL;
+ }
png_ptr->free_me &= ~PNG_FREE_PLTE;
-#else
- if (png_ptr->flags & PNG_FLAG_FREE_PLTE)
- png_zfree(png_ptr, png_ptr->palette);
- png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
-#endif
+
#if defined(PNG_tRNS_SUPPORTED) || \
defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-#ifdef PNG_FREE_ME_SUPPORTED
- if (png_ptr->free_me & PNG_FREE_TRNS)
- png_free(png_ptr, png_ptr->trans);
+ if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
+ {
+ png_free(png_ptr, png_ptr->trans_alpha);
+ png_ptr->trans_alpha = NULL;
+ }
png_ptr->free_me &= ~PNG_FREE_TRNS;
-#else
- if (png_ptr->flags & PNG_FLAG_FREE_TRNS)
- png_free(png_ptr, png_ptr->trans);
- png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
-#endif
-#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
-#ifdef PNG_FREE_ME_SUPPORTED
- if (png_ptr->free_me & PNG_FREE_HIST)
- png_free(png_ptr, png_ptr->hist);
- png_ptr->free_me &= ~PNG_FREE_HIST;
-#else
- if (png_ptr->flags & PNG_FLAG_FREE_HIST)
- png_free(png_ptr, png_ptr->hist);
- png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
-#endif
-#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (png_ptr->gamma_16_table != NULL)
- {
- int i;
- int istop = (1 << (8 - png_ptr->gamma_shift));
- for (i = 0; i < istop; i++)
- {
- png_free(png_ptr, png_ptr->gamma_16_table[i]);
- }
- png_free(png_ptr, png_ptr->gamma_16_table);
- }
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_16_from_1 != NULL)
- {
- int i;
- int istop = (1 << (8 - png_ptr->gamma_shift));
- for (i = 0; i < istop; i++)
- {
- png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
- }
- png_free(png_ptr, png_ptr->gamma_16_from_1);
- }
- if (png_ptr->gamma_16_to_1 != NULL)
- {
- int i;
- int istop = (1 << (8 - png_ptr->gamma_shift));
- for (i = 0; i < istop; i++)
- {
- png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
- }
- png_free(png_ptr, png_ptr->gamma_16_to_1);
- }
-#endif
-#endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- png_free(png_ptr, png_ptr->time_buffer);
#endif
inflateEnd(&png_ptr->zstream);
+
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
png_free(png_ptr, png_ptr->save_buffer);
+ png_ptr->save_buffer = NULL;
#endif
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-#ifdef PNG_TEXT_SUPPORTED
- png_free(png_ptr, png_ptr->current_text);
-#endif /* PNG_TEXT_SUPPORTED */
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \
+ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+#endif
- /* Save the important info out of the png_struct, in case it is
- * being used again.
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list = NULL;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && \
+ defined(PNG_ARM_NEON_IMPLEMENTATION)
+ png_free(png_ptr, png_ptr->riffled_palette);
+ png_ptr->riffled_palette = NULL;
+#endif
+
+ /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error
+ * callbacks are still set at this point. They are required to complete the
+ * destruction of the png_struct itself.
*/
-#ifdef PNG_SETJMP_SUPPORTED
- png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
-#endif
+}
- error_fn = png_ptr->error_fn;
- warning_fn = png_ptr->warning_fn;
- error_ptr = png_ptr->error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- free_fn = png_ptr->free_fn;
-#endif
+/* Free all memory used by the read */
+void PNGAPI
+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
+ png_infopp end_info_ptr_ptr)
+{
+ png_structrp png_ptr = NULL;
- png_memset(png_ptr, 0, png_sizeof (png_struct));
+ png_debug(1, "in png_destroy_read_struct");
- png_ptr->error_fn = error_fn;
- png_ptr->warning_fn = warning_fn;
- png_ptr->error_ptr = error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_ptr->free_fn = free_fn;
-#endif
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
-#ifdef PNG_SETJMP_SUPPORTED
- png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
-#endif
+ if (png_ptr == NULL)
+ return;
+ /* libpng 1.6.0: use the API to destroy info structs to ensure consistent
+ * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API.
+ * The extra was, apparently, unnecessary yet this hides memory leak bugs.
+ */
+ png_destroy_info_struct(png_ptr, end_info_ptr_ptr);
+ png_destroy_info_struct(png_ptr, info_ptr_ptr);
+
+ *png_ptr_ptr = NULL;
+ png_read_destroy(png_ptr);
+ png_destroy_png_struct(png_ptr);
}
void PNGAPI
-png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
+png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
png_ptr->read_row_fn = read_row_fn;
}
-#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
-png_read_png(png_structp png_ptr, png_infop info_ptr,
- int transforms,
- voidp params)
+png_read_png(png_structrp png_ptr, png_inforp info_ptr,
+ int transforms, voidp params)
{
- int row;
+ png_debug(1, "in png_read_png");
- if(png_ptr == NULL) return;
-#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
- /* invert the alpha channel from opacity to transparency
- */
- if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
- png_set_invert_alpha(png_ptr);
-#endif
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
/* png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk).
*/
png_read_info(png_ptr, info_ptr);
- if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
- png_error(png_ptr,"Image is too high to process with png_read_png()");
+ if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep)))
+ png_error(png_ptr, "Image is too high to process with png_read_png()");
/* -------------- image transformations start here ------------------- */
-
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
- /* tell libpng to strip 16 bit/color files down to 8 bits per color
+ /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM
+ * is not implemented. This will only happen in de-configured (non-default)
+ * libpng builds. The results can be unexpected - png_read_png may return
+ * short or mal-formed rows because the transform is skipped.
*/
- if (transforms & PNG_TRANSFORM_STRIP_16)
- png_set_strip_16(png_ptr);
+
+ /* Tell libpng to strip 16-bit/color files down to 8 bits per color.
+ */
+ if ((transforms & PNG_TRANSFORM_SCALE_16) != 0)
+ /* Added at libpng-1.5.4. "strip_16" produces the same result that it
+ * did in earlier versions, while "scale_16" is now more accurate.
+ */
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+ png_set_scale_16(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported");
+#endif
+
+ /* If both SCALE and STRIP are required pngrtran will effectively cancel the
+ * latter by doing SCALE first. This is ok and allows apps not to check for
+ * which is supported to get the right answer.
+ */
+ if ((transforms & PNG_TRANSFORM_STRIP_16) != 0)
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+ png_set_strip_16(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported");
#endif
-#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
/* Strip alpha bytes from the input data without combining with
* the background (not recommended).
*/
- if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
- png_set_strip_alpha(png_ptr);
+ if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0)
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+ png_set_strip_alpha(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported");
#endif
-#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
/* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
* byte into separate bytes (useful for paletted and grayscale images).
*/
- if (transforms & PNG_TRANSFORM_PACKING)
- png_set_packing(png_ptr);
+ if ((transforms & PNG_TRANSFORM_PACKING) != 0)
+#ifdef PNG_READ_PACK_SUPPORTED
+ png_set_packing(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
#endif
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
/* Change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing).
*/
- if (transforms & PNG_TRANSFORM_PACKSWAP)
- png_set_packswap(png_ptr);
+ if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+ png_set_packswap(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
#endif
-#if defined(PNG_READ_EXPAND_SUPPORTED)
/* Expand paletted colors into true RGB triplets
* Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
* Expand paletted or RGB images with transparency to full alpha
* channels so the data will be available as RGBA quartets.
*/
- if (transforms & PNG_TRANSFORM_EXPAND)
- if ((png_ptr->bit_depth < 8) ||
- (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
- (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
- png_set_expand(png_ptr);
+ if ((transforms & PNG_TRANSFORM_EXPAND) != 0)
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ png_set_expand(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported");
#endif
- /* We don't handle background color or gamma transformation or dithering.
+ /* We don't handle background color or gamma transformation or quantizing.
*/
-#if defined(PNG_READ_INVERT_SUPPORTED)
- /* invert monochrome files to have 0 as white and 1 as black
+ /* Invert monochrome files to have 0 as white and 1 as black
*/
- if (transforms & PNG_TRANSFORM_INVERT_MONO)
- png_set_invert_mono(png_ptr);
+ if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
+#ifdef PNG_READ_INVERT_SUPPORTED
+ png_set_invert_mono(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
#endif
-#if defined(PNG_READ_SHIFT_SUPPORTED)
/* If you want to shift the pixel values from the range [0,255] or
* [0,65535] to the original [0,7] or [0,31], or whatever range the
* colors were originally in:
*/
- if ((transforms & PNG_TRANSFORM_SHIFT)
- && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
- {
- png_color_8p sig_bit;
-
- png_get_sBIT(png_ptr, info_ptr, &sig_bit);
- png_set_shift(png_ptr, sig_bit);
- }
+ if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
+#ifdef PNG_READ_SHIFT_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
+ png_set_shift(png_ptr, &info_ptr->sig_bit);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
#endif
-#if defined(PNG_READ_BGR_SUPPORTED)
- /* flip the RGB pixels to BGR (or RGBA to BGRA)
- */
- if (transforms & PNG_TRANSFORM_BGR)
- png_set_bgr(png_ptr);
+ /* Flip the RGB pixels to BGR (or RGBA to BGRA) */
+ if ((transforms & PNG_TRANSFORM_BGR) != 0)
+#ifdef PNG_READ_BGR_SUPPORTED
+ png_set_bgr(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
#endif
-#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
- /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
- */
- if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
- png_set_swap_alpha(png_ptr);
+ /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
+ png_set_swap_alpha(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
#endif
-#if defined(PNG_READ_SWAP_SUPPORTED)
- /* swap bytes of 16 bit files to least significant byte first
- */
- if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
- png_set_swap(png_ptr);
+ /* Swap bytes of 16-bit files to least significant byte first */
+ if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
+#ifdef PNG_READ_SWAP_SUPPORTED
+ png_set_swap(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
+#endif
+
+/* Added at libpng-1.2.41 */
+ /* Invert the alpha channel from opacity to transparency */
+ if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+ png_set_invert_alpha(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
+#endif
+
+/* Added at libpng-1.2.41 */
+ /* Expand grayscale image to RGB */
+ if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0)
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+ png_set_gray_to_rgb(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported");
+#endif
+
+/* Added at libpng-1.5.4 */
+ if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0)
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+ png_set_expand_16(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported");
#endif
/* We don't handle adding filler bytes */
+ /* We use png_read_image and rely on that for interlace handling, but we also
+ * call png_read_update_info therefore must turn on interlace handling now:
+ */
+ (void)png_set_interlace_handling(png_ptr);
+
/* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (i.e., you selected such a transform above).
@@ -1441,33 +1226,3003 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
/* -------------- image transformations end here ------------------- */
-#ifdef PNG_FREE_ME_SUPPORTED
png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
-#endif
- if(info_ptr->row_pointers == NULL)
+ if (info_ptr->row_pointers == NULL)
{
- info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
- info_ptr->height * png_sizeof(png_bytep));
-#ifdef PNG_FREE_ME_SUPPORTED
+ png_uint_32 iptr;
+
+ info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr,
+ info_ptr->height * (sizeof (png_bytep))));
+
+ for (iptr=0; iptrheight; iptr++)
+ info_ptr->row_pointers[iptr] = NULL;
+
info_ptr->free_me |= PNG_FREE_ROWS;
-#endif
- for (row = 0; row < (int)info_ptr->height; row++)
- {
- info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
- png_get_rowbytes(png_ptr, info_ptr));
- }
+
+ for (iptr = 0; iptr < info_ptr->height; iptr++)
+ info_ptr->row_pointers[iptr] = png_voidcast(png_bytep,
+ png_malloc(png_ptr, info_ptr->rowbytes));
}
png_read_image(png_ptr, info_ptr->row_pointers);
info_ptr->valid |= PNG_INFO_IDAT;
- /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
- transforms = transforms; /* quiet compiler warnings */
- params = params;
-
+ PNG_UNUSED(params)
}
-#endif /* PNG_INFO_IMAGE_SUPPORTED */
-#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
-#endif /* PNG_READ_SUPPORTED */
+#endif /* INFO_IMAGE */
+#endif /* SEQUENTIAL_READ */
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+/* SIMPLIFIED READ
+ *
+ * This code currently relies on the sequential reader, though it could easily
+ * be made to work with the progressive one.
+ */
+/* Arguments to png_image_finish_read: */
+
+/* Encoding of PNG data (used by the color-map code) */
+# define P_NOTSET 0 /* File encoding not yet known */
+# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */
+# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */
+# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */
+# define P_LINEAR8 4 /* 8-bit linear: only from a file value */
+
+/* Color-map processing: after libpng has run on the PNG image further
+ * processing may be needed to convert the data to color-map indices.
+ */
+#define PNG_CMAP_NONE 0
+#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */
+#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */
+#define PNG_CMAP_RGB 3 /* Process RGB data */
+#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */
+
+/* The following document where the background is for each processing case. */
+#define PNG_CMAP_NONE_BACKGROUND 256
+#define PNG_CMAP_GA_BACKGROUND 231
+#define PNG_CMAP_TRANS_BACKGROUND 254
+#define PNG_CMAP_RGB_BACKGROUND 256
+#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216
+
+typedef struct
+{
+ /* Arguments: */
+ png_imagep image;
+ png_voidp buffer;
+ png_int_32 row_stride;
+ png_voidp colormap;
+ png_const_colorp background;
+ /* Local variables: */
+ png_voidp local_row;
+ png_voidp first_row;
+ ptrdiff_t row_bytes; /* step between rows */
+ int file_encoding; /* E_ values above */
+ png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */
+ int colormap_processing; /* PNG_CMAP_ values above */
+} png_image_read_control;
+
+/* Do all the *safe* initialization - 'safe' means that png_error won't be
+ * called, so setting up the jmp_buf is not required. This means that anything
+ * called from here must *not* call png_malloc - it has to call png_malloc_warn
+ * instead so that control is returned safely back to this routine.
+ */
+static int
+png_image_read_init(png_imagep image)
+{
+ if (image->opaque == NULL)
+ {
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image,
+ png_safe_error, png_safe_warning);
+
+ /* And set the rest of the structure to NULL to ensure that the various
+ * fields are consistent.
+ */
+ memset(image, 0, (sizeof *image));
+ image->version = PNG_IMAGE_VERSION;
+
+ if (png_ptr != NULL)
+ {
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+
+ if (info_ptr != NULL)
+ {
+ png_controlp control = png_voidcast(png_controlp,
+ png_malloc_warn(png_ptr, (sizeof *control)));
+
+ if (control != NULL)
+ {
+ memset(control, 0, (sizeof *control));
+
+ control->png_ptr = png_ptr;
+ control->info_ptr = info_ptr;
+ control->for_write = 0;
+
+ image->opaque = control;
+ return 1;
+ }
+
+ /* Error clean up */
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ }
+
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ }
+
+ return png_image_error(image, "png_image_read: out of memory");
+ }
+
+ return png_image_error(image, "png_image_read: opaque pointer not NULL");
+}
+
+/* Utility to find the base format of a PNG file from a png_struct. */
+static png_uint_32
+png_image_format(png_structrp png_ptr)
+{
+ png_uint_32 format = 0;
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+ format |= PNG_FORMAT_FLAG_COLOR;
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
+ format |= PNG_FORMAT_FLAG_ALPHA;
+
+ /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS
+ * sets the png_struct fields; that's all we are interested in here. The
+ * precise interaction with an app call to png_set_tRNS and PNG file reading
+ * is unclear.
+ */
+ else if (png_ptr->num_trans > 0)
+ format |= PNG_FORMAT_FLAG_ALPHA;
+
+ if (png_ptr->bit_depth == 16)
+ format |= PNG_FORMAT_FLAG_LINEAR;
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0)
+ format |= PNG_FORMAT_FLAG_COLORMAP;
+
+ return format;
+}
+
+/* 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
+ * file sRGB gamma is 2.2
+ */
+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;
+
+ return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
+ }
+
+ return 1;
+}
+
+/* Do the main body of a 'png_image_begin_read' function; read the PNG file
+ * header and fill in all the information. This is executed in a safe context,
+ * unlike the init routine above.
+ */
+static int
+png_image_read_header(png_voidp argument)
+{
+ png_imagep image = png_voidcast(png_imagep, argument);
+ png_structrp png_ptr = image->opaque->png_ptr;
+ png_inforp info_ptr = image->opaque->info_ptr;
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ png_set_benign_errors(png_ptr, 1/*warn*/);
+#endif
+ png_read_info(png_ptr, info_ptr);
+
+ /* Do this the fast way; just read directly out of png_struct. */
+ image->width = png_ptr->width;
+ image->height = png_ptr->height;
+
+ {
+ png_uint_32 format = png_image_format(png_ptr);
+
+ 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.
+ */
+ 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))
+ image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;
+#endif
+ }
+
+ /* We need the maximum number of entries regardless of the format the
+ * application sets here.
+ */
+ {
+ png_uint_32 cmap_entries;
+
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ cmap_entries = 1U << png_ptr->bit_depth;
+ break;
+
+ case PNG_COLOR_TYPE_PALETTE:
+ cmap_entries = (png_uint_32)png_ptr->num_palette;
+ break;
+
+ default:
+ cmap_entries = 256;
+ break;
+ }
+
+ if (cmap_entries > 256)
+ cmap_entries = 256;
+
+ image->colormap_entries = cmap_entries;
+ }
+
+ return 1;
+}
+
+#ifdef PNG_STDIO_SUPPORTED
+int PNGAPI
+png_image_begin_read_from_stdio(png_imagep image, FILE* file)
+{
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (file != NULL)
+ {
+ if (png_image_read_init(image) != 0)
+ {
+ /* This is slightly evil, but png_init_io doesn't do anything other
+ * than this and we haven't changed the standard IO functions so
+ * this saves a 'safe' function.
+ */
+ image->opaque->png_ptr->io_ptr = file;
+ return png_safe_execute(image, png_image_read_header, image);
+ }
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_begin_read_from_stdio: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION");
+
+ return 0;
+}
+
+int PNGAPI
+png_image_begin_read_from_file(png_imagep image, const char *file_name)
+{
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (file_name != NULL)
+ {
+ FILE *fp = fopen(file_name, "rb");
+
+ if (fp != NULL)
+ {
+ if (png_image_read_init(image) != 0)
+ {
+ image->opaque->png_ptr->io_ptr = fp;
+ image->opaque->owned_file = 1;
+ return png_safe_execute(image, png_image_read_header, image);
+ }
+
+ /* Clean up: just the opened file. */
+ (void)fclose(fp);
+ }
+
+ else
+ return png_image_error(image, strerror(errno));
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_begin_read_from_file: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION");
+
+ return 0;
+}
+#endif /* STDIO */
+
+static void PNGCBAPI
+png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need)
+{
+ if (png_ptr != NULL)
+ {
+ png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr);
+ if (image != NULL)
+ {
+ png_controlp cp = image->opaque;
+ if (cp != NULL)
+ {
+ png_const_bytep memory = cp->memory;
+ size_t size = cp->size;
+
+ if (memory != NULL && size >= need)
+ {
+ memcpy(out, memory, need);
+ cp->memory = memory + need;
+ cp->size = size - need;
+ return;
+ }
+
+ png_error(png_ptr, "read beyond end of data");
+ }
+ }
+
+ png_error(png_ptr, "invalid memory read");
+ }
+}
+
+int PNGAPI png_image_begin_read_from_memory(png_imagep image,
+ png_const_voidp memory, size_t size)
+{
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (memory != NULL && size > 0)
+ {
+ if (png_image_read_init(image) != 0)
+ {
+ /* Now set the IO functions to read from the memory buffer and
+ * store it into io_ptr. Again do this in-place to avoid calling a
+ * libpng function that requires error handling.
+ */
+ image->opaque->memory = png_voidcast(png_const_bytep, memory);
+ image->opaque->size = size;
+ image->opaque->png_ptr->io_ptr = image;
+ image->opaque->png_ptr->read_data_fn = png_image_memory_read;
+
+ return png_safe_execute(image, png_image_read_header, image);
+ }
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_begin_read_from_memory: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION");
+
+ return 0;
+}
+
+/* Utility function to skip chunks that are not used by the simplified image
+ * read functions and an appropriate macro to call it.
+ */
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+static void
+png_image_skip_unused_chunks(png_structrp png_ptr)
+{
+ /* Prepare the reader to ignore all recognized chunks whose data will not
+ * be used, i.e., all chunks recognized by libpng except for those
+ * involved in basic image reading:
+ *
+ * IHDR, PLTE, IDAT, IEND
+ *
+ * Or image data handling:
+ *
+ * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT.
+ *
+ * This provides a small performance improvement and eliminates any
+ * 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.)
+ */
+ {
+ static const png_byte chunks_to_process[] = {
+ 98, 75, 71, 68, '\0', /* bKGD */
+ 99, 72, 82, 77, '\0', /* cHRM */
+ 103, 65, 77, 65, '\0', /* gAMA */
+# ifdef PNG_READ_iCCP_SUPPORTED
+ 105, 67, 67, 80, '\0', /* iCCP */
+# endif
+ 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.
+ */
+ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER,
+ NULL, -1);
+
+ /* But do not ignore image data handling chunks */
+ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT,
+ chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5);
+ }
+}
+
+# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p)
+#else
+# define PNG_SKIP_CHUNKS(p) ((void)0)
+#endif /* HANDLE_AS_UNKNOWN */
+
+/* The following macro gives the exact rounded answer for all values in the
+ * range 0..255 (it actually divides by 51.2, but the rounding still generates
+ * the correct numbers 0..5
+ */
+#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8)
+
+/* Utility functions to make particular color-maps */
+static void
+set_file_encoding(png_image_read_control *display)
+{
+ png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;
+ if (png_gamma_significant(g) != 0)
+ {
+ if (png_gamma_not_sRGB(g) != 0)
+ {
+ display->file_encoding = P_FILE;
+ display->gamma_to_linear = png_reciprocal(g);
+ }
+
+ else
+ display->file_encoding = P_sRGB;
+ }
+
+ else
+ display->file_encoding = P_LINEAR8;
+}
+
+static unsigned int
+decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding)
+{
+ if (encoding == P_FILE) /* double check */
+ encoding = display->file_encoding;
+
+ if (encoding == P_NOTSET) /* must be the file encoding */
+ {
+ set_file_encoding(display);
+ encoding = display->file_encoding;
+ }
+
+ switch (encoding)
+ {
+ case P_FILE:
+ value = png_gamma_16bit_correct(value*257, display->gamma_to_linear);
+ break;
+
+ case P_sRGB:
+ value = png_sRGB_table[value];
+ break;
+
+ case P_LINEAR:
+ break;
+
+ case P_LINEAR8:
+ value *= 257;
+ break;
+
+#ifdef __GNUC__
+ default:
+ png_error(display->image->opaque->png_ptr,
+ "unexpected encoding (internal error)");
+#endif
+ }
+
+ return value;
+}
+
+static png_uint_32
+png_colormap_compose(png_image_read_control *display,
+ png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha,
+ png_uint_32 background, int encoding)
+{
+ /* The file value is composed on the background, the background has the given
+ * encoding and so does the result, the file is encoded with P_FILE and the
+ * file and alpha are 8-bit values. The (output) encoding will always be
+ * P_LINEAR or P_sRGB.
+ */
+ png_uint_32 f = decode_gamma(display, foreground, foreground_encoding);
+ png_uint_32 b = decode_gamma(display, background, encoding);
+
+ /* The alpha is always an 8-bit value (it comes from the palette), the value
+ * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires.
+ */
+ f = f * alpha + b * (255-alpha);
+
+ if (encoding == P_LINEAR)
+ {
+ /* Scale to 65535; divide by 255, approximately (in fact this is extremely
+ * accurate, it divides by 255.00000005937181414556, with no overflow.)
+ */
+ f *= 257; /* Now scaled by 65535 */
+ f += f >> 16;
+ f = (f+32768) >> 16;
+ }
+
+ else /* P_sRGB */
+ f = PNG_sRGB_FROM_LINEAR(f);
+
+ return f;
+}
+
+/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must
+ * be 8-bit.
+ */
+static void
+png_create_colormap_entry(png_image_read_control *display,
+ png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue,
+ png_uint_32 alpha, int encoding)
+{
+ png_imagep image = display->image;
+ int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ?
+ P_LINEAR : P_sRGB;
+ int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 &&
+ (red != green || green != blue);
+
+ if (ip > 255)
+ png_error(image->opaque->png_ptr, "color-map index out of range");
+
+ /* Update the cache with whether the file gamma is significantly different
+ * from sRGB.
+ */
+ if (encoding == P_FILE)
+ {
+ if (display->file_encoding == P_NOTSET)
+ set_file_encoding(display);
+
+ /* Note that the cached value may be P_FILE too, but if it is then the
+ * gamma_to_linear member has been set.
+ */
+ encoding = display->file_encoding;
+ }
+
+ if (encoding == P_FILE)
+ {
+ png_fixed_point g = display->gamma_to_linear;
+
+ red = png_gamma_16bit_correct(red*257, g);
+ green = png_gamma_16bit_correct(green*257, g);
+ blue = png_gamma_16bit_correct(blue*257, g);
+
+ if (convert_to_Y != 0 || output_encoding == P_LINEAR)
+ {
+ alpha *= 257;
+ encoding = P_LINEAR;
+ }
+
+ else
+ {
+ red = PNG_sRGB_FROM_LINEAR(red * 255);
+ green = PNG_sRGB_FROM_LINEAR(green * 255);
+ blue = PNG_sRGB_FROM_LINEAR(blue * 255);
+ encoding = P_sRGB;
+ }
+ }
+
+ else if (encoding == P_LINEAR8)
+ {
+ /* This encoding occurs quite frequently in test cases because PngSuite
+ * includes a gAMA 1.0 chunk with most images.
+ */
+ red *= 257;
+ green *= 257;
+ blue *= 257;
+ alpha *= 257;
+ encoding = P_LINEAR;
+ }
+
+ else if (encoding == P_sRGB &&
+ (convert_to_Y != 0 || output_encoding == P_LINEAR))
+ {
+ /* The values are 8-bit sRGB values, but must be converted to 16-bit
+ * linear.
+ */
+ red = png_sRGB_table[red];
+ green = png_sRGB_table[green];
+ blue = png_sRGB_table[blue];
+ alpha *= 257;
+ encoding = P_LINEAR;
+ }
+
+ /* This is set if the color isn't gray but the output is. */
+ if (encoding == P_LINEAR)
+ {
+ if (convert_to_Y != 0)
+ {
+ /* NOTE: these values are copied from png_do_rgb_to_gray */
+ png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green +
+ (png_uint_32)2366 * blue;
+
+ if (output_encoding == P_LINEAR)
+ y = (y + 16384) >> 15;
+
+ else
+ {
+ /* y is scaled by 32768, we need it scaled by 255: */
+ y = (y + 128) >> 8;
+ y *= 255;
+ y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7);
+ alpha = PNG_DIV257(alpha);
+ encoding = P_sRGB;
+ }
+
+ blue = red = green = y;
+ }
+
+ else if (output_encoding == P_sRGB)
+ {
+ red = PNG_sRGB_FROM_LINEAR(red * 255);
+ green = PNG_sRGB_FROM_LINEAR(green * 255);
+ blue = PNG_sRGB_FROM_LINEAR(blue * 255);
+ alpha = PNG_DIV257(alpha);
+ encoding = P_sRGB;
+ }
+ }
+
+ if (encoding != output_encoding)
+ png_error(image->opaque->png_ptr, "bad encoding (internal error)");
+
+ /* Store the value. */
+ {
+# ifdef PNG_FORMAT_AFIRST_SUPPORTED
+ int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
+ (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;
+# else
+# define afirst 0
+# endif
+# ifdef PNG_FORMAT_BGR_SUPPORTED
+ int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
+# else
+# define bgr 0
+# endif
+
+ if (output_encoding == P_LINEAR)
+ {
+ png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap);
+
+ entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);
+
+ /* The linear 16-bit values must be pre-multiplied by the alpha channel
+ * value, if less than 65535 (this is, effectively, composite on black
+ * if the alpha channel is removed.)
+ */
+ switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))
+ {
+ case 4:
+ entry[afirst ? 0 : 3] = (png_uint_16)alpha;
+ /* FALLTHROUGH */
+
+ case 3:
+ if (alpha < 65535)
+ {
+ if (alpha > 0)
+ {
+ blue = (blue * alpha + 32767U)/65535U;
+ green = (green * alpha + 32767U)/65535U;
+ red = (red * alpha + 32767U)/65535U;
+ }
+
+ else
+ red = green = blue = 0;
+ }
+ entry[afirst + (2 ^ bgr)] = (png_uint_16)blue;
+ entry[afirst + 1] = (png_uint_16)green;
+ entry[afirst + bgr] = (png_uint_16)red;
+ break;
+
+ case 2:
+ entry[1 ^ afirst] = (png_uint_16)alpha;
+ /* FALLTHROUGH */
+
+ case 1:
+ if (alpha < 65535)
+ {
+ if (alpha > 0)
+ green = (green * alpha + 32767U)/65535U;
+
+ else
+ green = 0;
+ }
+ entry[afirst] = (png_uint_16)green;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ else /* output encoding is P_sRGB */
+ {
+ png_bytep entry = png_voidcast(png_bytep, display->colormap);
+
+ entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);
+
+ switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))
+ {
+ case 4:
+ entry[afirst ? 0 : 3] = (png_byte)alpha;
+ /* FALLTHROUGH */
+ case 3:
+ entry[afirst + (2 ^ bgr)] = (png_byte)blue;
+ entry[afirst + 1] = (png_byte)green;
+ entry[afirst + bgr] = (png_byte)red;
+ break;
+
+ case 2:
+ entry[1 ^ afirst] = (png_byte)alpha;
+ /* FALLTHROUGH */
+ case 1:
+ entry[afirst] = (png_byte)green;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+# ifdef afirst
+# undef afirst
+# endif
+# ifdef bgr
+# undef bgr
+# endif
+ }
+}
+
+static int
+make_gray_file_colormap(png_image_read_control *display)
+{
+ unsigned int i;
+
+ for (i=0; i<256; ++i)
+ png_create_colormap_entry(display, i, i, i, i, 255, P_FILE);
+
+ return (int)i;
+}
+
+static int
+make_gray_colormap(png_image_read_control *display)
+{
+ unsigned int i;
+
+ for (i=0; i<256; ++i)
+ png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB);
+
+ return (int)i;
+}
+#define PNG_GRAY_COLORMAP_ENTRIES 256
+
+static int
+make_ga_colormap(png_image_read_control *display)
+{
+ unsigned int i, a;
+
+ /* Alpha is retained, the output will be a color-map with entries
+ * selected by six levels of alpha. One transparent entry, 6 gray
+ * levels for all the intermediate alpha values, leaving 230 entries
+ * for the opaque grays. The color-map entries are the six values
+ * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the
+ * relevant entry.
+ *
+ * if (alpha > 229) // opaque
+ * {
+ * // The 231 entries are selected to make the math below work:
+ * base = 0;
+ * entry = (231 * gray + 128) >> 8;
+ * }
+ * else if (alpha < 26) // transparent
+ * {
+ * base = 231;
+ * entry = 0;
+ * }
+ * else // partially opaque
+ * {
+ * base = 226 + 6 * PNG_DIV51(alpha);
+ * entry = PNG_DIV51(gray);
+ * }
+ */
+ i = 0;
+ while (i < 231)
+ {
+ unsigned int gray = (i * 256 + 115) / 231;
+ png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB);
+ }
+
+ /* 255 is used here for the component values for consistency with the code
+ * that undoes premultiplication in pngwrite.c.
+ */
+ png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB);
+
+ for (a=1; a<5; ++a)
+ {
+ unsigned int g;
+
+ for (g=0; g<6; ++g)
+ png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,
+ P_sRGB);
+ }
+
+ return (int)i;
+}
+
+#define PNG_GA_COLORMAP_ENTRIES 256
+
+static int
+make_rgb_colormap(png_image_read_control *display)
+{
+ unsigned int i, r;
+
+ /* Build a 6x6x6 opaque RGB cube */
+ for (i=r=0; r<6; ++r)
+ {
+ unsigned int g;
+
+ for (g=0; g<6; ++g)
+ {
+ unsigned int b;
+
+ for (b=0; b<6; ++b)
+ png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,
+ P_sRGB);
+ }
+ }
+
+ return (int)i;
+}
+
+#define PNG_RGB_COLORMAP_ENTRIES 216
+
+/* Return a palette index to the above palette given three 8-bit sRGB values. */
+#define PNG_RGB_INDEX(r,g,b) \
+ ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b)))
+
+static int
+png_image_read_colormap(png_voidp argument)
+{
+ png_image_read_control *display =
+ png_voidcast(png_image_read_control*, argument);
+ png_imagep image = display->image;
+
+ png_structrp png_ptr = image->opaque->png_ptr;
+ png_uint_32 output_format = image->format;
+ int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ?
+ P_LINEAR : P_sRGB;
+
+ unsigned int cmap_entries;
+ unsigned int output_processing; /* Output processing option */
+ unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */
+
+ /* Background information; the background color and the index of this color
+ * in the color-map if it exists (else 256).
+ */
+ unsigned int background_index = 256;
+ png_uint_32 back_r, back_g, back_b;
+
+ /* Flags to accumulate things that need to be done to the input. */
+ int expand_tRNS = 0;
+
+ /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is
+ * very difficult to do, the results look awful, and it is difficult to see
+ * what possible use it is because the application can't control the
+ * color-map.
+ */
+ if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 ||
+ png_ptr->num_trans > 0) /* alpha in input */ &&
+ ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */)
+ {
+ if (output_encoding == P_LINEAR) /* compose on black */
+ back_b = back_g = back_r = 0;
+
+ else if (display->background == NULL /* no way to remove it */)
+ png_error(png_ptr,
+ "background color must be supplied to remove alpha/transparency");
+
+ /* Get a copy of the background color (this avoids repeating the checks
+ * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the
+ * output format.
+ */
+ else
+ {
+ back_g = display->background->green;
+ if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0)
+ {
+ back_r = display->background->red;
+ back_b = display->background->blue;
+ }
+ else
+ back_b = back_r = back_g;
+ }
+ }
+
+ else if (output_encoding == P_LINEAR)
+ back_b = back_r = back_g = 65535;
+
+ else
+ back_b = back_r = back_g = 255;
+
+ /* 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.
+ */
+ 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;
+
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
+ }
+
+ /* Decide what to do based on the PNG color type of the input data. The
+ * utility function png_create_colormap_entry deals with most aspects of the
+ * output transformations; this code works out how to produce bytes of
+ * color-map entries from the original format.
+ */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ if (png_ptr->bit_depth <= 8)
+ {
+ /* There at most 256 colors in the output, regardless of
+ * transparency.
+ */
+ unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0;
+
+ cmap_entries = 1U << png_ptr->bit_depth;
+ if (cmap_entries > image->colormap_entries)
+ png_error(png_ptr, "gray[8] color-map: too few entries");
+
+ step = 255 / (cmap_entries - 1);
+ output_processing = PNG_CMAP_NONE;
+
+ /* If there is a tRNS chunk then this either selects a transparent
+ * value or, if the output has no alpha, the background color.
+ */
+ if (png_ptr->num_trans > 0)
+ {
+ trans = png_ptr->trans_color.gray;
+
+ if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0)
+ back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
+ }
+
+ /* png_create_colormap_entry just takes an RGBA and writes the
+ * corresponding color-map entry using the format from 'image',
+ * including the required conversion to sRGB or linear as
+ * appropriate. The input values are always either sRGB (if the
+ * gamma correction flag is 0) or 0..255 scaled file encoded values
+ * (if the function must gamma correct them).
+ */
+ for (i=val=0; ibit_depth < 8)
+ png_set_packing(png_ptr);
+ }
+
+ else /* bit depth is 16 */
+ {
+ /* The 16-bit input values can be converted directly to 8-bit gamma
+ * encoded values; however, if a tRNS chunk is present 257 color-map
+ * entries are required. This means that the extra entry requires
+ * special processing; add an alpha channel, sacrifice gray level
+ * 254 and convert transparent (alpha==0) entries to that.
+ *
+ * Use libpng to chop the data to 8 bits. Convert it to sRGB at the
+ * same time to minimize quality loss. If a tRNS chunk is present
+ * this means libpng must handle it too; otherwise it is impossible
+ * to do the exact match on the 16-bit value.
+ *
+ * If the output has no alpha channel *and* the background color is
+ * gray then it is possible to let libpng handle the substitution by
+ * ensuring that the corresponding gray level matches the background
+ * color exactly.
+ */
+ data_encoding = P_sRGB;
+
+ if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "gray[16] color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_gray_colormap(display);
+
+ if (png_ptr->num_trans > 0)
+ {
+ unsigned int back_alpha;
+
+ if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ back_alpha = 0;
+
+ else
+ {
+ if (back_r == back_g && back_g == back_b)
+ {
+ /* Background is gray; no special processing will be
+ * required.
+ */
+ png_color_16 c;
+ png_uint_32 gray = back_g;
+
+ if (output_encoding == P_LINEAR)
+ {
+ gray = PNG_sRGB_FROM_LINEAR(gray * 255);
+
+ /* And make sure the corresponding palette entry
+ * matches.
+ */
+ png_create_colormap_entry(display, gray, back_g, back_g,
+ back_g, 65535, P_LINEAR);
+ }
+
+ /* The background passed to libpng, however, must be the
+ * sRGB value.
+ */
+ c.index = 0; /*unused*/
+ c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
+
+ /* NOTE: does this work without expanding tRNS to alpha?
+ * It should be the color->gray case below apparently
+ * doesn't.
+ */
+ png_set_background_fixed(png_ptr, &c,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
+ 0/*gamma: not used*/);
+
+ output_processing = PNG_CMAP_NONE;
+ break;
+ }
+#ifdef __COVERITY__
+ /* Coverity claims that output_encoding cannot be 2 (P_LINEAR)
+ * here.
+ */
+ back_alpha = 255;
+#else
+ back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
+#endif
+ }
+
+ /* output_processing means that the libpng-processed row will be
+ * 8-bit GA and it has to be processing to single byte color-map
+ * values. Entry 254 is replaced by either a completely
+ * transparent entry or by the background color at full
+ * precision (and the background color is not a simple gray
+ * level in this case.)
+ */
+ expand_tRNS = 1;
+ output_processing = PNG_CMAP_TRANS;
+ background_index = 254;
+
+ /* And set (overwrite) color-map entry 254 to the actual
+ * background color at full precision.
+ */
+ png_create_colormap_entry(display, 254, back_r, back_g, back_b,
+ back_alpha, output_encoding);
+ }
+
+ else
+ output_processing = PNG_CMAP_NONE;
+ }
+ break;
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum
+ * of 65536 combinations. If, however, the alpha channel is to be
+ * removed there are only 256 possibilities if the background is gray.
+ * (Otherwise there is a subset of the 65536 possibilities defined by
+ * the triangle between black, white and the background color.)
+ *
+ * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to
+ * worry about tRNS matching - tRNS is ignored if there is an alpha
+ * channel.
+ */
+ data_encoding = P_sRGB;
+
+ if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "gray+alpha color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_ga_colormap(display);
+
+ background_index = PNG_CMAP_GA_BACKGROUND;
+ output_processing = PNG_CMAP_GA;
+ }
+
+ else /* alpha is removed */
+ {
+ /* Alpha must be removed as the PNG data is processed when the
+ * background is a color because the G and A channels are
+ * independent and the vector addition (non-parallel vectors) is a
+ * 2-D problem.
+ *
+ * This can be reduced to the same algorithm as above by making a
+ * colormap containing gray levels (for the opaque grays), a
+ * background entry (for a transparent pixel) and a set of four six
+ * level color values, one set for each intermediate alpha value.
+ * See the comments in make_ga_colormap for how this works in the
+ * per-pixel processing.
+ *
+ * If the background is gray, however, we only need a 256 entry gray
+ * level color map. It is sufficient to make the entry generated
+ * for the background color be exactly the color specified.
+ */
+ if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 ||
+ (back_r == back_g && back_g == back_b))
+ {
+ /* Background is gray; no special processing will be required. */
+ png_color_16 c;
+ png_uint_32 gray = back_g;
+
+ if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "gray-alpha color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_gray_colormap(display);
+
+ if (output_encoding == P_LINEAR)
+ {
+ gray = PNG_sRGB_FROM_LINEAR(gray * 255);
+
+ /* And make sure the corresponding palette entry matches. */
+ png_create_colormap_entry(display, gray, back_g, back_g,
+ back_g, 65535, P_LINEAR);
+ }
+
+ /* The background passed to libpng, however, must be the sRGB
+ * value.
+ */
+ c.index = 0; /*unused*/
+ c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
+
+ png_set_background_fixed(png_ptr, &c,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
+ 0/*gamma: not used*/);
+
+ output_processing = PNG_CMAP_NONE;
+ }
+
+ else
+ {
+ png_uint_32 i, a;
+
+ /* This is the same as png_make_ga_colormap, above, except that
+ * the entries are all opaque.
+ */
+ if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "ga-alpha color-map: too few entries");
+
+ i = 0;
+ while (i < 231)
+ {
+ png_uint_32 gray = (i * 256 + 115) / 231;
+ png_create_colormap_entry(display, i++, gray, gray, gray,
+ 255, P_sRGB);
+ }
+
+ /* NOTE: this preserves the full precision of the application
+ * background color.
+ */
+ background_index = i;
+ png_create_colormap_entry(display, i++, back_r, back_g, back_b,
+#ifdef __COVERITY__
+ /* Coverity claims that output_encoding
+ * cannot be 2 (P_LINEAR) here.
+ */ 255U,
+#else
+ output_encoding == P_LINEAR ? 65535U : 255U,
+#endif
+ output_encoding);
+
+ /* For non-opaque input composite on the sRGB background - this
+ * requires inverting the encoding for each component. The input
+ * is still converted to the sRGB encoding because this is a
+ * reasonable approximate to the logarithmic curve of human
+ * visual sensitivity, at least over the narrow range which PNG
+ * represents. Consequently 'G' is always sRGB encoded, while
+ * 'A' is linear. We need the linear background colors.
+ */
+ if (output_encoding == P_sRGB) /* else already linear */
+ {
+ /* This may produce a value not exactly matching the
+ * background, but that's ok because these numbers are only
+ * used when alpha != 0
+ */
+ back_r = png_sRGB_table[back_r];
+ back_g = png_sRGB_table[back_g];
+ back_b = png_sRGB_table[back_b];
+ }
+
+ for (a=1; a<5; ++a)
+ {
+ unsigned int g;
+
+ /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled
+ * by an 8-bit alpha value (0..255).
+ */
+ png_uint_32 alpha = 51 * a;
+ png_uint_32 back_rx = (255-alpha) * back_r;
+ png_uint_32 back_gx = (255-alpha) * back_g;
+ png_uint_32 back_bx = (255-alpha) * back_b;
+
+ for (g=0; g<6; ++g)
+ {
+ png_uint_32 gray = png_sRGB_table[g*51] * alpha;
+
+ png_create_colormap_entry(display, i++,
+ PNG_sRGB_FROM_LINEAR(gray + back_rx),
+ PNG_sRGB_FROM_LINEAR(gray + back_gx),
+ PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB);
+ }
+ }
+
+ cmap_entries = i;
+ output_processing = PNG_CMAP_GA;
+ }
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ /* Exclude the case where the output is gray; we can always handle this
+ * with the cases above.
+ */
+ if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)
+ {
+ /* The color-map will be grayscale, so we may as well convert the
+ * input RGB values to a simple grayscale and use the grayscale
+ * code above.
+ *
+ * NOTE: calling this apparently damages the recognition of the
+ * transparent color in background color handling; call
+ * png_set_tRNS_to_alpha before png_set_background_fixed.
+ */
+ png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,
+ -1);
+ data_encoding = P_sRGB;
+
+ /* The output will now be one or two 8-bit gray or gray+alpha
+ * channels. The more complex case arises when the input has alpha.
+ */
+ if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ png_ptr->num_trans > 0) &&
+ (output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ /* Both input and output have an alpha channel, so no background
+ * processing is required; just map the GA bytes to the right
+ * color-map entry.
+ */
+ expand_tRNS = 1;
+
+ if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "rgb[ga] color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_ga_colormap(display);
+ background_index = PNG_CMAP_GA_BACKGROUND;
+ output_processing = PNG_CMAP_GA;
+ }
+
+ else
+ {
+ /* 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.
+ */
+ if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "rgb[gray] color-map: too few entries");
+
+ /* Ideally this code would use libpng to do the gamma correction,
+ * but if an input alpha channel is to be removed we will hit the
+ * libpng bug in gamma+compose+rgb-to-gray (the double gamma
+ * correction bug). Fix this by dropping the gamma correction in
+ * 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.
+ */
+ if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ png_ptr->num_trans > 0) &&
+ png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
+ {
+ cmap_entries = (unsigned int)make_gray_file_colormap(display);
+ data_encoding = P_FILE;
+ }
+
+ else
+ cmap_entries = (unsigned int)make_gray_colormap(display);
+
+ /* But if the input has alpha or transparency it must be removed
+ */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ png_ptr->num_trans > 0)
+ {
+ png_color_16 c;
+ png_uint_32 gray = back_g;
+
+ /* We need to ensure that the application background exists in
+ * the colormap and that completely transparent pixels map to
+ * it. Achieve this simply by ensuring that the entry
+ * selected for the background really is the background color.
+ */
+ if (data_encoding == P_FILE) /* from the fixup above */
+ {
+ /* The app supplied a gray which is in output_encoding, we
+ * need to convert it to a value of the input (P_FILE)
+ * encoding then set this palette entry to the required
+ * output encoding.
+ */
+ 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 */
+
+ /* And make sure the corresponding palette entry contains
+ * exactly the required sRGB value.
+ */
+ png_create_colormap_entry(display, gray, back_g, back_g,
+ back_g, 0/*unused*/, output_encoding);
+ }
+
+ else if (output_encoding == P_LINEAR)
+ {
+ gray = PNG_sRGB_FROM_LINEAR(gray * 255);
+
+ /* And make sure the corresponding palette entry matches.
+ */
+ png_create_colormap_entry(display, gray, back_g, back_g,
+ back_g, 0/*unused*/, P_LINEAR);
+ }
+
+ /* The background passed to libpng, however, must be the
+ * output (normally sRGB) value.
+ */
+ c.index = 0; /*unused*/
+ c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
+
+ /* NOTE: the following is apparently a bug in libpng. Without
+ * it the transparent color recognition in
+ * png_set_background_fixed seems to go wrong.
+ */
+ expand_tRNS = 1;
+ png_set_background_fixed(png_ptr, &c,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
+ 0/*gamma: not used*/);
+ }
+
+ output_processing = PNG_CMAP_NONE;
+ }
+ }
+
+ else /* output is color */
+ {
+ /* We could use png_quantize here so long as there is no transparent
+ * color or alpha; png_quantize ignores alpha. Easier overall just
+ * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube.
+ * Consequently we always want libpng to produce sRGB data.
+ */
+ data_encoding = P_sRGB;
+
+ /* Is there any transparency or alpha? */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ png_ptr->num_trans > 0)
+ {
+ /* Is there alpha in the output too? If so all four channels are
+ * processed into a special RGB cube with alpha support.
+ */
+ if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ png_uint_32 r;
+
+ if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
+ png_error(png_ptr, "rgb+alpha color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_rgb_colormap(display);
+
+ /* Add a transparent entry. */
+ png_create_colormap_entry(display, cmap_entries, 255, 255,
+ 255, 0, P_sRGB);
+
+ /* This is stored as the background index for the processing
+ * algorithm.
+ */
+ background_index = cmap_entries++;
+
+ /* Add 27 r,g,b entries each with alpha 0.5. */
+ for (r=0; r<256; r = (r << 1) | 0x7f)
+ {
+ png_uint_32 g;
+
+ for (g=0; g<256; g = (g << 1) | 0x7f)
+ {
+ png_uint_32 b;
+
+ /* This generates components with the values 0, 127 and
+ * 255
+ */
+ for (b=0; b<256; b = (b << 1) | 0x7f)
+ png_create_colormap_entry(display, cmap_entries++,
+ r, g, b, 128, P_sRGB);
+ }
+ }
+
+ expand_tRNS = 1;
+ output_processing = PNG_CMAP_RGB_ALPHA;
+ }
+
+ else
+ {
+ /* Alpha/transparency must be removed. The background must
+ * exist in the color map (achieved by setting adding it after
+ * the 666 color-map). If the standard processing code will
+ * pick up this entry automatically that's all that is
+ * required; libpng can be called to do the background
+ * processing.
+ */
+ unsigned int sample_size =
+ PNG_IMAGE_SAMPLE_SIZE(output_format);
+ png_uint_32 r, g, b; /* sRGB background */
+
+ if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
+ png_error(png_ptr, "rgb-alpha color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_rgb_colormap(display);
+
+ png_create_colormap_entry(display, cmap_entries, back_r,
+ back_g, back_b, 0/*unused*/, output_encoding);
+
+ if (output_encoding == P_LINEAR)
+ {
+ r = PNG_sRGB_FROM_LINEAR(back_r * 255);
+ g = PNG_sRGB_FROM_LINEAR(back_g * 255);
+ b = PNG_sRGB_FROM_LINEAR(back_b * 255);
+ }
+
+ else
+ {
+ r = back_r;
+ g = back_g;
+ b = back_g;
+ }
+
+ /* Compare the newly-created color-map entry with the one the
+ * PNG_CMAP_RGB algorithm will use. If the two entries don't
+ * match, add the new one and set this as the background
+ * index.
+ */
+ if (memcmp((png_const_bytep)display->colormap +
+ sample_size * cmap_entries,
+ (png_const_bytep)display->colormap +
+ sample_size * PNG_RGB_INDEX(r,g,b),
+ sample_size) != 0)
+ {
+ /* The background color must be added. */
+ background_index = cmap_entries++;
+
+ /* Add 27 r,g,b entries each with created by composing with
+ * the background at alpha 0.5.
+ */
+ for (r=0; r<256; r = (r << 1) | 0x7f)
+ {
+ for (g=0; g<256; g = (g << 1) | 0x7f)
+ {
+ /* This generates components with the values 0, 127
+ * and 255
+ */
+ for (b=0; b<256; b = (b << 1) | 0x7f)
+ png_create_colormap_entry(display, cmap_entries++,
+ png_colormap_compose(display, r, P_sRGB, 128,
+ back_r, output_encoding),
+ png_colormap_compose(display, g, P_sRGB, 128,
+ back_g, output_encoding),
+ png_colormap_compose(display, b, P_sRGB, 128,
+ back_b, output_encoding),
+ 0/*unused*/, output_encoding);
+ }
+ }
+
+ expand_tRNS = 1;
+ output_processing = PNG_CMAP_RGB_ALPHA;
+ }
+
+ else /* background color is in the standard color-map */
+ {
+ png_color_16 c;
+
+ c.index = 0; /*unused*/
+ c.red = (png_uint_16)back_r;
+ c.gray = c.green = (png_uint_16)back_g;
+ c.blue = (png_uint_16)back_b;
+
+ png_set_background_fixed(png_ptr, &c,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
+ 0/*gamma: not used*/);
+
+ output_processing = PNG_CMAP_RGB;
+ }
+ }
+ }
+
+ else /* no alpha or transparency in the input */
+ {
+ /* Alpha in the output is irrelevant, simply map the opaque input
+ * pixels to the 6x6x6 color-map.
+ */
+ if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries)
+ png_error(png_ptr, "rgb color-map: too few entries");
+
+ cmap_entries = (unsigned int)make_rgb_colormap(display);
+ output_processing = PNG_CMAP_RGB;
+ }
+ }
+ break;
+
+ case PNG_COLOR_TYPE_PALETTE:
+ /* It's already got a color-map. It may be necessary to eliminate the
+ * tRNS entries though.
+ */
+ {
+ unsigned int num_trans = png_ptr->num_trans;
+ png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL;
+ png_const_colorp colormap = png_ptr->palette;
+ int do_background = trans != NULL &&
+ (output_format & PNG_FORMAT_FLAG_ALPHA) == 0;
+ unsigned int i;
+
+ /* Just in case: */
+ if (trans == NULL)
+ num_trans = 0;
+
+ output_processing = PNG_CMAP_NONE;
+ data_encoding = P_FILE; /* Don't change from color-map indices */
+ cmap_entries = (unsigned int)png_ptr->num_palette;
+ if (cmap_entries > 256)
+ cmap_entries = 256;
+
+ if (cmap_entries > (unsigned int)image->colormap_entries)
+ png_error(png_ptr, "palette color-map: too few entries");
+
+ for (i=0; i < cmap_entries; ++i)
+ {
+ if (do_background != 0 && i < num_trans && trans[i] < 255)
+ {
+ if (trans[i] == 0)
+ png_create_colormap_entry(display, i, back_r, back_g,
+ back_b, 0, output_encoding);
+
+ else
+ {
+ /* Must compose the PNG file color in the color-map entry
+ * on the sRGB color in 'back'.
+ */
+ png_create_colormap_entry(display, i,
+ png_colormap_compose(display, colormap[i].red,
+ P_FILE, trans[i], back_r, output_encoding),
+ png_colormap_compose(display, colormap[i].green,
+ P_FILE, trans[i], back_g, output_encoding),
+ png_colormap_compose(display, colormap[i].blue,
+ P_FILE, trans[i], back_b, output_encoding),
+ output_encoding == P_LINEAR ? trans[i] * 257U :
+ trans[i],
+ output_encoding);
+ }
+ }
+
+ else
+ png_create_colormap_entry(display, i, colormap[i].red,
+ colormap[i].green, colormap[i].blue,
+ i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/);
+ }
+
+ /* The PNG data may have indices packed in fewer than 8 bits, it
+ * must be expanded if so.
+ */
+ if (png_ptr->bit_depth < 8)
+ png_set_packing(png_ptr);
+ }
+ break;
+
+ default:
+ png_error(png_ptr, "invalid PNG color type");
+ /*NOT REACHED*/
+ }
+
+ /* Now deal with the output processing */
+ if (expand_tRNS != 0 && png_ptr->num_trans > 0 &&
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0)
+ png_set_tRNS_to_alpha(png_ptr);
+
+ switch (data_encoding)
+ {
+ case P_sRGB:
+ /* Change to 8-bit sRGB */
+ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB);
+ /* FALLTHROUGH */
+
+ case P_FILE:
+ if (png_ptr->bit_depth > 8)
+ png_set_scale_16(png_ptr);
+ break;
+
+#ifdef __GNUC__
+ default:
+ png_error(png_ptr, "bad data option (internal error)");
+#endif
+ }
+
+ if (cmap_entries > 256 || cmap_entries > image->colormap_entries)
+ png_error(png_ptr, "color map overflow (BAD internal error)");
+
+ image->colormap_entries = cmap_entries;
+
+ /* Double check using the recorded background index */
+ switch (output_processing)
+ {
+ case PNG_CMAP_NONE:
+ if (background_index != PNG_CMAP_NONE_BACKGROUND)
+ goto bad_background;
+ break;
+
+ case PNG_CMAP_GA:
+ if (background_index != PNG_CMAP_GA_BACKGROUND)
+ goto bad_background;
+ break;
+
+ case PNG_CMAP_TRANS:
+ if (background_index >= cmap_entries ||
+ background_index != PNG_CMAP_TRANS_BACKGROUND)
+ goto bad_background;
+ break;
+
+ case PNG_CMAP_RGB:
+ if (background_index != PNG_CMAP_RGB_BACKGROUND)
+ goto bad_background;
+ break;
+
+ case PNG_CMAP_RGB_ALPHA:
+ if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND)
+ goto bad_background;
+ break;
+
+ default:
+ png_error(png_ptr, "bad processing option (internal error)");
+
+ bad_background:
+ png_error(png_ptr, "bad background index (internal error)");
+ }
+
+ display->colormap_processing = (int)output_processing;
+
+ return 1/*ok*/;
+}
+
+/* The final part of the color-map read called from png_image_finish_read. */
+static int
+png_image_read_and_map(png_voidp argument)
+{
+ png_image_read_control *display = png_voidcast(png_image_read_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+ int passes;
+
+ /* Called when the libpng data must be transformed into the color-mapped
+ * form. There is a local row buffer in display->local and this routine must
+ * do the interlace handling.
+ */
+ switch (png_ptr->interlaced)
+ {
+ case PNG_INTERLACE_NONE:
+ passes = 1;
+ break;
+
+ case PNG_INTERLACE_ADAM7:
+ passes = PNG_INTERLACE_ADAM7_PASSES;
+ break;
+
+ default:
+ png_error(png_ptr, "unknown interlace type");
+ }
+
+ {
+ png_uint_32 height = image->height;
+ png_uint_32 width = image->width;
+ int proc = display->colormap_processing;
+ png_bytep first_row = png_voidcast(png_bytep, display->first_row);
+ ptrdiff_t step_row = display->row_bytes;
+ int pass;
+
+ for (pass = 0; pass < passes; ++pass)
+ {
+ unsigned int startx, stepx, stepy;
+ png_uint_32 y;
+
+ if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
+ {
+ /* The row may be empty for a short image: */
+ if (PNG_PASS_COLS(width, pass) == 0)
+ continue;
+
+ startx = PNG_PASS_START_COL(pass);
+ stepx = PNG_PASS_COL_OFFSET(pass);
+ y = PNG_PASS_START_ROW(pass);
+ stepy = PNG_PASS_ROW_OFFSET(pass);
+ }
+
+ else
+ {
+ y = 0;
+ startx = 0;
+ stepx = stepy = 1;
+ }
+
+ for (; ylocal_row);
+ png_bytep outrow = first_row + y * step_row;
+ png_const_bytep end_row = outrow + width;
+
+ /* Read read the libpng data into the temporary buffer. */
+ png_read_row(png_ptr, inrow, NULL);
+
+ /* Now process the row according to the processing option, note
+ * that the caller verifies that the format of the libpng output
+ * data is as required.
+ */
+ outrow += startx;
+ switch (proc)
+ {
+ case PNG_CMAP_GA:
+ for (; outrow < end_row; outrow += stepx)
+ {
+ /* The data is always in the PNG order */
+ unsigned int gray = *inrow++;
+ unsigned int alpha = *inrow++;
+ unsigned int entry;
+
+ /* NOTE: this code is copied as a comment in
+ * make_ga_colormap above. Please update the
+ * comment if you change this code!
+ */
+ if (alpha > 229) /* opaque */
+ {
+ entry = (231 * gray + 128) >> 8;
+ }
+ else if (alpha < 26) /* transparent */
+ {
+ entry = 231;
+ }
+ else /* partially opaque */
+ {
+ entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray);
+ }
+
+ *outrow = (png_byte)entry;
+ }
+ break;
+
+ case PNG_CMAP_TRANS:
+ for (; outrow < end_row; outrow += stepx)
+ {
+ png_byte gray = *inrow++;
+ png_byte alpha = *inrow++;
+
+ if (alpha == 0)
+ *outrow = PNG_CMAP_TRANS_BACKGROUND;
+
+ else if (gray != PNG_CMAP_TRANS_BACKGROUND)
+ *outrow = gray;
+
+ else
+ *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1);
+ }
+ break;
+
+ case PNG_CMAP_RGB:
+ for (; outrow < end_row; outrow += stepx)
+ {
+ *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
+ inrow += 3;
+ }
+ break;
+
+ case PNG_CMAP_RGB_ALPHA:
+ for (; outrow < end_row; outrow += stepx)
+ {
+ unsigned int alpha = inrow[3];
+
+ /* Because the alpha entries only hold alpha==0.5 values
+ * split the processing at alpha==0.25 (64) and 0.75
+ * (196).
+ */
+
+ if (alpha >= 196)
+ *outrow = PNG_RGB_INDEX(inrow[0], inrow[1],
+ inrow[2]);
+
+ else if (alpha < 64)
+ *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND;
+
+ else
+ {
+ /* Likewise there are three entries for each of r, g
+ * and b. We could select the entry by popcount on
+ * the top two bits on those architectures that
+ * support it, this is what the code below does,
+ * crudely.
+ */
+ unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1;
+
+ /* Here are how the values map:
+ *
+ * 0x00 .. 0x3f -> 0
+ * 0x40 .. 0xbf -> 1
+ * 0xc0 .. 0xff -> 2
+ *
+ * So, as above with the explicit alpha checks, the
+ * breakpoints are at 64 and 196.
+ */
+ if (inrow[0] & 0x80) back_i += 9; /* red */
+ if (inrow[0] & 0x40) back_i += 9;
+ if (inrow[0] & 0x80) back_i += 3; /* green */
+ if (inrow[0] & 0x40) back_i += 3;
+ if (inrow[0] & 0x80) back_i += 1; /* blue */
+ if (inrow[0] & 0x40) back_i += 1;
+
+ *outrow = (png_byte)back_i;
+ }
+
+ inrow += 4;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int
+png_image_read_colormapped(png_voidp argument)
+{
+ png_image_read_control *display = png_voidcast(png_image_read_control*,
+ argument);
+ png_imagep image = display->image;
+ png_controlp control = image->opaque;
+ png_structrp png_ptr = control->png_ptr;
+ png_inforp info_ptr = control->info_ptr;
+
+ int passes = 0; /* As a flag */
+
+ PNG_SKIP_CHUNKS(png_ptr);
+
+ /* Update the 'info' structure and make sure the result is as required; first
+ * make sure to turn on the interlace handling if it will be required
+ * (because it can't be turned on *after* the call to png_read_update_info!)
+ */
+ if (display->colormap_processing == PNG_CMAP_NONE)
+ passes = png_set_interlace_handling(png_ptr);
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* The expected output can be deduced from the colormap_processing option. */
+ switch (display->colormap_processing)
+ {
+ case PNG_CMAP_NONE:
+ /* Output must be one channel and one byte per pixel, the output
+ * encoding can be anything.
+ */
+ if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY) &&
+ info_ptr->bit_depth == 8)
+ break;
+
+ goto bad_output;
+
+ case PNG_CMAP_TRANS:
+ case PNG_CMAP_GA:
+ /* Output must be two channels and the 'G' one must be sRGB, the latter
+ * can be checked with an exact number because it should have been set
+ * to this number above!
+ */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ info_ptr->bit_depth == 8 &&
+ png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
+ image->colormap_entries == 256)
+ break;
+
+ goto bad_output;
+
+ case PNG_CMAP_RGB:
+ /* Output must be 8-bit sRGB encoded RGB */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+ info_ptr->bit_depth == 8 &&
+ png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
+ image->colormap_entries == 216)
+ break;
+
+ goto bad_output;
+
+ case PNG_CMAP_RGB_ALPHA:
+ /* Output must be 8-bit sRGB encoded RGBA */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ info_ptr->bit_depth == 8 &&
+ png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
+ image->colormap_entries == 244 /* 216 + 1 + 27 */)
+ break;
+
+ goto bad_output;
+
+ default:
+ bad_output:
+ png_error(png_ptr, "bad color-map processing (internal error)");
+ }
+
+ /* Now read the rows. Do this here if it is possible to read directly into
+ * the output buffer, otherwise allocate a local row buffer of the maximum
+ * size libpng requires and call the relevant processing routine safely.
+ */
+ {
+ png_voidp first_row = display->buffer;
+ ptrdiff_t row_bytes = display->row_stride;
+
+ /* The following expression is designed to work correctly whether it gives
+ * a signed or an unsigned result.
+ */
+ if (row_bytes < 0)
+ {
+ char *ptr = png_voidcast(char*, first_row);
+ ptr += (image->height-1) * (-row_bytes);
+ first_row = png_voidcast(png_voidp, ptr);
+ }
+
+ display->first_row = first_row;
+ display->row_bytes = row_bytes;
+ }
+
+ if (passes == 0)
+ {
+ int result;
+ png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
+
+ display->local_row = row;
+ result = png_safe_execute(image, png_image_read_and_map, display);
+ display->local_row = NULL;
+ png_free(png_ptr, row);
+
+ return result;
+ }
+
+ else
+ {
+ png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
+
+ while (--passes >= 0)
+ {
+ png_uint_32 y = image->height;
+ png_bytep row = png_voidcast(png_bytep, display->first_row);
+
+ for (; y > 0; --y)
+ {
+ png_read_row(png_ptr, row, NULL);
+ row += row_bytes;
+ }
+ }
+
+ return 1;
+ }
+}
+
+/* Just the row reading part of png_image_read. */
+static int
+png_image_read_composite(png_voidp argument)
+{
+ png_image_read_control *display = png_voidcast(png_image_read_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+ int passes;
+
+ switch (png_ptr->interlaced)
+ {
+ case PNG_INTERLACE_NONE:
+ passes = 1;
+ break;
+
+ case PNG_INTERLACE_ADAM7:
+ passes = PNG_INTERLACE_ADAM7_PASSES;
+ break;
+
+ default:
+ png_error(png_ptr, "unknown interlace type");
+ }
+
+ {
+ png_uint_32 height = image->height;
+ png_uint_32 width = image->width;
+ ptrdiff_t step_row = display->row_bytes;
+ unsigned int channels =
+ (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
+ int pass;
+
+ for (pass = 0; pass < passes; ++pass)
+ {
+ unsigned int startx, stepx, stepy;
+ png_uint_32 y;
+
+ if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
+ {
+ /* The row may be empty for a short image: */
+ if (PNG_PASS_COLS(width, pass) == 0)
+ continue;
+
+ startx = PNG_PASS_START_COL(pass) * channels;
+ stepx = PNG_PASS_COL_OFFSET(pass) * channels;
+ y = PNG_PASS_START_ROW(pass);
+ stepy = PNG_PASS_ROW_OFFSET(pass);
+ }
+
+ else
+ {
+ y = 0;
+ startx = 0;
+ stepx = channels;
+ stepy = 1;
+ }
+
+ for (; ylocal_row);
+ png_bytep outrow;
+ png_const_bytep end_row;
+
+ /* Read the row, which is packed: */
+ png_read_row(png_ptr, inrow, NULL);
+
+ outrow = png_voidcast(png_bytep, display->first_row);
+ outrow += y * step_row;
+ end_row = outrow + width * channels;
+
+ /* Now do the composition on each pixel in this row. */
+ outrow += startx;
+ for (; outrow < end_row; outrow += stepx)
+ {
+ png_byte alpha = inrow[channels];
+
+ if (alpha > 0) /* else no change to the output */
+ {
+ unsigned int c;
+
+ for (c=0; cimage;
+ png_structrp png_ptr = image->opaque->png_ptr;
+ png_inforp info_ptr = image->opaque->info_ptr;
+ png_uint_32 height = image->height;
+ png_uint_32 width = image->width;
+ int pass, passes;
+
+ /* Double check the convoluted logic below. We expect to get here with
+ * libpng doing rgb to gray and gamma correction but background processing
+ * left to the png_image_read_background function. The rows libpng produce
+ * might be 8 or 16-bit but should always have two channels; gray plus alpha.
+ */
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
+ png_error(png_ptr, "lost rgb to gray");
+
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0)
+ png_error(png_ptr, "unexpected compose");
+
+ if (png_get_channels(png_ptr, info_ptr) != 2)
+ png_error(png_ptr, "lost/gained channels");
+
+ /* Expect the 8-bit case to always remove the alpha channel */
+ if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 &&
+ (image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ png_error(png_ptr, "unexpected 8-bit transformation");
+
+ switch (png_ptr->interlaced)
+ {
+ case PNG_INTERLACE_NONE:
+ passes = 1;
+ break;
+
+ case PNG_INTERLACE_ADAM7:
+ passes = PNG_INTERLACE_ADAM7_PASSES;
+ break;
+
+ default:
+ png_error(png_ptr, "unknown interlace type");
+ }
+
+ /* Use direct access to info_ptr here because otherwise the simplified API
+ * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is
+ * checking the value after libpng expansions, not the original value in the
+ * PNG.
+ */
+ switch (info_ptr->bit_depth)
+ {
+ case 8:
+ /* 8-bit sRGB gray values with an alpha channel; the alpha channel is
+ * to be removed by composing on a background: either the row if
+ * display->background is NULL or display->background->green if not.
+ * Unlike the code above ALPHA_OPTIMIZED has *not* been done.
+ */
+ {
+ png_bytep first_row = png_voidcast(png_bytep, display->first_row);
+ ptrdiff_t step_row = display->row_bytes;
+
+ for (pass = 0; pass < passes; ++pass)
+ {
+ unsigned int startx, stepx, stepy;
+ png_uint_32 y;
+
+ if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
+ {
+ /* The row may be empty for a short image: */
+ if (PNG_PASS_COLS(width, pass) == 0)
+ continue;
+
+ startx = PNG_PASS_START_COL(pass);
+ stepx = PNG_PASS_COL_OFFSET(pass);
+ y = PNG_PASS_START_ROW(pass);
+ stepy = PNG_PASS_ROW_OFFSET(pass);
+ }
+
+ else
+ {
+ y = 0;
+ startx = 0;
+ stepx = stepy = 1;
+ }
+
+ if (display->background == NULL)
+ {
+ for (; ylocal_row);
+ png_bytep outrow = first_row + y * step_row;
+ png_const_bytep end_row = outrow + width;
+
+ /* Read the row, which is packed: */
+ png_read_row(png_ptr, inrow, NULL);
+
+ /* Now do the composition on each pixel in this row. */
+ outrow += startx;
+ for (; outrow < end_row; outrow += stepx)
+ {
+ png_byte alpha = inrow[1];
+
+ if (alpha > 0) /* else no change to the output */
+ {
+ png_uint_32 component = inrow[0];
+
+ if (alpha < 255) /* else just use component */
+ {
+ /* Since PNG_OPTIMIZED_ALPHA was not set it is
+ * necessary to invert the sRGB transfer
+ * function and multiply the alpha out.
+ */
+ component = png_sRGB_table[component] * alpha;
+ component += png_sRGB_table[outrow[0]] *
+ (255-alpha);
+ component = PNG_sRGB_FROM_LINEAR(component);
+ }
+
+ outrow[0] = (png_byte)component;
+ }
+
+ inrow += 2; /* gray and alpha channel */
+ }
+ }
+ }
+
+ else /* constant background value */
+ {
+ png_byte background8 = display->background->green;
+ png_uint_16 background = png_sRGB_table[background8];
+
+ for (; ylocal_row);
+ png_bytep outrow = first_row + y * step_row;
+ png_const_bytep end_row = outrow + width;
+
+ /* Read the row, which is packed: */
+ png_read_row(png_ptr, inrow, NULL);
+
+ /* Now do the composition on each pixel in this row. */
+ outrow += startx;
+ for (; outrow < end_row; outrow += stepx)
+ {
+ png_byte alpha = inrow[1];
+
+ if (alpha > 0) /* else use background */
+ {
+ png_uint_32 component = inrow[0];
+
+ if (alpha < 255) /* else just use component */
+ {
+ component = png_sRGB_table[component] * alpha;
+ component += background * (255-alpha);
+ component = PNG_sRGB_FROM_LINEAR(component);
+ }
+
+ outrow[0] = (png_byte)component;
+ }
+
+ else
+ outrow[0] = background8;
+
+ inrow += 2; /* gray and alpha channel */
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 16:
+ /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must
+ * still be done and, maybe, the alpha channel removed. This code also
+ * handles the alpha-first option.
+ */
+ {
+ png_uint_16p first_row = png_voidcast(png_uint_16p,
+ display->first_row);
+ /* The division by two is safe because the caller passed in a
+ * stride which was multiplied by 2 (below) to get row_bytes.
+ */
+ ptrdiff_t step_row = display->row_bytes / 2;
+ unsigned int preserve_alpha = (image->format &
+ PNG_FORMAT_FLAG_ALPHA) != 0;
+ unsigned int outchannels = 1U+preserve_alpha;
+ int swap_alpha = 0;
+
+# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
+ if (preserve_alpha != 0 &&
+ (image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ swap_alpha = 1;
+# endif
+
+ for (pass = 0; pass < passes; ++pass)
+ {
+ unsigned int startx, stepx, stepy;
+ png_uint_32 y;
+
+ /* The 'x' start and step are adjusted to output components here.
+ */
+ if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
+ {
+ /* The row may be empty for a short image: */
+ if (PNG_PASS_COLS(width, pass) == 0)
+ continue;
+
+ startx = PNG_PASS_START_COL(pass) * outchannels;
+ stepx = PNG_PASS_COL_OFFSET(pass) * outchannels;
+ y = PNG_PASS_START_ROW(pass);
+ stepy = PNG_PASS_ROW_OFFSET(pass);
+ }
+
+ else
+ {
+ y = 0;
+ startx = 0;
+ stepx = outchannels;
+ stepy = 1;
+ }
+
+ for (; ylocal_row), NULL);
+ inrow = png_voidcast(png_const_uint_16p, display->local_row);
+
+ /* Now do the pre-multiplication on each pixel in this row.
+ */
+ outrow += startx;
+ for (; outrow < end_row; outrow += stepx)
+ {
+ png_uint_32 component = inrow[0];
+ png_uint_16 alpha = inrow[1];
+
+ if (alpha > 0) /* else 0 */
+ {
+ if (alpha < 65535) /* else just use component */
+ {
+ component *= alpha;
+ component += 32767;
+ component /= 65535;
+ }
+ }
+
+ else
+ component = 0;
+
+ outrow[swap_alpha] = (png_uint_16)component;
+ if (preserve_alpha != 0)
+ outrow[1 ^ swap_alpha] = alpha;
+
+ inrow += 2; /* components and alpha channel */
+ }
+ }
+ }
+ }
+ break;
+
+#ifdef __GNUC__
+ default:
+ png_error(png_ptr, "unexpected bit depth");
+#endif
+ }
+
+ return 1;
+}
+
+/* The guts of png_image_finish_read as a png_safe_execute callback. */
+static int
+png_image_read_direct(png_voidp argument)
+{
+ png_image_read_control *display = png_voidcast(png_image_read_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+ png_inforp info_ptr = image->opaque->info_ptr;
+
+ png_uint_32 format = image->format;
+ int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
+ int do_local_compose = 0;
+ int do_local_background = 0; /* to avoid double gamma correction bug */
+ int passes = 0;
+
+ /* Add transforms to ensure the correct output format is produced then check
+ * that the required implementation support is there. Always expand; always
+ * need 8 bits minimum, no palette and expanded tRNS.
+ */
+ png_set_expand(png_ptr);
+
+ /* Now check the format to see if it was modified. */
+ {
+ png_uint_32 base_format = png_image_format(png_ptr) &
+ ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */;
+ png_uint_32 change = format ^ base_format;
+ png_fixed_point output_gamma;
+ int mode; /* alpha mode */
+
+ /* Do this first so that we have a record if rgb to gray is happening. */
+ if ((change & PNG_FORMAT_FLAG_COLOR) != 0)
+ {
+ /* gray<->color transformation required. */
+ if ((format & PNG_FORMAT_FLAG_COLOR) != 0)
+ png_set_gray_to_rgb(png_ptr);
+
+ else
+ {
+ /* libpng can't do both rgb to gray and
+ * background/pre-multiplication if there is also significant gamma
+ * correction, because both operations require linear colors and
+ * the code only supports one transform doing the gamma correction.
+ * Handle this by doing the pre-multiplication or background
+ * operation in this code, if necessary.
+ *
+ * TODO: fix this by rewriting pngrtran.c (!)
+ *
+ * For the moment (given that fixing this in pngrtran.c is an
+ * enormous change) 'do_local_background' is used to indicate that
+ * the problem exists.
+ */
+ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ do_local_background = 1/*maybe*/;
+
+ png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE,
+ PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
+ }
+
+ change &= ~PNG_FORMAT_FLAG_COLOR;
+ }
+
+ /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.
+ */
+ {
+ png_fixed_point input_gamma_default;
+
+ if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 &&
+ (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
+ input_gamma_default = PNG_GAMMA_LINEAR;
+ else
+ input_gamma_default = PNG_DEFAULT_sRGB;
+
+ /* Call png_set_alpha_mode to set the default for the input gamma; the
+ * output gamma is set by a second call below.
+ */
+ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default);
+ }
+
+ if (linear != 0)
+ {
+ /* If there *is* an alpha channel in the input it must be multiplied
+ * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG.
+ */
+ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ mode = PNG_ALPHA_STANDARD; /* associated alpha */
+
+ else
+ mode = PNG_ALPHA_PNG;
+
+ output_gamma = PNG_GAMMA_LINEAR;
+ }
+
+ else
+ {
+ mode = PNG_ALPHA_PNG;
+ output_gamma = PNG_DEFAULT_sRGB;
+ }
+
+ if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)
+ {
+ mode = PNG_ALPHA_OPTIMIZED;
+ change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
+ /* If 'do_local_background' is set check for the presence of gamma
+ * correction; this is part of the work-round for the libpng bug
+ * described above.
+ *
+ * TODO: fix libpng and remove this.
+ */
+ if (do_local_background != 0)
+ {
+ png_fixed_point gtest;
+
+ /* This is 'png_gamma_threshold' from pngrtran.c; the test used for
+ * gamma correction, the screen gamma hasn't been set on png_struct
+ * 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)
+ do_local_background = 0;
+
+ else if (mode == PNG_ALPHA_STANDARD)
+ {
+ do_local_background = 2/*required*/;
+ mode = PNG_ALPHA_PNG; /* prevent libpng doing it */
+ }
+
+ /* else leave as 1 for the checks below */
+ }
+
+ /* If the bit-depth changes then handle that here. */
+ if ((change & PNG_FORMAT_FLAG_LINEAR) != 0)
+ {
+ if (linear != 0 /*16-bit output*/)
+ png_set_expand_16(png_ptr);
+
+ else /* 8-bit output */
+ png_set_scale_16(png_ptr);
+
+ change &= ~PNG_FORMAT_FLAG_LINEAR;
+ }
+
+ /* Now the background/alpha channel changes. */
+ if ((change & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ /* Removing an alpha channel requires composition for the 8-bit
+ * formats; for the 16-bit it is already done, above, by the
+ * pre-multiplication and the channel just needs to be stripped.
+ */
+ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ /* If RGB->gray is happening the alpha channel must be left and the
+ * operation completed locally.
+ *
+ * TODO: fix libpng and remove this.
+ */
+ if (do_local_background != 0)
+ do_local_background = 2/*required*/;
+
+ /* 16-bit output: just remove the channel */
+ else if (linear != 0) /* compose on black (well, pre-multiply) */
+ png_set_strip_alpha(png_ptr);
+
+ /* 8-bit output: do an appropriate compose */
+ else if (display->background != NULL)
+ {
+ png_color_16 c;
+
+ c.index = 0; /*unused*/
+ c.red = display->background->red;
+ c.green = display->background->green;
+ c.blue = display->background->blue;
+ c.gray = display->background->green;
+
+ /* This is always an 8-bit sRGB value, using the 'green' channel
+ * for gray is much better than calculating the luminance here;
+ * we can get off-by-one errors in that calculation relative to
+ * the app expectations and that will show up in transparent
+ * pixels.
+ */
+ png_set_background_fixed(png_ptr, &c,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
+ 0/*gamma: not used*/);
+ }
+
+ else /* compose on row: implemented below. */
+ {
+ do_local_compose = 1;
+ /* This leaves the alpha channel in the output, so it has to be
+ * removed by the code below. Set the encoding to the 'OPTIMIZE'
+ * one so the code only has to hack on the pixels that require
+ * composition.
+ */
+ mode = PNG_ALPHA_OPTIMIZED;
+ }
+ }
+
+ else /* output needs an alpha channel */
+ {
+ /* This is tricky because it happens before the swap operation has
+ * been accomplished; however, the swap does *not* swap the added
+ * alpha channel (weird API), so it must be added in the correct
+ * place.
+ */
+ png_uint_32 filler; /* opaque filler */
+ int where;
+
+ if (linear != 0)
+ filler = 65535;
+
+ else
+ filler = 255;
+
+#ifdef PNG_FORMAT_AFIRST_SUPPORTED
+ if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ {
+ where = PNG_FILLER_BEFORE;
+ change &= ~PNG_FORMAT_FLAG_AFIRST;
+ }
+
+ else
+#endif
+ where = PNG_FILLER_AFTER;
+
+ png_set_add_alpha(png_ptr, filler, where);
+ }
+
+ /* This stops the (irrelevant) call to swap_alpha below. */
+ change &= ~PNG_FORMAT_FLAG_ALPHA;
+ }
+
+ /* Now set the alpha mode correctly; this is always done, even if there is
+ * no alpha channel in either the input or the output because it correctly
+ * sets the output gamma.
+ */
+ png_set_alpha_mode_fixed(png_ptr, mode, output_gamma);
+
+# ifdef PNG_FORMAT_BGR_SUPPORTED
+ if ((change & PNG_FORMAT_FLAG_BGR) != 0)
+ {
+ /* Check only the output format; PNG is never BGR; don't do this if
+ * the output is gray, but fix up the 'format' value in that case.
+ */
+ if ((format & PNG_FORMAT_FLAG_COLOR) != 0)
+ png_set_bgr(png_ptr);
+
+ else
+ format &= ~PNG_FORMAT_FLAG_BGR;
+
+ change &= ~PNG_FORMAT_FLAG_BGR;
+ }
+# endif
+
+# ifdef PNG_FORMAT_AFIRST_SUPPORTED
+ if ((change & PNG_FORMAT_FLAG_AFIRST) != 0)
+ {
+ /* Only relevant if there is an alpha channel - it's particularly
+ * important to handle this correctly because do_local_compose may
+ * be set above and then libpng will keep the alpha channel for this
+ * code to remove.
+ */
+ if ((format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ /* Disable this if doing a local background,
+ * TODO: remove this when local background is no longer required.
+ */
+ if (do_local_background != 2)
+ png_set_swap_alpha(png_ptr);
+ }
+
+ else
+ format &= ~PNG_FORMAT_FLAG_AFIRST;
+
+ change &= ~PNG_FORMAT_FLAG_AFIRST;
+ }
+# endif
+
+ /* If the *output* is 16-bit then we need to check for a byte-swap on this
+ * architecture.
+ */
+ if (linear != 0)
+ {
+ png_uint_16 le = 0x0001;
+
+ if ((*(png_const_bytep) & le) != 0)
+ png_set_swap(png_ptr);
+ }
+
+ /* If change is not now 0 some transformation is missing - error out. */
+ if (change != 0)
+ png_error(png_ptr, "png_read_image: unsupported transformation");
+ }
+
+ PNG_SKIP_CHUNKS(png_ptr);
+
+ /* Update the 'info' structure and make sure the result is as required; first
+ * make sure to turn on the interlace handling if it will be required
+ * (because it can't be turned on *after* the call to png_read_update_info!)
+ *
+ * TODO: remove the do_local_background fixup below.
+ */
+ if (do_local_compose == 0 && do_local_background != 2)
+ passes = png_set_interlace_handling(png_ptr);
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ {
+ png_uint_32 info_format = 0;
+
+ if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+ info_format |= PNG_FORMAT_FLAG_COLOR;
+
+ if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
+ {
+ /* do_local_compose removes this channel below. */
+ if (do_local_compose == 0)
+ {
+ /* do_local_background does the same if required. */
+ if (do_local_background != 2 ||
+ (format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ info_format |= PNG_FORMAT_FLAG_ALPHA;
+ }
+ }
+
+ else if (do_local_compose != 0) /* internal error */
+ png_error(png_ptr, "png_image_read: alpha channel lost");
+
+ if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) {
+ info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
+ if (info_ptr->bit_depth == 16)
+ info_format |= PNG_FORMAT_FLAG_LINEAR;
+
+#ifdef PNG_FORMAT_BGR_SUPPORTED
+ if ((png_ptr->transformations & PNG_BGR) != 0)
+ info_format |= PNG_FORMAT_FLAG_BGR;
+#endif
+
+#ifdef PNG_FORMAT_AFIRST_SUPPORTED
+ if (do_local_background == 2)
+ {
+ if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ info_format |= PNG_FORMAT_FLAG_AFIRST;
+ }
+
+ if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 ||
+ ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 &&
+ (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0))
+ {
+ if (do_local_background == 2)
+ png_error(png_ptr, "unexpected alpha swap transformation");
+
+ info_format |= PNG_FORMAT_FLAG_AFIRST;
+ }
+# endif
+
+ /* This is actually an internal error. */
+ if (info_format != format)
+ png_error(png_ptr, "png_read_image: invalid transformations");
+ }
+
+ /* Now read the rows. If do_local_compose is set then it is necessary to use
+ * a local row buffer. The output will be GA, RGBA or BGRA and must be
+ * converted to G, RGB or BGR as appropriate. The 'local_row' member of the
+ * display acts as a flag.
+ */
+ {
+ png_voidp first_row = display->buffer;
+ ptrdiff_t row_bytes = display->row_stride;
+
+ if (linear != 0)
+ row_bytes *= 2;
+
+ /* The following expression is designed to work correctly whether it gives
+ * a signed or an unsigned result.
+ */
+ if (row_bytes < 0)
+ {
+ char *ptr = png_voidcast(char*, first_row);
+ ptr += (image->height-1) * (-row_bytes);
+ first_row = png_voidcast(png_voidp, ptr);
+ }
+
+ display->first_row = first_row;
+ display->row_bytes = row_bytes;
+ }
+
+ if (do_local_compose != 0)
+ {
+ int result;
+ png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
+
+ display->local_row = row;
+ result = png_safe_execute(image, png_image_read_composite, display);
+ display->local_row = NULL;
+ png_free(png_ptr, row);
+
+ return result;
+ }
+
+ else if (do_local_background == 2)
+ {
+ int result;
+ png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
+
+ display->local_row = row;
+ result = png_safe_execute(image, png_image_read_background, display);
+ display->local_row = NULL;
+ png_free(png_ptr, row);
+
+ return result;
+ }
+
+ else
+ {
+ png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
+
+ while (--passes >= 0)
+ {
+ png_uint_32 y = image->height;
+ png_bytep row = png_voidcast(png_bytep, display->first_row);
+
+ for (; y > 0; --y)
+ {
+ png_read_row(png_ptr, row, NULL);
+ row += row_bytes;
+ }
+ }
+
+ return 1;
+ }
+}
+
+int PNGAPI
+png_image_finish_read(png_imagep image, png_const_colorp background,
+ void *buffer, png_int_32 row_stride, void *colormap)
+{
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ /* Check for row_stride overflow. This check is not performed on the
+ * original PNG format because it may not occur in the output PNG format
+ * and libpng deals with the issues of reading the original.
+ */
+ unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
+
+ /* The following checks just the 'row_stride' calculation to ensure it
+ * fits in a signed 32-bit value. Because channels/components can be
+ * either 1 or 2 bytes in size the length of a row can still overflow 32
+ * bits; this is just to verify that the 'row_stride' argument can be
+ * represented.
+ */
+ if (image->width <= 0x7fffffffU/channels) /* no overflow */
+ {
+ png_uint_32 check;
+ png_uint_32 png_row_stride = image->width * channels;
+
+ if (row_stride == 0)
+ row_stride = (png_int_32)/*SAFE*/png_row_stride;
+
+ if (row_stride < 0)
+ check = (png_uint_32)(-row_stride);
+
+ else
+ check = (png_uint_32)row_stride;
+
+ /* This verifies 'check', the absolute value of the actual stride
+ * passed in and detects overflow in the application calculation (i.e.
+ * if the app did actually pass in a non-zero 'row_stride'.
+ */
+ if (image->opaque != NULL && buffer != NULL && check >= png_row_stride)
+ {
+ /* Now check for overflow of the image buffer calculation; this
+ * limits the whole image size to 32 bits for API compatibility with
+ * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
+ *
+ * The PNG_IMAGE_BUFFER_SIZE macro is:
+ *
+ * (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride))
+ *
+ * And the component size is always 1 or 2, so make sure that the
+ * number of *bytes* that the application is saying are available
+ * does actually fit into a 32-bit number.
+ *
+ * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE
+ * will be changed to use png_alloc_size_t; bigger images can be
+ * accommodated on 64-bit systems.
+ */
+ if (image->height <=
+ 0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check)
+ {
+ if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||
+ (image->colormap_entries > 0 && colormap != NULL))
+ {
+ int result;
+ png_image_read_control display;
+
+ memset(&display, 0, (sizeof display));
+ display.image = image;
+ display.buffer = buffer;
+ display.row_stride = row_stride;
+ display.colormap = colormap;
+ display.background = background;
+ display.local_row = NULL;
+
+ /* Choose the correct 'end' routine; for the color-map case
+ * all the setup has already been done.
+ */
+ if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
+ result =
+ png_safe_execute(image,
+ png_image_read_colormap, &display) &&
+ png_safe_execute(image,
+ png_image_read_colormapped, &display);
+
+ else
+ result =
+ png_safe_execute(image,
+ png_image_read_direct, &display);
+
+ png_image_free(image);
+ return result;
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_finish_read[color-map]: no color-map");
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_finish_read: image too large");
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_finish_read: invalid argument");
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_finish_read: row_stride too large");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_finish_read: damaged PNG_IMAGE_VERSION");
+
+ return 0;
+}
+
+#endif /* SIMPLIFIED_READ */
+#endif /* READ */
diff --git a/PDF/src/pngrio.c b/PDF/src/pngrio.c
index 7d2522f1f..794635810 100644
--- a/PDF/src/pngrio.c
+++ b/PDF/src/pngrio.c
@@ -1,11 +1,14 @@
/* pngrio.c - functions for data input
*
- * Last changed in libpng 1.2.13 November 13, 2006
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2006 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* This file provides a location for all input. Users who need
* special handling are expected to write a function that has the same
@@ -15,153 +18,103 @@
* libpng use it at run time with png_set_read_fn(...).
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
-#if defined(PNG_READ_SUPPORTED)
+#ifdef PNG_READ_SUPPORTED
/* Read the data from whatever input you are using. The default routine
- reads from a file pointer. Note that this routine sometimes gets called
- with very small lengths, so you should implement some kind of simple
- buffering if you are using unbuffered reads. This should never be asked
- to read more then 64K on a 16 bit machine. */
+ * reads from a file pointer. Note that this routine sometimes gets called
+ * with very small lengths, so you should implement some kind of simple
+ * buffering if you are using unbuffered reads. This should never be asked
+ * to read more than 64K on a 16-bit machine.
+ */
void /* PRIVATE */
-png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+png_read_data(png_structrp png_ptr, png_bytep data, size_t length)
{
- png_debug1(4,"reading %d bytes\n", (int)length);
+ png_debug1(4, "reading %d bytes", (int)length);
+
if (png_ptr->read_data_fn != NULL)
(*(png_ptr->read_data_fn))(png_ptr, data, length);
+
else
png_error(png_ptr, "Call to NULL read function");
}
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_STDIO_SUPPORTED
/* This is the function that does the actual reading of data. If you are
- not reading from a standard C stream, you should create a replacement
- read_data function and use it at run time with png_set_read_fn(), rather
- than changing the library. */
-#ifndef USE_FAR_KEYWORD
-void PNGAPI
-png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+ * not reading from a standard C stream, you should create a replacement
+ * read_data function and use it at run time with png_set_read_fn(), rather
+ * than changing the library.
+ */
+void PNGCBAPI
+png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
{
- png_size_t check;
+ size_t check;
- if(png_ptr == NULL) return;
- /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ if (png_ptr == NULL)
+ return;
+
+ /* 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.
*/
-#if defined(_WIN32_WCE)
- if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
- check = 0;
-#else
- check = (png_size_t)fread(data, (png_size_t)1, length,
- (png_FILE_p)png_ptr->io_ptr);
-#endif
+ check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
if (check != length)
png_error(png_ptr, "Read Error");
}
-#else
-/* this is the model-independent version. Since the standard I/O library
- can't handle far buffers in the medium and small models, we have to copy
- the data.
-*/
-
-#define NEAR_BUF_SIZE 1024
-#define MIN(a,b) (a <= b ? a : b)
-
-static void PNGAPI
-png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
-{
- int check;
- png_byte *n_data;
- png_FILE_p io_ptr;
-
- if(png_ptr == NULL) return;
- /* Check if data really is near. If so, use usual code. */
- n_data = (png_byte *)CVT_PTR_NOCHECK(data);
- io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
- if ((png_bytep)n_data == data)
- {
-#if defined(_WIN32_WCE)
- if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
- check = 0;
-#else
- check = fread(n_data, 1, length, io_ptr);
-#endif
- }
- else
- {
- png_byte buf[NEAR_BUF_SIZE];
- png_size_t read, remaining, err;
- check = 0;
- remaining = length;
- do
- {
- read = MIN(NEAR_BUF_SIZE, remaining);
-#if defined(_WIN32_WCE)
- if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) )
- err = 0;
-#else
- err = fread(buf, (png_size_t)1, read, io_ptr);
-#endif
- png_memcpy(data, buf, read); /* copy far buffer to near buffer */
- if(err != read)
- break;
- else
- check += err;
- data += read;
- remaining -= read;
- }
- while (remaining != 0);
- }
- if ((png_uint_32)check != (png_uint_32)length)
- png_error(png_ptr, "read Error");
-}
-#endif
#endif
/* This function allows the application to supply a new input function
- for libpng if standard C streams aren't being used.
-
- This function takes as its arguments:
- png_ptr - pointer to a png input data structure
- io_ptr - pointer to user supplied structure containing info about
- the input functions. May be NULL.
- read_data_fn - pointer to a new input function that takes as its
- arguments a pointer to a png_struct, a pointer to
- a location where input data can be stored, and a 32-bit
- unsigned int that is the number of bytes to be read.
- To exit and output any fatal error messages the new write
- function should call png_error(png_ptr, "Error msg"). */
+ * for libpng if standard C streams aren't being used.
+ *
+ * This function takes as its arguments:
+ *
+ * png_ptr - pointer to a png input data structure
+ *
+ * io_ptr - pointer to user supplied structure containing info about
+ * the input functions. May be NULL.
+ *
+ * read_data_fn - pointer to a new input function that takes as its
+ * arguments a pointer to a png_struct, a pointer to
+ * a location where input data can be stored, and a 32-bit
+ * unsigned int that is the number of bytes to be read.
+ * To exit and output any fatal error messages the new write
+ * function should call png_error(png_ptr, "Error msg").
+ * May be NULL, in which case libpng's default function will
+ * be used.
+ */
void PNGAPI
-png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
- png_rw_ptr read_data_fn)
+png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
png_ptr->io_ptr = io_ptr;
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_STDIO_SUPPORTED
if (read_data_fn != NULL)
png_ptr->read_data_fn = read_data_fn;
+
else
png_ptr->read_data_fn = png_default_read_data;
#else
png_ptr->read_data_fn = read_data_fn;
#endif
+#ifdef PNG_WRITE_SUPPORTED
/* It is an error to write to a read device */
if (png_ptr->write_data_fn != NULL)
{
png_ptr->write_data_fn = NULL;
png_warning(png_ptr,
- "It's an error to set both read_data_fn and write_data_fn in the ");
- png_warning(png_ptr,
- "same structure. Resetting write_data_fn to NULL.");
+ "Can't set both read_data_fn and write_data_fn in the"
+ " same structure");
}
+#endif
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->output_flush_fn = NULL;
#endif
}
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ */
diff --git a/PDF/src/pngrtran.c b/PDF/src/pngrtran.c
index 96ca4a146..1526123e0 100644
--- a/PDF/src/pngrtran.c
+++ b/PDF/src/pngrtran.c
@@ -1,11 +1,14 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.2.22 [October 13, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * 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 functions optionally called by an application
* in order to tell libpng how to handle data when reading a PNG.
@@ -13,58 +16,83 @@
* in pngtrans.c.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
-#if defined(PNG_READ_SUPPORTED)
+#ifdef PNG_ARM_NEON_IMPLEMENTATION
+# if PNG_ARM_NEON_IMPLEMENTATION == 1
+# define PNG_ARM_NEON_INTRINSICS_AVAILABLE
+# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
+# include
+# else
+# include
+# endif
+# endif
+#endif
+
+#ifdef PNG_READ_SUPPORTED
/* Set the action on getting a CRC error for an ancillary or critical chunk. */
void PNGAPI
-png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
+png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
{
- png_debug(1, "in png_set_crc_action\n");
+ png_debug(1, "in png_set_crc_action");
+
+ if (png_ptr == NULL)
+ return;
+
/* Tell libpng how we react to CRC errors in critical chunks */
- if(png_ptr == NULL) return;
switch (crit_action)
{
- case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ case PNG_CRC_NO_CHANGE: /* Leave setting as is */
break;
- case PNG_CRC_WARN_USE: /* warn/use data */
+
+ case PNG_CRC_WARN_USE: /* Warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
break;
- case PNG_CRC_QUIET_USE: /* quiet/use data */
+
+ case PNG_CRC_QUIET_USE: /* Quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
PNG_FLAG_CRC_CRITICAL_IGNORE;
break;
- case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
- png_warning(png_ptr, "Can't discard critical data on CRC error.");
- case PNG_CRC_ERROR_QUIT: /* error/quit */
+
+ case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
+ png_warning(png_ptr,
+ "Can't discard critical data on CRC error");
+ /* FALLTHROUGH */
+ case PNG_CRC_ERROR_QUIT: /* Error/quit */
+
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
break;
}
+ /* Tell libpng how we react to CRC errors in ancillary chunks */
switch (ancil_action)
{
- case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ case PNG_CRC_NO_CHANGE: /* Leave setting as is */
break;
- case PNG_CRC_WARN_USE: /* warn/use data */
+
+ case PNG_CRC_WARN_USE: /* Warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
break;
- case PNG_CRC_QUIET_USE: /* quiet/use data */
+
+ case PNG_CRC_QUIET_USE: /* Quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
- case PNG_CRC_ERROR_QUIT: /* error/quit */
+
+ case PNG_CRC_ERROR_QUIT: /* Error/quit */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
- case PNG_CRC_WARN_DISCARD: /* warn/discard data */
+
+ case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
+
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
@@ -72,88 +100,349 @@ png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
}
}
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
- defined(PNG_FLOATING_POINT_SUPPORTED)
-/* handle alpha and tRNS via a background color */
-void PNGAPI
-png_set_background(png_structp png_ptr,
- png_color_16p background_color, int background_gamma_code,
- int need_expand, double background_gamma)
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+/* Is it OK to set a transformation now? Only if png_start_read_image or
+ * png_read_update_info have not been called. It is not necessary for the IHDR
+ * to have been read in all cases; the need_IHDR parameter allows for this
+ * check too.
+ */
+static int
+png_rtran_ok(png_structrp png_ptr, int need_IHDR)
{
- png_debug(1, "in png_set_background\n");
- if(png_ptr == NULL) return;
+ if (png_ptr != NULL)
+ {
+ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)
+ png_app_error(png_ptr,
+ "invalid after png_start_read_image or png_read_update_info");
+
+ else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_app_error(png_ptr, "invalid before the PNG header has been read");
+
+ else
+ {
+ /* Turn on failure to initialize correctly for all transforms. */
+ png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
+
+ return 1; /* Ok */
+ }
+ }
+
+ return 0; /* no png_error possible! */
+}
+#endif
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+/* Handle alpha and tRNS via a background color */
+void PNGFAPI
+png_set_background_fixed(png_structrp png_ptr,
+ png_const_color_16p background_color, int background_gamma_code,
+ int need_expand, png_fixed_point background_gamma)
+{
+ png_debug(1, "in png_set_background_fixed");
+
+ if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL)
+ return;
+
if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
{
png_warning(png_ptr, "Application must supply a known background gamma");
return;
}
- png_ptr->transformations |= PNG_BACKGROUND;
- png_memcpy(&(png_ptr->background), background_color,
- png_sizeof(png_color_16));
- png_ptr->background_gamma = (float)background_gamma;
+ png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
+ png_ptr->background = *background_color;
+ png_ptr->background_gamma = background_gamma;
png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
- png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+ if (need_expand != 0)
+ png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
+ else
+ png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_background(png_structrp png_ptr,
+ png_const_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma)
+{
+ png_set_background_fixed(png_ptr, background_color, background_gamma_code,
+ need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
+}
+# endif /* FLOATING_POINT */
+#endif /* READ_BACKGROUND */
+
+/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the
+ * one that pngrtran does first (scale) happens. This is necessary to allow the
+ * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
+ */
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+void PNGAPI
+png_set_scale_16(png_structrp png_ptr)
+{
+ png_debug(1, "in png_set_scale_16");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
+ png_ptr->transformations |= PNG_SCALE_16_TO_8;
}
#endif
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
-/* strip 16 bit depth files to 8 bit depth */
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+/* Chop 16-bit depth files to 8-bit depth */
void PNGAPI
-png_set_strip_16(png_structp png_ptr)
+png_set_strip_16(png_structrp png_ptr)
{
- png_debug(1, "in png_set_strip_16\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_strip_16");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
png_ptr->transformations |= PNG_16_TO_8;
}
#endif
-#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
void PNGAPI
-png_set_strip_alpha(png_structp png_ptr)
+png_set_strip_alpha(png_structrp png_ptr)
{
- png_debug(1, "in png_set_strip_alpha\n");
- if(png_ptr == NULL) return;
- png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
+ png_debug(1, "in png_set_strip_alpha");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
+ png_ptr->transformations |= PNG_STRIP_ALPHA;
}
#endif
-#if defined(PNG_READ_DITHER_SUPPORTED)
-/* Dither file to 8 bit. Supply a palette, the current number
+#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
+static png_fixed_point
+translate_gamma_flags(png_structrp png_ptr, 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
+ * value is from Apple documentation - a working Mac system is needed to
+ * discover the value!
+ */
+ 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
+ output_gamma = PNG_GAMMA_sRGB_INVERSE;
+ }
+
+ else if (output_gamma == PNG_GAMMA_MAC_18 ||
+ output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
+ {
+ if (is_screen != 0)
+ output_gamma = PNG_GAMMA_MAC_OLD;
+ else
+ output_gamma = PNG_GAMMA_MAC_INVERSE;
+ }
+
+ return output_gamma;
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+static png_fixed_point
+convert_gamma_value(png_structrp png_ptr, double output_gamma)
+{
+ /* The following silently ignores cases where fixed point (times 100,000)
+ * gamma values are passed to the floating point API. This is safe and it
+ * means the fixed point constants work just fine with the floating point
+ * API. The alternative would just lead to undetected errors and spurious
+ * bug reports. Negative values fail inside the _fixed API unless they
+ * correspond to the flag values.
+ */
+ if (output_gamma > 0 && output_gamma < 128)
+ output_gamma *= PNG_FP_1;
+
+ /* This preserves -1 and -2 exactly: */
+ output_gamma = floor(output_gamma + .5);
+
+ if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)
+ png_fixed_error(png_ptr, "gamma value");
+
+ return (png_fixed_point)output_gamma;
+}
+# endif
+#endif /* READ_ALPHA_MODE || READ_GAMMA */
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+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;
+
+ 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");
+
+ /* The default file gamma is the inverse of the output gamma; the output
+ * gamma may be changed below so get the file value first:
+ */
+ file_gamma = png_reciprocal(output_gamma);
+
+ /* There are really 8 possibilities here, composed of any combination
+ * of:
+ *
+ * premultiply the color channels
+ * do not encode non-opaque pixels
+ * encode the alpha as well as the color channels
+ *
+ * The differences disappear if the input/output ('screen') gamma is 1.0,
+ * because then the encoding is a no-op and there is only the choice of
+ * premultiplying the color channels or not.
+ *
+ * png_set_alpha_mode and png_set_background interact because both use
+ * png_compose to do the work. Calling both is only useful when
+ * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along
+ * with a default gamma value. Otherwise PNG_COMPOSE must not be set.
+ */
+ switch (mode)
+ {
+ case PNG_ALPHA_PNG: /* default: png standard */
+ /* No compose, but it may be set by png_set_background! */
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+ break;
+
+ case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
+ compose = 1;
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+ /* The output is linear: */
+ output_gamma = PNG_FP_1;
+ break;
+
+ case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */
+ compose = 1;
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;
+ /* output_gamma records the encoding of opaque pixels! */
+ break;
+
+ case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */
+ compose = 1;
+ png_ptr->transformations |= PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+ break;
+
+ default:
+ 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: */
+ png_ptr->screen_gamma = output_gamma;
+
+ /* Finally, if pre-multiplying, set the background fields to achieve the
+ * desired result.
+ */
+ if (compose != 0)
+ {
+ /* 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_type = PNG_BACKGROUND_GAMMA_FILE;
+ png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
+
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0)
+ png_error(png_ptr,
+ "conflicting calls to set alpha mode and background");
+
+ png_ptr->transformations |= PNG_COMPOSE;
+ }
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
+{
+ png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
+ output_gamma));
+}
+# endif
+#endif
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+/* Dither file to 8-bit. Supply a palette, the current number
* of elements in the palette, the maximum number of elements
* allowed, and a histogram if possible. If the current number
- * of colors is greater then the maximum number, the palette will be
- * modified to fit in the maximum number. "full_dither" indicates
- * whether we need a dithering cube set up for RGB images, or if we
+ * of colors is greater than the maximum number, the palette will be
+ * modified to fit in the maximum number. "full_quantize" indicates
+ * whether we need a quantizing cube set up for RGB images, or if we
* simply are reducing the number of colors in a paletted image.
*/
typedef struct png_dsort_struct
{
- struct png_dsort_struct FAR * next;
+ struct png_dsort_struct * next;
png_byte left;
png_byte right;
} png_dsort;
-typedef png_dsort FAR * png_dsortp;
-typedef png_dsort FAR * FAR * png_dsortpp;
+typedef png_dsort * png_dsortp;
+typedef png_dsort * * png_dsortpp;
void PNGAPI
-png_set_dither(png_structp png_ptr, png_colorp palette,
- int num_palette, int maximum_colors, png_uint_16p histogram,
- int full_dither)
+png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ int num_palette, int maximum_colors, png_const_uint_16p histogram,
+ int full_quantize)
{
- png_debug(1, "in png_set_dither\n");
- if(png_ptr == NULL) return;
- png_ptr->transformations |= PNG_DITHER;
+ png_debug(1, "in png_set_quantize");
- if (!full_dither)
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
+ png_ptr->transformations |= PNG_QUANTIZE;
+
+ if (full_quantize == 0)
{
int i;
- png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
+ (png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
- png_ptr->dither_index[i] = (png_byte)i;
+ png_ptr->quantize_index[i] = (png_byte)i;
}
if (num_palette > maximum_colors)
@@ -161,61 +450,66 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
if (histogram != NULL)
{
/* This is easy enough, just throw out the least used colors.
- Perhaps not the best solution, but good enough. */
+ * Perhaps not the best solution, but good enough.
+ */
int i;
- /* initialize an array to sort colors */
- png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ /* Initialize an array to sort colors */
+ png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
+ (png_alloc_size_t)num_palette);
- /* initialize the dither_sort array */
+ /* Initialize the quantize_sort array */
for (i = 0; i < num_palette; i++)
- png_ptr->dither_sort[i] = (png_byte)i;
+ png_ptr->quantize_sort[i] = (png_byte)i;
/* Find the least used palette entries by starting a
- bubble sort, and running it until we have sorted
- out enough colors. Note that we don't care about
- sorting all the colors, just finding which are
- least used. */
+ * bubble sort, and running it until we have sorted
+ * out enough colors. Note that we don't care about
+ * sorting all the colors, just finding which are
+ * least used.
+ */
for (i = num_palette - 1; i >= maximum_colors; i--)
{
- int done; /* to stop early if the list is pre-sorted */
+ int done; /* To stop early if the list is pre-sorted */
int j;
done = 1;
for (j = 0; j < i; j++)
{
- if (histogram[png_ptr->dither_sort[j]]
- < histogram[png_ptr->dither_sort[j + 1]])
+ if (histogram[png_ptr->quantize_sort[j]]
+ < histogram[png_ptr->quantize_sort[j + 1]])
{
png_byte t;
- t = png_ptr->dither_sort[j];
- png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
- png_ptr->dither_sort[j + 1] = t;
+ t = png_ptr->quantize_sort[j];
+ png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
+ png_ptr->quantize_sort[j + 1] = t;
done = 0;
}
}
- if (done)
+
+ if (done != 0)
break;
}
- /* swap the palette around, and set up a table, if necessary */
- if (full_dither)
+ /* Swap the palette around, and set up a table, if necessary */
+ if (full_quantize != 0)
{
int j = num_palette;
- /* put all the useful colors within the max, but don't
- move the others */
+ /* Put all the useful colors within the max, but don't
+ * move the others.
+ */
for (i = 0; i < maximum_colors; i++)
{
- if ((int)png_ptr->dither_sort[i] >= maximum_colors)
+ if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
{
do
j--;
- while ((int)png_ptr->dither_sort[j] >= maximum_colors);
+ while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
+
palette[i] = palette[j];
}
}
@@ -224,37 +518,38 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
{
int j = num_palette;
- /* move all the used colors inside the max limit, and
- develop a translation table */
+ /* Move all the used colors inside the max limit, and
+ * develop a translation table.
+ */
for (i = 0; i < maximum_colors; i++)
{
- /* only move the colors we need to */
- if ((int)png_ptr->dither_sort[i] >= maximum_colors)
+ /* Only move the colors we need to */
+ if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
{
png_color tmp_color;
do
j--;
- while ((int)png_ptr->dither_sort[j] >= maximum_colors);
+ while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
tmp_color = palette[j];
palette[j] = palette[i];
palette[i] = tmp_color;
- /* indicate where the color went */
- png_ptr->dither_index[j] = (png_byte)i;
- png_ptr->dither_index[i] = (png_byte)j;
+ /* Indicate where the color went */
+ png_ptr->quantize_index[j] = (png_byte)i;
+ png_ptr->quantize_index[i] = (png_byte)j;
}
}
- /* find closest color for those colors we are not using */
+ /* Find closest color for those colors we are not using */
for (i = 0; i < num_palette; i++)
{
- if ((int)png_ptr->dither_index[i] >= maximum_colors)
+ if ((int)png_ptr->quantize_index[i] >= maximum_colors)
{
int min_d, k, min_k, d_index;
- /* find the closest color to one we threw out */
- d_index = png_ptr->dither_index[i];
+ /* Find the closest color to one we threw out */
+ d_index = png_ptr->quantize_index[i];
min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
for (k = 1, min_k = 0; k < maximum_colors; k++)
{
@@ -268,61 +563,58 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
min_k = k;
}
}
- /* point to closest color */
- png_ptr->dither_index[i] = (png_byte)min_k;
+ /* Point to closest color */
+ png_ptr->quantize_index[i] = (png_byte)min_k;
}
}
}
- png_free(png_ptr, png_ptr->dither_sort);
- png_ptr->dither_sort=NULL;
+ png_free(png_ptr, png_ptr->quantize_sort);
+ png_ptr->quantize_sort = NULL;
}
else
{
/* This is much harder to do simply (and quickly). Perhaps
- we need to go through a median cut routine, but those
- don't always behave themselves with only a few colors
- as input. So we will just find the closest two colors,
- and throw out one of them (chosen somewhat randomly).
- [We don't understand this at all, so if someone wants to
- work on improving it, be our guest - AED, GRP]
- */
+ * we need to go through a median cut routine, but those
+ * don't always behave themselves with only a few colors
+ * as input. So we will just find the closest two colors,
+ * and throw out one of them (chosen somewhat randomly).
+ * [We don't understand this at all, so if someone wants to
+ * work on improving it, be our guest - AED, GRP]
+ */
int i;
int max_d;
int num_new_palette;
png_dsortp t;
png_dsortpp hash;
- t=NULL;
+ t = NULL;
- /* initialize palette index arrays */
+ /* Initialize palette index arrays */
png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ (png_alloc_size_t)num_palette);
png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ (png_alloc_size_t)num_palette);
- /* initialize the sort array */
+ /* Initialize the sort array */
for (i = 0; i < num_palette; i++)
{
png_ptr->index_to_palette[i] = (png_byte)i;
png_ptr->palette_to_index[i] = (png_byte)i;
}
- hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
- png_sizeof (png_dsortp)));
- for (i = 0; i < 769; i++)
- hash[i] = NULL;
-/* png_memset(hash, 0, 769 * png_sizeof (png_dsortp)); */
+ hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *
+ (sizeof (png_dsortp))));
num_new_palette = num_palette;
- /* initial wild guess at how far apart the farthest pixel
- pair we will be eliminating will be. Larger
- numbers mean more areas will be allocated, Smaller
- numbers run the risk of not saving enough data, and
- having to do this all over again.
-
- I have not done extensive checking on this number.
- */
+ /* Initial wild guess at how far apart the farthest pixel
+ * pair we will be eliminating will be. Larger
+ * numbers mean more areas will be allocated, Smaller
+ * numbers run the risk of not saving enough data, and
+ * having to do this all over again.
+ *
+ * I have not done extensive checking on this number.
+ */
max_d = 96;
while (num_new_palette > maximum_colors)
@@ -341,9 +633,11 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
{
t = (png_dsortp)png_malloc_warn(png_ptr,
- (png_uint_32)(png_sizeof(png_dsort)));
+ (png_alloc_size_t)(sizeof (png_dsort)));
+
if (t == NULL)
break;
+
t->next = hash[d];
t->left = (png_byte)i;
t->right = (png_byte)j;
@@ -364,9 +658,9 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
for (p = hash[i]; p; p = p->next)
{
if ((int)png_ptr->index_to_palette[p->left]
- < num_new_palette &&
- (int)png_ptr->index_to_palette[p->right]
- < num_new_palette)
+ < num_new_palette &&
+ (int)png_ptr->index_to_palette[p->right]
+ < num_new_palette)
{
int j, next_j;
@@ -383,31 +677,36 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
num_new_palette--;
palette[png_ptr->index_to_palette[j]]
- = palette[num_new_palette];
- if (!full_dither)
+ = palette[num_new_palette];
+ if (full_quantize == 0)
{
int k;
for (k = 0; k < num_palette; k++)
{
- if (png_ptr->dither_index[k] ==
- png_ptr->index_to_palette[j])
- png_ptr->dither_index[k] =
- png_ptr->index_to_palette[next_j];
- if ((int)png_ptr->dither_index[k] ==
- num_new_palette)
- png_ptr->dither_index[k] =
- png_ptr->index_to_palette[j];
+ if (png_ptr->quantize_index[k] ==
+ png_ptr->index_to_palette[j])
+ png_ptr->quantize_index[k] =
+ png_ptr->index_to_palette[next_j];
+
+ if ((int)png_ptr->quantize_index[k] ==
+ num_new_palette)
+ png_ptr->quantize_index[k] =
+ png_ptr->index_to_palette[j];
}
}
png_ptr->index_to_palette[png_ptr->palette_to_index
- [num_new_palette]] = png_ptr->index_to_palette[j];
- png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
- = png_ptr->palette_to_index[num_new_palette];
+ [num_new_palette]] = png_ptr->index_to_palette[j];
- png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
- png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
+ png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
+ = png_ptr->palette_to_index[num_new_palette];
+
+ png_ptr->index_to_palette[j] =
+ (png_byte)num_new_palette;
+
+ png_ptr->palette_to_index[num_new_palette] =
+ (png_byte)j;
}
if (num_new_palette <= maximum_colors)
break;
@@ -436,8 +735,8 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
png_free(png_ptr, hash);
png_free(png_ptr, png_ptr->palette_to_index);
png_free(png_ptr, png_ptr->index_to_palette);
- png_ptr->palette_to_index=NULL;
- png_ptr->index_to_palette=NULL;
+ png_ptr->palette_to_index = NULL;
+ png_ptr->index_to_palette = NULL;
}
num_palette = maximum_colors;
}
@@ -447,40 +746,37 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
}
png_ptr->num_palette = (png_uint_16)num_palette;
- if (full_dither)
+ if (full_quantize != 0)
{
int i;
png_bytep distance;
- int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
- PNG_DITHER_BLUE_BITS;
- int num_red = (1 << PNG_DITHER_RED_BITS);
- int num_green = (1 << PNG_DITHER_GREEN_BITS);
- int num_blue = (1 << PNG_DITHER_BLUE_BITS);
- png_size_t num_entries = ((png_size_t)1 << total_bits);
+ int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +
+ PNG_QUANTIZE_BLUE_BITS;
+ int num_red = (1 << PNG_QUANTIZE_RED_BITS);
+ int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);
+ int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);
+ size_t num_entries = ((size_t)1 << total_bits);
- png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
- (png_uint_32)(num_entries * png_sizeof (png_byte)));
+ png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
+ (png_alloc_size_t)(num_entries));
- png_memset(png_ptr->palette_lookup, 0, num_entries *
- png_sizeof (png_byte));
+ distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
- distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
- png_sizeof(png_byte)));
-
- png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
+ memset(distance, 0xff, num_entries);
for (i = 0; i < num_palette; i++)
{
int ir, ig, ib;
- int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
- int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
- int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+ int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));
+ int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));
+ int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));
for (ir = 0; ir < num_red; ir++)
{
/* int dr = abs(ir - r); */
int dr = ((ir > r) ? ir - r : r - ir);
- int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+ int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
+ PNG_QUANTIZE_GREEN_BITS));
for (ig = 0; ig < num_green; ig++)
{
@@ -488,7 +784,7 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
int dg = ((ig > g) ? ig - g : g - ig);
int dt = dr + dg;
int dm = ((dr > dg) ? dr : dg);
- int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+ int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);
for (ib = 0; ib < num_blue; ib++)
{
@@ -511,46 +807,72 @@ png_set_dither(png_structp png_ptr, png_colorp palette,
png_free(png_ptr, distance);
}
}
-#endif
+#endif /* READ_QUANTIZE */
-#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
-/* Transform the image from the file_gamma to the screen_gamma. We
- * only do transformations on images where the file_gamma and screen_gamma
- * are not close reciprocals, otherwise it slows things down slightly, and
- * also needlessly introduces small errors.
- *
- * We will turn off gamma transformation later if no semitransparent entries
- * are present in the tRNS array for palette images. We can't do it here
- * because we don't necessarily have the tRNS chunk yet.
- */
-void PNGAPI
-png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
+#ifdef PNG_READ_GAMMA_SUPPORTED
+void PNGFAPI
+png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
+ png_fixed_point file_gamma)
{
- png_debug(1, "in png_set_gamma\n");
- if(png_ptr == NULL) return;
- if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
- (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
- (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
- png_ptr->transformations |= PNG_GAMMA;
- png_ptr->gamma = (float)file_gamma;
- png_ptr->screen_gamma = (float)scrn_gamma;
-}
-#endif
+ png_debug(1, "in png_set_gamma_fixed");
-#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ 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*/);
+
+ /* 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
+ * of the previous implementation which allowed gamma processing to be
+ * disabled in background handling. There is no evidence (so far) that this
+ * was being used; however, png_set_background itself accepted and must still
+ * accept '0' for the gamma value it takes, because it isn't always used.
+ *
+ * Since this is an API change (albeit a very minor one that removes an
+ * undocumented API feature) the following checks were only enabled in
+ * libpng-1.6.0.
+ */
+ if (file_gamma <= 0)
+ png_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");
+
+ /* 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.
+ */
+ png_ptr->colorspace.gamma = file_gamma;
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
+ png_ptr->screen_gamma = scrn_gamma;
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
+{
+ png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
+ convert_gamma_value(png_ptr, file_gamma));
+}
+# endif /* FLOATING_POINT */
+#endif /* READ_GAMMA */
+
+#ifdef PNG_READ_EXPAND_SUPPORTED
/* Expand paletted images to RGB, expand grayscale images of
* less than 8-bit depth to 8-bit depth, and expand tRNS chunks
* to alpha channels.
*/
void PNGAPI
-png_set_expand(png_structp png_ptr)
+png_set_expand(png_structrp png_ptr)
{
- png_debug(1, "in png_set_expand\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_expand");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
-#endif
}
/* GRR 19990627: the following three functions currently are identical
@@ -566,317 +888,726 @@ png_set_expand(png_structp png_ptr)
* More to the point, these functions make it obvious what libpng will be
* doing, whereas "expand" can (and does) mean any number of things.
*
- * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
- * to expand only the sample depth but not to expand the tRNS to alpha.
+ * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified
+ * to expand only the sample depth but not to expand the tRNS to alpha
+ * and its name was changed to png_set_expand_gray_1_2_4_to_8().
*/
/* Expand paletted images to RGB. */
void PNGAPI
-png_set_palette_to_rgb(png_structp png_ptr)
+png_set_palette_to_rgb(png_structrp png_ptr)
{
- png_debug(1, "in png_set_palette_to_rgb\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_palette_to_rgb");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
-#endif
}
-#if !defined(PNG_1_0_X)
/* Expand grayscale images of less than 8-bit depth to 8 bits. */
void PNGAPI
-png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
+png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
{
- png_debug(1, "in png_set_expand_gray_1_2_4_to_8\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
png_ptr->transformations |= PNG_EXPAND;
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
-#endif
}
-#endif
-
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-/* Expand grayscale images of less than 8-bit depth to 8 bits. */
-/* Deprecated as of libpng-1.2.9 */
-void PNGAPI
-png_set_gray_1_2_4_to_8(png_structp png_ptr)
-{
- png_debug(1, "in png_set_gray_1_2_4_to_8\n");
- if(png_ptr == NULL) return;
- png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
-}
-#endif
-
/* Expand tRNS chunks to alpha channels. */
void PNGAPI
-png_set_tRNS_to_alpha(png_structp png_ptr)
+png_set_tRNS_to_alpha(png_structrp png_ptr)
{
- png_debug(1, "in png_set_tRNS_to_alpha\n");
+ png_debug(1, "in png_set_tRNS_to_alpha");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
-#endif
}
-#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
+#endif /* READ_EXPAND */
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise
+ * it may not work correctly.)
+ */
void PNGAPI
-png_set_gray_to_rgb(png_structp png_ptr)
+png_set_expand_16(png_structrp png_ptr)
{
- png_debug(1, "in png_set_gray_to_rgb\n");
- png_ptr->transformations |= PNG_GRAY_TO_RGB;
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
-#endif
+ png_debug(1, "in png_set_expand_16");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
+ png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);
}
#endif
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-#if defined(PNG_FLOATING_POINT_SUPPORTED)
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+void PNGAPI
+png_set_gray_to_rgb(png_structrp png_ptr)
+{
+ png_debug(1, "in png_set_gray_to_rgb");
+
+ if (png_rtran_ok(png_ptr, 0) == 0)
+ return;
+
+ /* Because rgb must be 8 bits or more: */
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+}
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+void PNGFAPI
+png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
+ png_fixed_point red, png_fixed_point green)
+{
+ png_debug(1, "in png_set_rgb_to_gray_fixed");
+
+ /* Need the IHDR here because of the check on color_type below. */
+ /* TODO: fix this */
+ if (png_rtran_ok(png_ptr, 1) == 0)
+ return;
+
+ switch (error_action)
+ {
+ case PNG_ERROR_ACTION_NONE:
+ png_ptr->transformations |= PNG_RGB_TO_GRAY;
+ break;
+
+ case PNG_ERROR_ACTION_WARN:
+ png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
+ break;
+
+ case PNG_ERROR_ACTION_ERROR:
+ png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
+ break;
+
+ default:
+ png_error(png_ptr, "invalid error action to rgb_to_gray");
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ png_ptr->transformations |= PNG_EXPAND;
+#else
+ {
+ /* Make this an error in 1.6 because otherwise the application may assume
+ * that it just worked and get a memory overwrite.
+ */
+ png_error(png_ptr,
+ "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
+
+ /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */
+ }
+#endif
+ {
+ if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)
+ {
+ png_uint_16 red_int, green_int;
+
+ /* NOTE: this calculation does not round, but this behavior is retained
+ * for consistency; the inaccuracy is very small. The code here always
+ * overwrites the coefficients, regardless of whether they have been
+ * defaulted or set already.
+ */
+ red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);
+ green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);
+
+ png_ptr->rgb_to_gray_red_coeff = red_int;
+ png_ptr->rgb_to_gray_green_coeff = green_int;
+ 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; */
+ }
+ }
+ }
+}
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
/* Convert a RGB image to a grayscale of the same width. This allows us,
* for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
*/
void PNGAPI
-png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
- double green)
+png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
+ double green)
{
- int red_fixed = (int)((float)red*100000.0 + 0.5);
- int green_fixed = (int)((float)green*100000.0 + 0.5);
- if(png_ptr == NULL) return;
- png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
+ png_set_rgb_to_gray_fixed(png_ptr, error_action,
+ png_fixed(png_ptr, red, "rgb to gray red coefficient"),
+ png_fixed(png_ptr, green, "rgb to gray green coefficient"));
}
-#endif
+#endif /* FLOATING POINT */
-void PNGAPI
-png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
- png_fixed_point red, png_fixed_point green)
-{
- png_debug(1, "in png_set_rgb_to_gray\n");
- if(png_ptr == NULL) return;
- switch(error_action)
- {
- case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
- break;
- case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
- break;
- case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
- }
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- png_ptr->transformations |= PNG_EXPAND;
-#else
- {
- png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
- png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
- }
-#endif
- {
- png_uint_16 red_int, green_int;
- if(red < 0 || green < 0)
- {
- red_int = 6968; /* .212671 * 32768 + .5 */
- green_int = 23434; /* .715160 * 32768 + .5 */
- }
- else if(red + green < 100000L)
- {
- red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
- green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
- }
- else
- {
- png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
- red_int = 6968;
- green_int = 23434;
- }
- png_ptr->rgb_to_gray_red_coeff = red_int;
- png_ptr->rgb_to_gray_green_coeff = green_int;
- png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
- }
-}
-#endif
+#endif /* RGB_TO_GRAY */
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
void PNGAPI
-png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
- read_user_transform_fn)
+png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
+ read_user_transform_fn)
{
- png_debug(1, "in png_set_read_user_transform_fn\n");
- if(png_ptr == NULL) return;
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ png_debug(1, "in png_set_read_user_transform_fn");
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
png_ptr->transformations |= PNG_USER_TRANSFORM;
png_ptr->read_user_transform_fn = read_user_transform_fn;
#endif
-#ifdef PNG_LEGACY_SUPPORTED
- if(read_user_transform_fn)
- png_warning(png_ptr,
- "This version of libpng does not support user transforms");
+}
#endif
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+#ifdef PNG_READ_GAMMA_SUPPORTED
+/* In the case of gamma transformations only do transformations on images where
+ * the [file] gamma and screen_gamma are not close reciprocals, otherwise it
+ * slows things down slightly, and also needlessly introduces small errors.
+ */
+static int /* PRIVATE */
+png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
+{
+ /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
+ * correction as a difference of the overall transform from 1.0
+ *
+ * We want to compare the threshold with s*f - 1, if we get
+ * overflow here it is because of wacky gamma values so we
+ * turn on processing anyway.
+ */
+ png_fixed_point gtest;
+ return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) ||
+ png_gamma_significant(gtest);
}
#endif
/* Initialize everything needed for the read. This includes modifying
* the palette.
*/
-void /* PRIVATE */
-png_init_read_transformations(png_structp png_ptr)
+
+/* For the moment 'png_init_palette_transformations' and
+ * 'png_init_rgb_transformations' only do some flag canceling optimizations.
+ * The intent is that these two routines should have palette or rgb operations
+ * extracted from 'png_init_read_transformations'.
+ */
+static void /* PRIVATE */
+png_init_palette_transformations(png_structrp png_ptr)
{
- png_debug(1, "in png_init_read_transformations\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if(png_ptr != NULL)
-#endif
- {
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
- || defined(PNG_READ_GAMMA_SUPPORTED)
- int color_type = png_ptr->color_type;
-#endif
+ /* Called to handle the (input) palette case. In png_do_read_transformations
+ * the first step is to expand the palette if requested, so this code must
+ * take care to only make changes that are invariant with respect to the
+ * palette expansion, or only do them if there is no expansion.
+ *
+ * STRIP_ALPHA has already been handled in the caller (by setting num_trans
+ * to 0.)
+ */
+ int input_has_alpha = 0;
+ int input_has_transparency = 0;
+
+ if (png_ptr->num_trans > 0)
+ {
+ int i;
+
+ /* Ignore if all the entries are opaque (unlikely!) */
+ for (i=0; inum_trans; ++i)
+ {
+ if (png_ptr->trans_alpha[i] == 255)
+ continue;
+ else if (png_ptr->trans_alpha[i] == 0)
+ input_has_transparency = 1;
+ else
+ {
+ input_has_transparency = 1;
+ input_has_alpha = 1;
+ break;
+ }
+ }
+ }
+
+ /* If no alpha we can optimize. */
+ if (input_has_alpha == 0)
+ {
+ /* Any alpha means background and associative alpha processing is
+ * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
+ * and ENCODE_ALPHA are irrelevant.
+ */
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
+ if (input_has_transparency == 0)
+ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
+ }
#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* png_set_background handling - deals with the complexity of whether the
+ * background color is in the file format or the screen format in the case
+ * where an 'expand' will happen.
+ */
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
- /* Detect gray background and attempt to enable optimization
- * for gray --> RGB case */
- /* Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
+ /* The following code cannot be entered in the alpha pre-multiplication case
+ * because PNG_BACKGROUND_EXPAND is cancelled below.
+ */
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
+ (png_ptr->transformations & PNG_EXPAND) != 0)
+ {
+ {
+ png_ptr->background.red =
+ png_ptr->palette[png_ptr->background.index].red;
+ png_ptr->background.green =
+ png_ptr->palette[png_ptr->background.index].green;
+ png_ptr->background.blue =
+ png_ptr->palette[png_ptr->background.index].blue;
+
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
+ {
+ if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
+ {
+ /* Invert the alpha channel (in tRNS) unless the pixels are
+ * going to be expanded, in which case leave it for later
+ */
+ int i, istop = png_ptr->num_trans;
+
+ for (i = 0; i < istop; i++)
+ png_ptr->trans_alpha[i] =
+ (png_byte)(255 - png_ptr->trans_alpha[i]);
+ }
+ }
+#endif /* READ_INVERT_ALPHA */
+ }
+ } /* background expand and (therefore) no alpha association. */
+#endif /* READ_EXPAND && READ_BACKGROUND */
+}
+
+static void /* PRIVATE */
+png_init_rgb_transformations(png_structrp png_ptr)
+{
+ /* Added to libpng-1.5.4: check the color type to determine whether there
+ * is any alpha or transparency in the image and simply cancel the
+ * background and alpha mode stuff if there isn't.
+ */
+ int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;
+ int input_has_transparency = png_ptr->num_trans > 0;
+
+ /* If no alpha we can optimize. */
+ if (input_has_alpha == 0)
+ {
+ /* Any alpha means background and associative alpha processing is
+ * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
+ * and ENCODE_ALPHA are irrelevant.
+ */
+# ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+# endif
+
+ if (input_has_transparency == 0)
+ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
+ }
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* png_set_background handling - deals with the complexity of whether the
+ * background color is in the file format or the screen format in the case
+ * where an 'expand' will happen.
+ */
+
+ /* The following code cannot be entered in the alpha pre-multiplication case
+ * because PNG_BACKGROUND_EXPAND is cancelled below.
+ */
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
+ (png_ptr->transformations & PNG_EXPAND) != 0 &&
+ (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
+ /* i.e., GRAY or GRAY_ALPHA */
+ {
+ {
+ /* Expand background and tRNS chunks */
+ int gray = png_ptr->background.gray;
+ int trans_gray = png_ptr->trans_color.gray;
+
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ gray *= 0xff;
+ trans_gray *= 0xff;
+ break;
+
+ case 2:
+ gray *= 0x55;
+ trans_gray *= 0x55;
+ break;
+
+ case 4:
+ gray *= 0x11;
+ trans_gray *= 0x11;
+ break;
+
+ default:
+
+ case 8:
+ /* FALLTHROUGH */ /* (Already 8 bits) */
+
+ case 16:
+ /* Already a full 16 bits */
+ break;
+ }
+
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = (png_uint_16)gray;
+
+ if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
+ {
+ png_ptr->trans_color.red = png_ptr->trans_color.green =
+ png_ptr->trans_color.blue = (png_uint_16)trans_gray;
+ }
+ }
+ } /* background expand and (therefore) no alpha association. */
+#endif /* READ_EXPAND && READ_BACKGROUND */
+}
+
+void /* PRIVATE */
+png_init_read_transformations(png_structrp png_ptr)
+{
+ png_debug(1, "in png_init_read_transformations");
+
+ /* This internal function is called from png_read_start_row in pngrutil.c
+ * and it is called before the 'rowbytes' calculation is done, so the code
+ * in here can change or update the transformations flags.
+ *
+ * First do updates that do not depend on the details of the PNG image data
+ * being processed.
+ */
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds
+ * png_set_alpha_mode and this is another source for a default file gamma so
+ * 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.)
+ */
+ {
+ /* 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);
+
+ 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;
+ }
+#endif
+
+ /* Certain transformations have the effect of preventing other
+ * transformations that happen afterward in png_do_read_transformations;
+ * resolve the interdependencies here. From the code of
+ * png_do_read_transformations the order is:
+ *
+ * 1) PNG_EXPAND (including PNG_EXPAND_tRNS)
+ * 2) PNG_STRIP_ALPHA (if no compose)
+ * 3) PNG_RGB_TO_GRAY
+ * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY
+ * 5) PNG_COMPOSE
+ * 6) PNG_GAMMA
+ * 7) PNG_STRIP_ALPHA (if compose)
+ * 8) PNG_ENCODE_ALPHA
+ * 9) PNG_SCALE_16_TO_8
+ * 10) PNG_16_TO_8
+ * 11) PNG_QUANTIZE (converts to palette)
+ * 12) PNG_EXPAND_16
+ * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY
+ * 14) PNG_INVERT_MONO
+ * 15) PNG_INVERT_ALPHA
+ * 16) PNG_SHIFT
+ * 17) PNG_PACK
+ * 18) PNG_BGR
+ * 19) PNG_PACKSWAP
+ * 20) PNG_FILLER (includes PNG_ADD_ALPHA)
+ * 21) PNG_SWAP_ALPHA
+ * 22) PNG_SWAP_BYTES
+ * 23) PNG_USER_TRANSFORM [must be last]
+ */
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
+ (png_ptr->transformations & PNG_COMPOSE) == 0)
+ {
+ /* Stripping the alpha channel happens immediately after the 'expand'
+ * transformations, before all other transformation, so it cancels out
+ * the alpha handling. It has the side effect negating the effect of
+ * PNG_EXPAND_tRNS too:
+ */
+ png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |
+ PNG_EXPAND_tRNS);
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
+ /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen
+ * so transparency information would remain just so long as it wasn't
+ * expanded. This produces unexpected API changes if the set of things
+ * that do PNG_EXPAND_tRNS changes (perfectly possible given the
+ * documentation - which says ask for what you want, accept what you
+ * get.) This makes the behavior consistent from 1.5.4:
+ */
+ png_ptr->num_trans = 0;
+ }
+#endif /* STRIP_ALPHA supported, no COMPOSE */
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+ /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA
+ * settings will have no effect.
+ */
+ if (png_gamma_significant(png_ptr->screen_gamma) == 0)
+ {
+ png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+ png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+ }
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ /* Make sure the coefficients for the rgb to gray conversion are set
+ * appropriately.
+ */
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
+ png_colorspace_set_rgb_coefficients(png_ptr);
+#endif
+
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* Detect gray background and attempt to enable optimization for
+ * gray --> RGB case.
+ *
+ * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
* RGB_ALPHA (in which case need_expand is superfluous anyway), the
* background color might actually be gray yet not be flagged as such.
* This is not a problem for the current code, which uses
* PNG_BACKGROUND_IS_GRAY only to decide when to do the
* png_do_gray_to_rgb() transformation.
+ *
+ * TODO: this code needs to be revised to avoid the complexity and
+ * interdependencies. The color type of the background should be recorded in
+ * png_set_background, along with the bit depth, then the code has a record
+ * of exactly what color space the background is currently in.
*/
- if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
- !(color_type & PNG_COLOR_MASK_COLOR))
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0)
{
- png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
- } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
- !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
- (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
- png_ptr->background.red == png_ptr->background.green &&
- png_ptr->background.red == png_ptr->background.blue)
- {
- png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
- png_ptr->background.gray = png_ptr->background.red;
+ /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
+ * the file was grayscale the background value is gray.
+ */
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
+ png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
}
-#endif
- if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
- (png_ptr->transformations & PNG_EXPAND))
+ else if ((png_ptr->transformations & PNG_COMPOSE) != 0)
{
- if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
+ /* PNG_COMPOSE: png_set_background was called with need_expand false,
+ * so the color is in the color space of the output or png_set_alpha_mode
+ * was called and the color is black. Ignore RGB_TO_GRAY because that
+ * happens before GRAY_TO_RGB.
+ */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
{
- /* expand background and tRNS chunks */
- switch (png_ptr->bit_depth)
+ if (png_ptr->background.red == png_ptr->background.green &&
+ png_ptr->background.red == png_ptr->background.blue)
{
- case 1:
- png_ptr->background.gray *= (png_uint_16)0xff;
- png_ptr->background.red = png_ptr->background.green
- = png_ptr->background.blue = png_ptr->background.gray;
- if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
- {
- png_ptr->trans_values.gray *= (png_uint_16)0xff;
- png_ptr->trans_values.red = png_ptr->trans_values.green
- = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
- }
- break;
- case 2:
- png_ptr->background.gray *= (png_uint_16)0x55;
- png_ptr->background.red = png_ptr->background.green
- = png_ptr->background.blue = png_ptr->background.gray;
- if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
- {
- png_ptr->trans_values.gray *= (png_uint_16)0x55;
- png_ptr->trans_values.red = png_ptr->trans_values.green
- = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
- }
- break;
- case 4:
- png_ptr->background.gray *= (png_uint_16)0x11;
- png_ptr->background.red = png_ptr->background.green
- = png_ptr->background.blue = png_ptr->background.gray;
- if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
- {
- png_ptr->trans_values.gray *= (png_uint_16)0x11;
- png_ptr->trans_values.red = png_ptr->trans_values.green
- = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
- }
- break;
- case 8:
- case 16:
- png_ptr->background.red = png_ptr->background.green
- = png_ptr->background.blue = png_ptr->background.gray;
- break;
+ png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+ png_ptr->background.gray = png_ptr->background.red;
}
}
- else if (color_type == PNG_COLOR_TYPE_PALETTE)
- {
- png_ptr->background.red =
- png_ptr->palette[png_ptr->background.index].red;
- png_ptr->background.green =
- png_ptr->palette[png_ptr->background.index].green;
- png_ptr->background.blue =
- png_ptr->palette[png_ptr->background.index].blue;
+ }
+#endif /* READ_EXPAND && READ_BACKGROUND */
+#endif /* READ_GRAY_TO_RGB */
-#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_ALPHA)
- {
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
-#endif
- {
- /* invert the alpha channel (in tRNS) unless the pixels are
- going to be expanded, in which case leave it for later */
- int i,istop;
- istop=(int)png_ptr->num_trans;
- for (i=0; itrans[i] = (png_byte)(255 - png_ptr->trans[i]);
- }
- }
-#endif
+ /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations
+ * can be performed directly on the palette, and some (such as rgb to gray)
+ * can be optimized inside the palette. This is particularly true of the
+ * composite (background and alpha) stuff, which can be pretty much all done
+ * in the palette even if the result is expanded to RGB or gray afterward.
+ *
+ * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and
+ * earlier and the palette stuff is actually handled on the first row. This
+ * leads to the reported bug that the palette returned by png_get_PLTE is not
+ * updated.
+ */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_init_palette_transformations(png_ptr);
- }
+ else
+ png_init_rgb_transformations(png_ptr);
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ defined(PNG_READ_EXPAND_16_SUPPORTED)
+ if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
+ (png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
+ png_ptr->bit_depth != 16)
+ {
+ /* TODO: fix this. Because the expand_16 operation is after the compose
+ * handling the background color must be 8, not 16, bits deep, but the
+ * application will supply a 16-bit value so reduce it here.
+ *
+ * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at
+ * present, so that case is ok (until do_expand_16 is moved.)
+ *
+ * NOTE: this discards the low 16 bits of the user supplied background
+ * color, but until expand_16 works properly there is no choice!
+ */
+# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))
+ CHOP(png_ptr->background.red);
+ CHOP(png_ptr->background.green);
+ CHOP(png_ptr->background.blue);
+ CHOP(png_ptr->background.gray);
+# undef CHOP
+ }
+#endif /* READ_BACKGROUND && READ_EXPAND_16 */
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \
+ defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))
+ if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 &&
+ (png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
+ png_ptr->bit_depth == 16)
+ {
+ /* On the other hand, if a 16-bit file is to be reduced to 8-bits per
+ * component this will also happen after PNG_COMPOSE and so the background
+ * color must be pre-expanded here.
+ *
+ * TODO: fix this too.
+ */
+ png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);
+ png_ptr->background.green =
+ (png_uint_16)(png_ptr->background.green * 257);
+ png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);
+ png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);
}
#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
- png_ptr->background_1 = png_ptr->background;
-#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the
+ * background support (see the comments in scripts/pnglibconf.dfa), this
+ * allows pre-multiplication of the alpha channel to be implemented as
+ * compositing on black. This is probably sub-optimal and has been done in
+ * 1.5.4 betas simply to enable external critique and testing (i.e. to
+ * implement the new API quickly, without lots of internal changes.)
+ */
- if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
- && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
- < PNG_GAMMA_THRESHOLD))
- {
- int i,k;
- k=0;
- for (i=0; inum_trans; i++)
- {
- if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
- k=1; /* partial transparency is present */
- }
- if (k == 0)
- png_ptr->transformations &= ~PNG_GAMMA;
- }
+#ifdef PNG_READ_GAMMA_SUPPORTED
+# ifdef PNG_READ_BACKGROUND_SUPPORTED
+ /* Includes ALPHA_MODE */
+ png_ptr->background_1 = png_ptr->background;
+# endif
- if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
- png_ptr->gamma != 0.0)
+ /* This needs to change - in the palette image case a whole set of tables are
+ * built when it would be quicker to just calculate the correct value for
+ * each palette entry directly. Also, the test is too tricky - why check
+ * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that
+ * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the
+ * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction
+ * the gamma tables will not be built even if composition is required on a
+ * gamma encoded value.
+ *
+ * In 1.5.4 this is addressed below by an additional check on the individual
+ * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the
+ * tables.
+ */
+ 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->screen_gamma) != 0)) ||
+ ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
+ png_gamma_significant(png_ptr->screen_gamma) != 0
+# ifdef PNG_READ_BACKGROUND_SUPPORTED
+ || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&
+ png_gamma_significant(png_ptr->background_gamma) != 0)
+# endif
+ )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
+ png_gamma_significant(png_ptr->screen_gamma) != 0))
{
- png_build_gamma_table(png_ptr);
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->transformations & PNG_BACKGROUND)
+ png_build_gamma_table(png_ptr, png_ptr->bit_depth);
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0)
{
- if (color_type == PNG_COLOR_TYPE_PALETTE)
+ /* Issue a warning about this combination: because RGB_TO_GRAY is
+ * optimized to do the gamma transform if present yet do_background has
+ * to do the same thing if both options are set a
+ * double-gamma-correction happens. This is true in all versions of
+ * libpng to date.
+ */
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
+ png_warning(png_ptr,
+ "libpng does not support gamma+background+rgb_to_gray");
+
+ if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0)
{
- /* could skip if no transparency and
- */
+ /* We don't get to here unless there is a tRNS chunk with non-opaque
+ * entries - see the checking code at the start of this function.
+ */
png_color back, back_1;
png_colorp palette = png_ptr->palette;
int num_palette = png_ptr->num_palette;
int i;
if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
{
+
back.red = png_ptr->gamma_table[png_ptr->background.red];
back.green = png_ptr->gamma_table[png_ptr->background.green];
back.blue = png_ptr->gamma_table[png_ptr->background.blue];
@@ -887,73 +1618,90 @@ png_init_read_transformations(png_structp png_ptr)
}
else
{
- double g, gs;
+ png_fixed_point g, gs;
switch (png_ptr->background_gamma_type)
{
case PNG_BACKGROUND_GAMMA_SCREEN:
g = (png_ptr->screen_gamma);
- gs = 1.0;
+ gs = PNG_FP_1;
break;
+
case PNG_BACKGROUND_GAMMA_FILE:
- g = 1.0 / (png_ptr->gamma);
- gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ g = png_reciprocal(png_ptr->colorspace.gamma);
+ gs = png_reciprocal2(png_ptr->colorspace.gamma,
+ png_ptr->screen_gamma);
break;
+
case PNG_BACKGROUND_GAMMA_UNIQUE:
- g = 1.0 / (png_ptr->background_gamma);
- gs = 1.0 / (png_ptr->background_gamma *
- png_ptr->screen_gamma);
+ g = png_reciprocal(png_ptr->background_gamma);
+ gs = png_reciprocal2(png_ptr->background_gamma,
+ png_ptr->screen_gamma);
break;
default:
- g = 1.0; /* back_1 */
- gs = 1.0; /* back */
+ g = PNG_FP_1; /* back_1 */
+ gs = PNG_FP_1; /* back */
+ break;
}
- if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
+ if (png_gamma_significant(gs) != 0)
+ {
+ back.red = png_gamma_8bit_correct(png_ptr->background.red,
+ gs);
+ back.green = png_gamma_8bit_correct(png_ptr->background.green,
+ gs);
+ back.blue = png_gamma_8bit_correct(png_ptr->background.blue,
+ gs);
+ }
+
+ else
{
back.red = (png_byte)png_ptr->background.red;
back.green = (png_byte)png_ptr->background.green;
back.blue = (png_byte)png_ptr->background.blue;
}
- else
+
+ if (png_gamma_significant(g) != 0)
{
- back.red = (png_byte)(pow(
- (double)png_ptr->background.red/255, gs) * 255.0 + .5);
- back.green = (png_byte)(pow(
- (double)png_ptr->background.green/255, gs) * 255.0 + .5);
- back.blue = (png_byte)(pow(
- (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
+ back_1.red = png_gamma_8bit_correct(png_ptr->background.red,
+ g);
+ back_1.green = png_gamma_8bit_correct(
+ png_ptr->background.green, g);
+ back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
+ g);
}
- back_1.red = (png_byte)(pow(
- (double)png_ptr->background.red/255, g) * 255.0 + .5);
- back_1.green = (png_byte)(pow(
- (double)png_ptr->background.green/255, g) * 255.0 + .5);
- back_1.blue = (png_byte)(pow(
- (double)png_ptr->background.blue/255, g) * 255.0 + .5);
+ else
+ {
+ back_1.red = (png_byte)png_ptr->background.red;
+ back_1.green = (png_byte)png_ptr->background.green;
+ back_1.blue = (png_byte)png_ptr->background.blue;
+ }
}
+
for (i = 0; i < num_palette; i++)
{
- if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ if (i < (int)png_ptr->num_trans &&
+ png_ptr->trans_alpha[i] != 0xff)
{
- if (png_ptr->trans[i] == 0)
+ if (png_ptr->trans_alpha[i] == 0)
{
palette[i] = back;
}
- else /* if (png_ptr->trans[i] != 0xff) */
+ else /* if (png_ptr->trans_alpha[i] != 0xff) */
{
png_byte v, w;
v = png_ptr->gamma_to_1[palette[i].red];
- png_composite(w, v, png_ptr->trans[i], back_1.red);
+ png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
palette[i].red = png_ptr->gamma_from_1[w];
v = png_ptr->gamma_to_1[palette[i].green];
- png_composite(w, v, png_ptr->trans[i], back_1.green);
+ png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
palette[i].green = png_ptr->gamma_from_1[w];
v = png_ptr->gamma_to_1[palette[i].blue];
- png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
palette[i].blue = png_ptr->gamma_from_1[w];
}
}
@@ -964,90 +1712,140 @@ png_init_read_transformations(png_structp png_ptr)
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
- }
+
+ /* Prevent the transformations being done again.
+ *
+ * NOTE: this is highly dubious; it removes the transformations in
+ * place. This seems inconsistent with the general treatment of the
+ * transformations elsewhere.
+ */
+ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
+ } /* color_type == PNG_COLOR_TYPE_PALETTE */
+
/* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
- else
- /* color_type != PNG_COLOR_TYPE_PALETTE */
+ else /* color_type != PNG_COLOR_TYPE_PALETTE */
{
- double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
- double g = 1.0;
- double gs = 1.0;
+ int gs_sig, g_sig;
+ png_fixed_point g = PNG_FP_1; /* Correction to linear */
+ png_fixed_point gs = PNG_FP_1; /* Correction to screen */
switch (png_ptr->background_gamma_type)
{
case PNG_BACKGROUND_GAMMA_SCREEN:
- g = (png_ptr->screen_gamma);
- gs = 1.0;
+ g = png_ptr->screen_gamma;
+ /* gs = PNG_FP_1; */
break;
+
case PNG_BACKGROUND_GAMMA_FILE:
- g = 1.0 / (png_ptr->gamma);
- gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ g = png_reciprocal(png_ptr->colorspace.gamma);
+ gs = png_reciprocal2(png_ptr->colorspace.gamma,
+ png_ptr->screen_gamma);
break;
+
case PNG_BACKGROUND_GAMMA_UNIQUE:
- g = 1.0 / (png_ptr->background_gamma);
- gs = 1.0 / (png_ptr->background_gamma *
- png_ptr->screen_gamma);
+ g = png_reciprocal(png_ptr->background_gamma);
+ gs = png_reciprocal2(png_ptr->background_gamma,
+ png_ptr->screen_gamma);
break;
+
+ default:
+ png_error(png_ptr, "invalid background gamma type");
}
- png_ptr->background_1.gray = (png_uint_16)(pow(
- (double)png_ptr->background.gray / m, g) * m + .5);
- png_ptr->background.gray = (png_uint_16)(pow(
- (double)png_ptr->background.gray / m, gs) * m + .5);
+ g_sig = png_gamma_significant(g);
+ gs_sig = png_gamma_significant(gs);
+
+ if (g_sig != 0)
+ png_ptr->background_1.gray = png_gamma_correct(png_ptr,
+ png_ptr->background.gray, g);
+
+ if (gs_sig != 0)
+ png_ptr->background.gray = png_gamma_correct(png_ptr,
+ png_ptr->background.gray, gs);
if ((png_ptr->background.red != png_ptr->background.green) ||
(png_ptr->background.red != png_ptr->background.blue) ||
(png_ptr->background.red != png_ptr->background.gray))
{
/* RGB or RGBA with color background */
- png_ptr->background_1.red = (png_uint_16)(pow(
- (double)png_ptr->background.red / m, g) * m + .5);
- png_ptr->background_1.green = (png_uint_16)(pow(
- (double)png_ptr->background.green / m, g) * m + .5);
- png_ptr->background_1.blue = (png_uint_16)(pow(
- (double)png_ptr->background.blue / m, g) * m + .5);
- png_ptr->background.red = (png_uint_16)(pow(
- (double)png_ptr->background.red / m, gs) * m + .5);
- png_ptr->background.green = (png_uint_16)(pow(
- (double)png_ptr->background.green / m, gs) * m + .5);
- png_ptr->background.blue = (png_uint_16)(pow(
- (double)png_ptr->background.blue / m, gs) * m + .5);
+ if (g_sig != 0)
+ {
+ png_ptr->background_1.red = png_gamma_correct(png_ptr,
+ png_ptr->background.red, g);
+
+ png_ptr->background_1.green = png_gamma_correct(png_ptr,
+ png_ptr->background.green, g);
+
+ png_ptr->background_1.blue = png_gamma_correct(png_ptr,
+ png_ptr->background.blue, g);
+ }
+
+ if (gs_sig != 0)
+ {
+ png_ptr->background.red = png_gamma_correct(png_ptr,
+ png_ptr->background.red, gs);
+
+ png_ptr->background.green = png_gamma_correct(png_ptr,
+ png_ptr->background.green, gs);
+
+ png_ptr->background.blue = png_gamma_correct(png_ptr,
+ png_ptr->background.blue, gs);
+ }
}
+
else
{
/* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
png_ptr->background_1.red = png_ptr->background_1.green
- = png_ptr->background_1.blue = png_ptr->background_1.gray;
+ = png_ptr->background_1.blue = png_ptr->background_1.gray;
+
png_ptr->background.red = png_ptr->background.green
- = png_ptr->background.blue = png_ptr->background.gray;
+ = png_ptr->background.blue = png_ptr->background.gray;
}
- }
- }
+
+ /* The background is now in screen gamma: */
+ png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;
+ } /* color_type != PNG_COLOR_TYPE_PALETTE */
+ }/* png_ptr->transformations & PNG_BACKGROUND */
+
else
- /* transformation does not include PNG_BACKGROUND */
-#endif /* PNG_READ_BACKGROUND_SUPPORTED */
- if (color_type == PNG_COLOR_TYPE_PALETTE)
+ /* Transformation does not include PNG_BACKGROUND */
+#endif /* READ_BACKGROUND */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ /* RGB_TO_GRAY needs to have non-gamma-corrected values! */
+ && ((png_ptr->transformations & PNG_EXPAND) == 0 ||
+ (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
+#endif
+ )
{
png_colorp palette = png_ptr->palette;
int num_palette = png_ptr->num_palette;
int i;
+ /* NOTE: there are other transformations that should probably be in
+ * here too.
+ */
for (i = 0; i < num_palette; i++)
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
- }
+
+ /* Done the gamma correction. */
+ png_ptr->transformations &= ~PNG_GAMMA;
+ } /* color_type == PALETTE && !PNG_BACKGROUND transformation */
}
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
else
#endif
-#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- /* No GAMMA transformation */
- if ((png_ptr->transformations & PNG_BACKGROUND) &&
- (color_type == PNG_COLOR_TYPE_PALETTE))
+#endif /* READ_GAMMA */
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+ /* No GAMMA transformation (see the hanging else 4 lines above) */
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
{
int i;
int istop = (int)png_ptr->num_trans;
@@ -1060,54 +1858,74 @@ png_init_read_transformations(png_structp png_ptr)
for (i = 0; i < istop; i++)
{
- if (png_ptr->trans[i] == 0)
+ if (png_ptr->trans_alpha[i] == 0)
{
palette[i] = back;
}
- else if (png_ptr->trans[i] != 0xff)
+
+ else if (png_ptr->trans_alpha[i] != 0xff)
{
/* The png_composite() macro is defined in png.h */
png_composite(palette[i].red, palette[i].red,
- png_ptr->trans[i], back.red);
+ png_ptr->trans_alpha[i], back.red);
+
png_composite(palette[i].green, palette[i].green,
- png_ptr->trans[i], back.green);
+ png_ptr->trans_alpha[i], back.green);
+
png_composite(palette[i].blue, palette[i].blue,
- png_ptr->trans[i], back.blue);
+ png_ptr->trans_alpha[i], back.blue);
}
}
- }
-#endif /* PNG_READ_BACKGROUND_SUPPORTED */
-#if defined(PNG_READ_SHIFT_SUPPORTED)
- if ((png_ptr->transformations & PNG_SHIFT) &&
- (color_type == PNG_COLOR_TYPE_PALETTE))
+ png_ptr->transformations &= ~PNG_COMPOSE;
+ }
+#endif /* READ_BACKGROUND */
+
+#ifdef PNG_READ_SHIFT_SUPPORTED
+ if ((png_ptr->transformations & PNG_SHIFT) != 0 &&
+ (png_ptr->transformations & PNG_EXPAND) == 0 &&
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
{
- png_uint_16 i;
- png_uint_16 istop = png_ptr->num_palette;
- int sr = 8 - png_ptr->sig_bit.red;
- int sg = 8 - png_ptr->sig_bit.green;
- int sb = 8 - png_ptr->sig_bit.blue;
+ int i;
+ int istop = png_ptr->num_palette;
+ int shift = 8 - png_ptr->sig_bit.red;
- if (sr < 0 || sr > 8)
- sr = 0;
- if (sg < 0 || sg > 8)
- sg = 0;
- if (sb < 0 || sb > 8)
- sb = 0;
- for (i = 0; i < istop; i++)
- {
- png_ptr->palette[i].red >>= sr;
- png_ptr->palette[i].green >>= sg;
- png_ptr->palette[i].blue >>= sb;
- }
+ png_ptr->transformations &= ~PNG_SHIFT;
+
+ /* significant bits can be in the range 1 to 7 for a meaningful result, if
+ * the number of significant bits is 0 then no shift is done (this is an
+ * error condition which is silently ignored.)
+ */
+ if (shift > 0 && shift < 8)
+ for (i=0; ipalette[i].red;
+
+ component >>= shift;
+ png_ptr->palette[i].red = (png_byte)component;
+ }
+
+ shift = 8 - png_ptr->sig_bit.green;
+ if (shift > 0 && shift < 8)
+ for (i=0; ipalette[i].green;
+
+ component >>= shift;
+ png_ptr->palette[i].green = (png_byte)component;
+ }
+
+ shift = 8 - png_ptr->sig_bit.blue;
+ if (shift > 0 && shift < 8)
+ for (i=0; ipalette[i].blue;
+
+ component >>= shift;
+ png_ptr->palette[i].blue = (png_byte)component;
+ }
}
-#endif /* PNG_READ_SHIFT_SUPPORTED */
- }
-#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
- && !defined(PNG_READ_BACKGROUND_SUPPORTED)
- if(png_ptr)
- return;
-#endif
+#endif /* READ_SHIFT */
}
/* Modify the info structure to reflect the transformations. The
@@ -1115,401 +1933,223 @@ png_init_read_transformations(png_structp png_ptr)
* assuming the transformations result in valid PNG data.
*/
void /* PRIVATE */
-png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
{
- png_debug(1, "in png_read_transform_info\n");
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- if (png_ptr->transformations & PNG_EXPAND)
+ png_debug(1, "in png_read_transform_info");
+
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
{
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND_tRNS))
+ /* This check must match what actually happens in
+ * png_do_expand_palette; if it ever checks the tRNS chunk to see if
+ * it is all opaque we must do the same (at present it does not.)
+ */
+ if (png_ptr->num_trans > 0)
info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+
else
info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+
info_ptr->bit_depth = 8;
info_ptr->num_trans = 0;
+
+ if (png_ptr->palette == NULL)
+ png_error (png_ptr, "Palette is NULL in indexed image");
}
else
{
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
{
- if (png_ptr->transformations & PNG_EXPAND_tRNS)
- info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
- else
- info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+ if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
}
if (info_ptr->bit_depth < 8)
info_ptr->bit_depth = 8;
+
info_ptr->num_trans = 0;
}
}
#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->transformations & PNG_BACKGROUND)
- {
- info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
- info_ptr->num_trans = 0;
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+ /* The following is almost certainly wrong unless the background value is in
+ * the screen space!
+ */
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0)
info_ptr->background = png_ptr->background;
- }
#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (png_ptr->transformations & PNG_GAMMA)
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),
+ * however it seems that the code in png_init_read_transformations, which has
+ * 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.
+ */
+ info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
+#endif
+
+ if (info_ptr->bit_depth == 16)
{
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- info_ptr->gamma = png_ptr->gamma;
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- info_ptr->int_gamma = png_ptr->int_gamma;
-#endif
+# ifdef PNG_READ_16BIT_SUPPORTED
+# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+ if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
+ info_ptr->bit_depth = 8;
+# endif
+
+# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+ if ((png_ptr->transformations & PNG_16_TO_8) != 0)
+ info_ptr->bit_depth = 8;
+# endif
+
+# else
+ /* No 16-bit support: force chopping 16-bit input down to 8, in this case
+ * the app program can chose if both APIs are available by setting the
+ * correct scaling to use.
+ */
+# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+ /* For compatibility with previous versions use the strip method by
+ * default. This code works because if PNG_SCALE_16_TO_8 is already
+ * set the code below will do that in preference to the chop.
+ */
+ png_ptr->transformations |= PNG_16_TO_8;
+ info_ptr->bit_depth = 8;
+# else
+
+# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+ png_ptr->transformations |= PNG_SCALE_16_TO_8;
+ info_ptr->bit_depth = 8;
+# else
+
+ CONFIGURATION ERROR: you must enable at least one 16 to 8 method
+# endif
+# endif
+#endif /* !READ_16BIT */
}
+
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
+ info_ptr->color_type = (png_byte)(info_ptr->color_type |
+ PNG_COLOR_MASK_COLOR);
#endif
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
- if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
- info_ptr->bit_depth = 8;
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
+ info_ptr->color_type = (png_byte)(info_ptr->color_type &
+ ~PNG_COLOR_MASK_COLOR);
#endif
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
- if (png_ptr->transformations & PNG_GRAY_TO_RGB)
- info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
-#endif
-
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
- if (png_ptr->transformations & PNG_RGB_TO_GRAY)
- info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
-#endif
-
-#if defined(PNG_READ_DITHER_SUPPORTED)
- if (png_ptr->transformations & PNG_DITHER)
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+ if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
{
if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
- (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
- png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+ png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8)
{
info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
}
}
#endif
-#if defined(PNG_READ_PACK_SUPPORTED)
- if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
+ info_ptr->bit_depth == 8 &&
+ info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ info_ptr->bit_depth = 16;
+ }
+#endif
+
+#ifdef PNG_READ_PACK_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACK) != 0 &&
+ (info_ptr->bit_depth < 8))
info_ptr->bit_depth = 8;
#endif
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
info_ptr->channels = 1;
- else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+
+ else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
info_ptr->channels = 3;
+
else
info_ptr->channels = 1;
-#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
- if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
- info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0)
+ {
+ info_ptr->color_type = (png_byte)(info_ptr->color_type &
+ ~PNG_COLOR_MASK_ALPHA);
+ info_ptr->num_trans = 0;
+ }
#endif
- if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
info_ptr->channels++;
-#if defined(PNG_READ_FILLER_SUPPORTED)
+#ifdef PNG_READ_FILLER_SUPPORTED
/* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
- if ((png_ptr->transformations & PNG_FILLER) &&
- ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
- (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
+ if ((png_ptr->transformations & PNG_FILLER) != 0 &&
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY))
{
info_ptr->channels++;
- /* if adding a true alpha channel not just filler */
-#if !defined(PNG_1_0_X)
- if (png_ptr->transformations & PNG_ADD_ALPHA)
- info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
-#endif
+ /* If adding a true alpha channel not just filler */
+ if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
}
#endif
#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- if(png_ptr->transformations & PNG_USER_TRANSFORM)
- {
- if(info_ptr->bit_depth < png_ptr->user_transform_depth)
+ if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
+ {
+ if (png_ptr->user_transform_depth != 0)
info_ptr->bit_depth = png_ptr->user_transform_depth;
- if(info_ptr->channels < png_ptr->user_transform_channels)
+
+ if (png_ptr->user_transform_channels != 0)
info_ptr->channels = png_ptr->user_transform_channels;
- }
+ }
#endif
info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
- info_ptr->bit_depth);
+ info_ptr->bit_depth);
- info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width);
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
-#if !defined(PNG_READ_EXPAND_SUPPORTED)
- if(png_ptr)
+ /* Adding in 1.5.4: cache the above value in png_struct so that we can later
+ * check in png_rowbytes that the user buffer won't get overwritten. Note
+ * that the field is not always set - if png_read_update_info isn't called
+ * the application has to either not do any transforms or get the calculation
+ * right itself.
+ */
+ png_ptr->info_rowbytes = info_ptr->rowbytes;
+
+#ifndef PNG_READ_EXPAND_SUPPORTED
+ if (png_ptr != NULL)
return;
#endif
}
-/* Transform the row. The order of transformations is significant,
- * and is very touchy. If you add a transformation, take care to
- * decide how it fits in with the other transformations here.
- */
-void /* PRIVATE */
-png_do_read_transformations(png_structp png_ptr)
-{
- png_debug(1, "in png_do_read_transformations\n");
- if (png_ptr->row_buf == NULL)
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char msg[50];
-
- png_snprintf2(msg, 50,
- "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
- png_ptr->pass);
- png_error(png_ptr, msg);
-#else
- png_error(png_ptr, "NULL row buffer");
-#endif
- }
-#ifdef PNG_WARN_UNINITIALIZED_ROW
- if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
- /* Application has failed to call either png_read_start_image()
- * or png_read_update_info() after setting transforms that expand
- * pixels. This check added to libpng-1.2.19 */
-#if (PNG_WARN_UNINITIALIZED_ROW==1)
- png_error(png_ptr, "Uninitialized row");
-#else
- png_warning(png_ptr, "Uninitialized row");
-#endif
-#endif
-
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- if (png_ptr->transformations & PNG_EXPAND)
- {
- if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
- {
- png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
- png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
- }
- else
- {
- if (png_ptr->num_trans &&
- (png_ptr->transformations & PNG_EXPAND_tRNS))
- png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
- &(png_ptr->trans_values));
- else
- png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
- NULL);
- }
- }
-#endif
-
-#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
- if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
- png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
- PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
-#endif
-
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
- if (png_ptr->transformations & PNG_RGB_TO_GRAY)
- {
- int rgb_error =
- png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
- if(rgb_error)
- {
- png_ptr->rgb_to_gray_status=1;
- if((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
- PNG_RGB_TO_GRAY_WARN)
- png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
- if((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
- PNG_RGB_TO_GRAY_ERR)
- png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
- }
- }
-#endif
-
-/*
-From Andreas Dilger e-mail to png-implement, 26 March 1998:
-
- In most cases, the "simple transparency" should be done prior to doing
- gray-to-RGB, or you will have to test 3x as many bytes to check if a
- pixel is transparent. You would also need to make sure that the
- transparency information is upgraded to RGB.
-
- To summarize, the current flow is:
- - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
- with background "in place" if transparent,
- convert to RGB if necessary
- - Gray + alpha -> composite with gray background and remove alpha bytes,
- convert to RGB if necessary
-
- To support RGB backgrounds for gray images we need:
- - Gray + simple transparency -> convert to RGB + simple transparency, compare
- 3 or 6 bytes and composite with background
- "in place" if transparent (3x compare/pixel
- compared to doing composite with gray bkgrnd)
- - Gray + alpha -> convert to RGB + alpha, composite with background and
- remove alpha bytes (3x float operations/pixel
- compared with composite on gray background)
-
- Greg's change will do this. The reason it wasn't done before is for
- performance, as this increases the per-pixel operations. If we would check
- in advance if the background was gray or RGB, and position the gray-to-RGB
- transform appropriately, then it would save a lot of work/time.
- */
-
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
- /* if gray -> RGB, do so now only if background is non-gray; else do later
- * for performance reasons */
- if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
- !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
- png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- if ((png_ptr->transformations & PNG_BACKGROUND) &&
- ((png_ptr->num_trans != 0 ) ||
- (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
- png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
- &(png_ptr->trans_values), &(png_ptr->background)
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- , &(png_ptr->background_1),
- png_ptr->gamma_table, png_ptr->gamma_from_1,
- png_ptr->gamma_to_1, png_ptr->gamma_16_table,
- png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
- png_ptr->gamma_shift
-#endif
-);
-#endif
-
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if ((png_ptr->transformations & PNG_GAMMA) &&
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- !((png_ptr->transformations & PNG_BACKGROUND) &&
- ((png_ptr->num_trans != 0) ||
- (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
-#endif
- (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
- png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
- png_ptr->gamma_table, png_ptr->gamma_16_table,
- png_ptr->gamma_shift);
-#endif
-
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
- if (png_ptr->transformations & PNG_16_TO_8)
- png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_DITHER_SUPPORTED)
- if (png_ptr->transformations & PNG_DITHER)
- {
- png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
- png_ptr->palette_lookup, png_ptr->dither_index);
- if(png_ptr->row_info.rowbytes == (png_uint_32)0)
- png_error(png_ptr, "png_do_dither returned rowbytes=0");
- }
-#endif
-
-#if defined(PNG_READ_INVERT_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_MONO)
- png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_SHIFT_SUPPORTED)
- if (png_ptr->transformations & PNG_SHIFT)
- png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
- &(png_ptr->shift));
-#endif
-
-#if defined(PNG_READ_PACK_SUPPORTED)
- if (png_ptr->transformations & PNG_PACK)
- png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_BGR_SUPPORTED)
- if (png_ptr->transformations & PNG_BGR)
- png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
- /* if gray -> RGB, do so now only if we did not do so above */
- if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
- (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
- png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_FILLER_SUPPORTED)
- if (png_ptr->transformations & PNG_FILLER)
- png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
- (png_uint_32)png_ptr->filler, png_ptr->flags);
-#endif
-
-#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_ALPHA)
- png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_ALPHA)
- png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_SWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_BYTES)
- png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- if (png_ptr->transformations & PNG_USER_TRANSFORM)
- {
- if(png_ptr->read_user_transform_fn != NULL)
- (*(png_ptr->read_user_transform_fn)) /* user read transform function */
- (png_ptr, /* png_ptr */
- &(png_ptr->row_info), /* row_info: */
- /* png_uint_32 width; width of row */
- /* png_uint_32 rowbytes; number of bytes in row */
- /* png_byte color_type; color type of pixels */
- /* png_byte bit_depth; bit depth of samples */
- /* png_byte channels; number of channels (1-4) */
- /* png_byte pixel_depth; bits per pixel (depth*channels) */
- png_ptr->row_buf + 1); /* start of pixel data for row */
-#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
- if(png_ptr->user_transform_depth)
- png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
- if(png_ptr->user_transform_channels)
- png_ptr->row_info.channels = png_ptr->user_transform_channels;
-#endif
- png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
- png_ptr->row_info.channels);
- png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
- png_ptr->row_info.width);
- }
-#endif
-
-}
-
-#if defined(PNG_READ_PACK_SUPPORTED)
+#ifdef PNG_READ_PACK_SUPPORTED
/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
* without changing the actual values. Thus, if you had a row with
* a bit depth of 1, you would end up with bytes that only contained
* the numbers 0 or 1. If you would rather they contain 0 and 255, use
* png_do_shift() after this.
*/
-void /* PRIVATE */
+static void
png_do_unpack(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_unpack\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
-#else
+ png_debug(1, "in png_do_unpack");
+
if (row_info->bit_depth < 8)
-#endif
{
png_uint_32 i;
png_uint_32 row_width=row_info->width;
@@ -1518,17 +2158,19 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
{
case 1:
{
- png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
- png_bytep dp = row + (png_size_t)row_width - 1;
- png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
+ png_bytep sp = row + (size_t)((row_width - 1) >> 3);
+ png_bytep dp = row + (size_t)row_width - 1;
+ png_uint_32 shift = 7U - ((row_width + 7U) & 0x07);
for (i = 0; i < row_width; i++)
{
*dp = (png_byte)((*sp >> shift) & 0x01);
+
if (shift == 7)
{
shift = 0;
sp--;
}
+
else
shift++;
@@ -1536,20 +2178,23 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
}
break;
}
+
case 2:
{
- png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
- png_bytep dp = row + (png_size_t)row_width - 1;
- png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ png_bytep sp = row + (size_t)((row_width - 1) >> 2);
+ png_bytep dp = row + (size_t)row_width - 1;
+ png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1);
for (i = 0; i < row_width; i++)
{
*dp = (png_byte)((*sp >> shift) & 0x03);
+
if (shift == 6)
{
shift = 0;
sp--;
}
+
else
shift += 2;
@@ -1557,19 +2202,22 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
}
break;
}
+
case 4:
{
- png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
- png_bytep dp = row + (png_size_t)row_width - 1;
- png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ png_bytep sp = row + (size_t)((row_width - 1) >> 1);
+ png_bytep dp = row + (size_t)row_width - 1;
+ png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2);
for (i = 0; i < row_width; i++)
{
*dp = (png_byte)((*sp >> shift) & 0x0f);
+
if (shift == 4)
{
shift = 0;
sp--;
}
+
else
shift = 4;
@@ -1577,6 +2225,9 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
}
break;
}
+
+ default:
+ break;
}
row_info->bit_depth = 8;
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
@@ -1585,164 +2236,201 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
}
#endif
-#if defined(PNG_READ_SHIFT_SUPPORTED)
+#ifdef PNG_READ_SHIFT_SUPPORTED
/* Reverse the effects of png_do_shift. This routine merely shifts the
* pixels back to their significant bits values. Thus, if you have
* a row of bit depth 8, but only 5 are significant, this will shift
* the values back to 0 through 31.
*/
-void /* PRIVATE */
-png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
+static void
+png_do_unshift(png_row_infop row_info, png_bytep row,
+ png_const_color_8p sig_bits)
{
- png_debug(1, "in png_do_unshift\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL && sig_bits != NULL &&
-#endif
- row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ int color_type;
+
+ png_debug(1, "in png_do_unshift");
+
+ /* The palette case has already been handled in the _init routine. */
+ color_type = row_info->color_type;
+
+ if (color_type != PNG_COLOR_TYPE_PALETTE)
{
int shift[4];
int channels = 0;
- int c;
- png_uint_16 value = 0;
- png_uint_32 row_width = row_info->width;
+ int bit_depth = row_info->bit_depth;
- if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
{
- shift[channels++] = row_info->bit_depth - sig_bits->red;
- shift[channels++] = row_info->bit_depth - sig_bits->green;
- shift[channels++] = row_info->bit_depth - sig_bits->blue;
+ shift[channels++] = bit_depth - sig_bits->red;
+ shift[channels++] = bit_depth - sig_bits->green;
+ shift[channels++] = bit_depth - sig_bits->blue;
}
+
else
{
- shift[channels++] = row_info->bit_depth - sig_bits->gray;
- }
- if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
- {
- shift[channels++] = row_info->bit_depth - sig_bits->alpha;
+ shift[channels++] = bit_depth - sig_bits->gray;
}
- for (c = 0; c < channels; c++)
+ if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
{
- if (shift[c] <= 0)
- shift[c] = 0;
- else
- value = 1;
+ shift[channels++] = bit_depth - sig_bits->alpha;
}
- if (!value)
- return;
-
- switch (row_info->bit_depth)
{
+ int c, have_shift;
+
+ for (c = have_shift = 0; c < channels; ++c)
+ {
+ /* A shift of more than the bit depth is an error condition but it
+ * gets ignored here.
+ */
+ if (shift[c] <= 0 || shift[c] >= bit_depth)
+ shift[c] = 0;
+
+ else
+ have_shift = 1;
+ }
+
+ if (have_shift == 0)
+ return;
+ }
+
+ switch (bit_depth)
+ {
+ default:
+ /* Must be 1bpp gray: should not be here! */
+ /* NOTREACHED */
+ break;
+
case 2:
+ /* Must be 2bpp gray */
+ /* assert(channels == 1 && shift[0] == 1) */
{
- png_bytep bp;
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
+ png_bytep bp = row;
+ png_bytep bp_end = bp + row_info->rowbytes;
- for (bp = row, i = 0; i < istop; i++)
+ while (bp < bp_end)
{
- *bp >>= 1;
- *bp++ &= 0x55;
+ int b = (*bp >> 1) & 0x55;
+ *bp++ = (png_byte)b;
}
break;
}
+
case 4:
+ /* Must be 4bpp gray */
+ /* assert(channels == 1) */
{
png_bytep bp = row;
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
- png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
- (png_byte)((int)0xf >> shift[0]));
+ png_bytep bp_end = bp + row_info->rowbytes;
+ int gray_shift = shift[0];
+ int mask = 0xf >> gray_shift;
- for (i = 0; i < istop; i++)
+ mask |= mask << 4;
+
+ while (bp < bp_end)
{
- *bp >>= shift[0];
- *bp++ &= mask;
+ int b = (*bp >> gray_shift) & mask;
+ *bp++ = (png_byte)b;
}
break;
}
+
case 8:
+ /* Single byte components, G, GA, RGB, RGBA */
{
png_bytep bp = row;
- png_uint_32 i;
- png_uint_32 istop = row_width * channels;
+ png_bytep bp_end = bp + row_info->rowbytes;
+ int channel = 0;
- for (i = 0; i < istop; i++)
+ while (bp < bp_end)
{
- *bp++ >>= shift[i%channels];
+ int b = *bp >> shift[channel];
+ if (++channel >= channels)
+ channel = 0;
+ *bp++ = (png_byte)b;
}
break;
}
+
+#ifdef PNG_READ_16BIT_SUPPORTED
case 16:
+ /* Double byte components, G, GA, RGB, RGBA */
{
png_bytep bp = row;
- png_uint_32 i;
- png_uint_32 istop = channels * row_width;
+ png_bytep bp_end = bp + row_info->rowbytes;
+ int channel = 0;
- for (i = 0; i < istop; i++)
+ while (bp < bp_end)
{
- value = (png_uint_16)((*bp << 8) + *(bp + 1));
- value >>= shift[i%channels];
+ int value = (bp[0] << 8) + bp[1];
+
+ value >>= shift[channel];
+ if (++channel >= channels)
+ channel = 0;
*bp++ = (png_byte)(value >> 8);
- *bp++ = (png_byte)(value & 0xff);
+ *bp++ = (png_byte)value;
}
break;
}
+#endif
}
}
}
#endif
-#if defined(PNG_READ_16_TO_8_SUPPORTED)
-/* chop rows of bit depth 16 down to 8 */
-void /* PRIVATE */
-png_do_chop(png_row_infop row_info, png_bytep row)
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+/* Scale rows of bit depth 16 down to 8 accurately */
+static void
+png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_chop\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
-#else
+ png_debug(1, "in png_do_scale_16_to_8");
+
if (row_info->bit_depth == 16)
-#endif
{
- png_bytep sp = row;
- png_bytep dp = row;
- png_uint_32 i;
- png_uint_32 istop = row_info->width * row_info->channels;
+ png_bytep sp = row; /* source */
+ png_bytep dp = row; /* destination */
+ png_bytep ep = sp + row_info->rowbytes; /* end+1 */
- for (i = 0; i> 8)) >> 8;
- *
- * Approximate calculation with shift/add instead of multiply/divide:
- * *dp = ((((png_uint_32)(*sp) << 8) |
- * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
- *
- * What we actually do to avoid extra shifting and conversion:
- */
+ /* The input is an array of 16-bit components, these must be scaled to
+ * 8 bits each. For a 16-bit value V the required value (from the PNG
+ * specification) is:
+ *
+ * (V * 255) / 65535
+ *
+ * This reduces to round(V / 257), or floor((V + 128.5)/257)
+ *
+ * Represent V as the two byte value vhi.vlo. Make a guess that the
+ * result is the top byte of V, vhi, then the correction to this value
+ * is:
+ *
+ * error = floor(((V-vhi.vhi) + 128.5) / 257)
+ * = floor(((vlo-vhi) + 128.5) / 257)
+ *
+ * This can be approximated using integer arithmetic (and a signed
+ * shift):
+ *
+ * error = (vlo-vhi+128) >> 8;
+ *
+ * The approximate differs from the exact answer only when (vlo-vhi) is
+ * 128; it then gives a correction of +1 when the exact correction is
+ * 0. This gives 128 errors. The exact answer (correct for all 16-bit
+ * input values) is:
+ *
+ * error = (vlo-vhi+128)*65535 >> 24;
+ *
+ * An alternative arithmetic calculation which also gives no errors is:
+ *
+ * (V * 255 + 32895) >> 16
+ */
- *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
-#else
- /* Simply discard the low order byte */
- *dp = *sp;
-#endif
+ png_int_32 tmp = *sp++; /* must be signed! */
+ tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;
+ *dp++ = (png_byte)tmp;
}
+
row_info->bit_depth = 8;
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
row_info->rowbytes = row_info->width * row_info->channels;
@@ -1750,222 +2438,257 @@ png_do_chop(png_row_infop row_info, png_bytep row)
}
#endif
-#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
-void /* PRIVATE */
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+static void
+/* Simply discard the low byte. This was the default behavior prior
+ * to libpng-1.5.4.
+ */
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_chop");
+
+ if (row_info->bit_depth == 16)
+ {
+ png_bytep sp = row; /* source */
+ png_bytep dp = row; /* destination */
+ png_bytep ep = sp + row_info->rowbytes; /* end+1 */
+
+ while (sp < ep)
+ {
+ *dp++ = *sp;
+ sp += 2; /* skip low byte */
+ }
+
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
+static void
png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_read_swap_alpha\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_uint_32 row_width = row_info->width;
+
+ png_debug(1, "in png_do_read_swap_alpha");
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
- png_uint_32 row_width = row_info->width;
- if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ /* This converts from RGBA to ARGB */
+ if (row_info->bit_depth == 8)
{
- /* This converts from RGBA to ARGB */
- if (row_info->bit_depth == 8)
- {
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_byte save;
- png_uint_32 i;
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
- for (i = 0; i < row_width; i++)
- {
- save = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = save;
- }
- }
- /* This converts from RRGGBBAA to AARRGGBB */
- else
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_byte save[2];
- png_uint_32 i;
-
- for (i = 0; i < row_width; i++)
- {
- save[0] = *(--sp);
- save[1] = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = save[0];
- *(--dp) = save[1];
- }
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
}
}
- else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ /* This converts from RRGGBBAA to AARRGGBB */
+ else
{
- /* This converts from GA to AG */
- if (row_info->bit_depth == 8)
- {
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_byte save;
- png_uint_32 i;
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
- for (i = 0; i < row_width; i++)
- {
- save = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = save;
- }
- }
- /* This converts from GGAA to AAGG */
- else
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_byte save[2];
- png_uint_32 i;
-
- for (i = 0; i < row_width; i++)
- {
- save[0] = *(--sp);
- save[1] = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = save[0];
- *(--dp) = save[1];
- }
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
}
}
+#endif
+ }
+
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from GA to AG */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ /* This converts from GGAA to AAGG */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+#endif
}
}
#endif
-#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
-void /* PRIVATE */
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+static void
png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_read_invert_alpha\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_uint_32 row_width;
+ png_debug(1, "in png_do_read_invert_alpha");
+
+ row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
- png_uint_32 row_width = row_info->width;
- if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ if (row_info->bit_depth == 8)
{
/* This inverts the alpha channel in RGBA */
- if (row_info->bit_depth == 8)
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_uint_32 i;
+ *(--dp) = (png_byte)(255 - *(--sp));
- for (i = 0; i < row_width; i++)
- {
- *(--dp) = (png_byte)(255 - *(--sp));
-
-/* This does nothing:
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- We can replace it with:
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
*/
- sp-=3;
- dp=sp;
- }
- }
- /* This inverts the alpha channel in RRGGBBAA */
- else
- {
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_uint_32 i;
-
- for (i = 0; i < row_width; i++)
- {
- *(--dp) = (png_byte)(255 - *(--sp));
- *(--dp) = (png_byte)(255 - *(--sp));
-
-/* This does nothing:
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
- We can replace it with:
-*/
- sp-=6;
- dp=sp;
- }
+ sp-=3;
+ dp=sp;
}
}
- else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
+*/
+ sp-=6;
+ dp=sp;
+ }
+ }
+#endif
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
{
/* This inverts the alpha channel in GA */
- if (row_info->bit_depth == 8)
- {
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_uint_32 i;
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
- for (i = 0; i < row_width; i++)
- {
- *(--dp) = (png_byte)(255 - *(--sp));
- *(--dp) = *(--sp);
- }
- }
- /* This inverts the alpha channel in GGAA */
- else
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row + row_info->rowbytes;
- png_bytep dp = sp;
- png_uint_32 i;
-
- for (i = 0; i < row_width; i++)
- {
- *(--dp) = (png_byte)(255 - *(--sp));
- *(--dp) = (png_byte)(255 - *(--sp));
-/*
- *(--dp) = *(--sp);
- *(--dp) = *(--sp);
-*/
- sp-=2;
- dp=sp;
- }
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = *(--sp);
}
}
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ else
+ {
+ /* This inverts the alpha channel in GGAA */
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+/*
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+*/
+ sp-=2;
+ dp=sp;
+ }
+ }
+#endif
}
}
#endif
-#if defined(PNG_READ_FILLER_SUPPORTED)
+#ifdef PNG_READ_FILLER_SUPPORTED
/* Add filler channel if we have RGB color */
-void /* PRIVATE */
+static void
png_do_read_filler(png_row_infop row_info, png_bytep row,
- png_uint_32 filler, png_uint_32 flags)
+ png_uint_32 filler, png_uint_32 flags)
{
png_uint_32 i;
png_uint_32 row_width = row_info->width;
- png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
- png_byte lo_filler = (png_byte)(filler & 0xff);
-
- png_debug(1, "in png_do_read_filler\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
+#ifdef PNG_READ_16BIT_SUPPORTED
+ png_byte hi_filler = (png_byte)(filler>>8);
#endif
+ png_byte lo_filler = (png_byte)filler;
+
+ png_debug(1, "in png_do_read_filler");
+
+ if (
row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
- if(row_info->bit_depth == 8)
+ if (row_info->bit_depth == 8)
{
- /* This changes the data from G to GX */
- if (flags & PNG_FLAG_FILLER_AFTER)
+ if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
{
- png_bytep sp = row + (png_size_t)row_width;
- png_bytep dp = sp + (png_size_t)row_width;
+ /* This changes the data from G to GX */
+ png_bytep sp = row + (size_t)row_width;
+ png_bytep dp = sp + (size_t)row_width;
for (i = 1; i < row_width; i++)
{
*(--dp) = lo_filler;
@@ -1976,11 +2699,12 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
row_info->pixel_depth = 16;
row_info->rowbytes = row_width * 2;
}
- /* This changes the data from G to XG */
+
else
{
- png_bytep sp = row + (png_size_t)row_width;
- png_bytep dp = sp + (png_size_t)row_width;
+ /* This changes the data from G to XG */
+ png_bytep sp = row + (size_t)row_width;
+ png_bytep dp = sp + (size_t)row_width;
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
@@ -1991,53 +2715,57 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
row_info->rowbytes = row_width * 2;
}
}
- else if(row_info->bit_depth == 16)
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ else if (row_info->bit_depth == 16)
{
- /* This changes the data from GG to GGXX */
- if (flags & PNG_FLAG_FILLER_AFTER)
+ if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
{
- png_bytep sp = row + (png_size_t)row_width * 2;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes the data from GG to GGXX */
+ png_bytep sp = row + (size_t)row_width * 2;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 1; i < row_width; i++)
{
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
+ *(--dp) = lo_filler;
*(--dp) = hi_filler;
- *(--dp) = lo_filler;
row_info->channels = 2;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
}
- /* This changes the data from GG to XXGG */
+
else
{
- png_bytep sp = row + (png_size_t)row_width * 2;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes the data from GG to XXGG */
+ png_bytep sp = row + (size_t)row_width * 2;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
*(--dp) = *(--sp);
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
}
row_info->channels = 2;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
}
}
+#endif
} /* COLOR_TYPE == GRAY */
else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
{
- if(row_info->bit_depth == 8)
+ if (row_info->bit_depth == 8)
{
- /* This changes the data from RGB to RGBX */
- if (flags & PNG_FLAG_FILLER_AFTER)
+ if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
{
- png_bytep sp = row + (png_size_t)row_width * 3;
- png_bytep dp = sp + (png_size_t)row_width;
+ /* This changes the data from RGB to RGBX */
+ png_bytep sp = row + (size_t)row_width * 3;
+ png_bytep dp = sp + (size_t)row_width;
for (i = 1; i < row_width; i++)
{
*(--dp) = lo_filler;
@@ -2050,11 +2778,12 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
}
- /* This changes the data from RGB to XRGB */
+
else
{
- png_bytep sp = row + (png_size_t)row_width * 3;
- png_bytep dp = sp + (png_size_t)row_width;
+ /* This changes the data from RGB to XRGB */
+ png_bytep sp = row + (size_t)row_width * 3;
+ png_bytep dp = sp + (size_t)row_width;
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
@@ -2067,17 +2796,19 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
row_info->rowbytes = row_width * 4;
}
}
- else if(row_info->bit_depth == 16)
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+ else if (row_info->bit_depth == 16)
{
- /* This changes the data from RRGGBB to RRGGBBXX */
- if (flags & PNG_FLAG_FILLER_AFTER)
+ if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
{
- png_bytep sp = row + (png_size_t)row_width * 6;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes the data from RRGGBB to RRGGBBXX */
+ png_bytep sp = row + (size_t)row_width * 6;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 1; i < row_width; i++)
{
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
@@ -2085,17 +2816,18 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
+ *(--dp) = lo_filler;
*(--dp) = hi_filler;
- *(--dp) = lo_filler;
row_info->channels = 4;
row_info->pixel_depth = 64;
row_info->rowbytes = row_width * 8;
}
- /* This changes the data from RRGGBB to XXRRGGBB */
+
else
{
- png_bytep sp = row + (png_size_t)row_width * 6;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes the data from RRGGBB to XXRRGGBB */
+ png_bytep sp = row + (size_t)row_width * 6;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
@@ -2104,39 +2836,40 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
}
+
row_info->channels = 4;
row_info->pixel_depth = 64;
row_info->rowbytes = row_width * 8;
}
}
+#endif
} /* COLOR_TYPE == RGB */
}
#endif
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
-/* expand grayscale files to RGB, with or without alpha */
-void /* PRIVATE */
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+/* Expand grayscale files to RGB, with or without alpha */
+static void
png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
{
png_uint_32 i;
png_uint_32 row_width = row_info->width;
- png_debug(1, "in png_do_gray_to_rgb\n");
+ png_debug(1, "in png_do_gray_to_rgb");
+
if (row_info->bit_depth >= 8 &&
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0)
{
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
if (row_info->bit_depth == 8)
{
- png_bytep sp = row + (png_size_t)row_width - 1;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes G to RGB */
+ png_bytep sp = row + (size_t)row_width - 1;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 0; i < row_width; i++)
{
*(dp--) = *sp;
@@ -2144,10 +2877,12 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
*(dp--) = *(sp--);
}
}
+
else
{
- png_bytep sp = row + (png_size_t)row_width * 2 - 1;
- png_bytep dp = sp + (png_size_t)row_width * 4;
+ /* This changes GG to RRGGBB */
+ png_bytep sp = row + (size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (size_t)row_width * 4;
for (i = 0; i < row_width; i++)
{
*(dp--) = *sp;
@@ -2159,12 +2894,14 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
}
}
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if (row_info->bit_depth == 8)
{
- png_bytep sp = row + (png_size_t)row_width * 2 - 1;
- png_bytep dp = sp + (png_size_t)row_width * 2;
+ /* This changes GA to RGBA */
+ png_bytep sp = row + (size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (size_t)row_width * 2;
for (i = 0; i < row_width; i++)
{
*(dp--) = *(sp--);
@@ -2173,10 +2910,12 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
*(dp--) = *(sp--);
}
}
+
else
{
- png_bytep sp = row + (png_size_t)row_width * 4 - 1;
- png_bytep dp = sp + (png_size_t)row_width * 4;
+ /* This changes GGAA to RRGGBBAA */
+ png_bytep sp = row + (size_t)row_width * 4 - 1;
+ png_bytep dp = sp + (size_t)row_width * 4;
for (i = 0; i < row_width; i++)
{
*(dp--) = *(sp--);
@@ -2190,823 +2929,513 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
}
}
}
- row_info->channels += (png_byte)2;
+ row_info->channels = (png_byte)(row_info->channels + 2);
row_info->color_type |= PNG_COLOR_MASK_COLOR;
row_info->pixel_depth = (png_byte)(row_info->channels *
- row_info->bit_depth);
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ row_info->bit_depth);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
}
#endif
-#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-/* reduce RGB files to grayscale, with or without alpha
- * using the equation given in Poynton's ColorFAQ at
- *
- * Copyright (c) 1998-01-04 Charles Poynton poynton at inforamp.net
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+/* Reduce RGB files to grayscale, with or without alpha
+ * using the equation given in Poynton's ColorFAQ of 1998-01-04 at
+ * (THIS LINK IS DEAD June 2008 but
+ * versions dated 1998 through November 2002 have been archived at
+ * https://web.archive.org/web/20000816232553/www.inforamp.net/
+ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )
+ * Charles Poynton poynton at poynton.com
*
* Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
*
- * We approximate this with
- *
- * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
- *
* which can be expressed with integers as
*
* Y = (6969 * R + 23434 * G + 2365 * B)/32768
*
- * The calculation is to be done in a linear colorspace.
+ * Poynton's current link (as of January 2003 through July 2011):
+ *
+ * has changed the numbers slightly:
*
- * Other integer coefficents can be used via png_set_rgb_to_gray().
+ * Y = 0.2126*R + 0.7152*G + 0.0722*B
+ *
+ * which can be expressed with integers as
+ *
+ * Y = (6966 * R + 23436 * G + 2366 * B)/32768
+ *
+ * Historically, however, libpng uses numbers derived from the ITU-R Rec 709
+ * end point chromaticities and the D65 white point. Depending on the
+ * precision used for the D65 white point this produces a variety of different
+ * numbers, however if the four decimal place value used in ITU-R Rec 709 is
+ * used (0.3127,0.3290) the Y calculation would be:
+ *
+ * Y = (6968 * R + 23435 * G + 2366 * B)/32768
+ *
+ * While this is correct the rounding results in an overflow for white, because
+ * the sum of the rounded coefficients is 32769, not 32768. Consequently
+ * libpng uses, instead, the closest non-overflowing approximation:
+ *
+ * Y = (6968 * R + 23434 * G + 2366 * B)/32768
+ *
+ * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk
+ * (including an sRGB chunk) then the chromaticities are used to calculate the
+ * coefficients. See the chunk handling in pngrutil.c for more information.
+ *
+ * In all cases the calculation is to be done in a linear colorspace. If no
+ * gamma information is available to correct the encoding of the original RGB
+ * values this results in an implicit assumption that the original PNG RGB
+ * values were linear.
+ *
+ * Other integer coefficients can be used via png_set_rgb_to_gray(). Because
+ * the API takes just red and green coefficients the blue coefficient is
+ * calculated to make the sum 32768. This will result in different rounding
+ * to that used above.
*/
-int /* PRIVATE */
-png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
-
+static int
+png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)
{
- png_uint_32 i;
-
- png_uint_32 row_width = row_info->width;
int rgb_error = 0;
- png_debug(1, "in png_do_rgb_to_gray\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ png_debug(1, "in png_do_rgb_to_gray");
+
+ if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 &&
+ (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
- png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
+ png_uint_32 bc = 32768 - rc - gc;
+ png_uint_32 row_width = row_info->width;
+ int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ if (row_info->bit_depth == 8)
{
- if (row_info->bit_depth == 8)
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ /* Notice that gamma to/from 1 are not necessarily inverses (if
+ * there is an overall gamma correction). Prior to 1.5.5 this code
+ * checked the linearized values for equality; this doesn't match
+ * the documentation, the original values must be checked.
+ */
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
{
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
- for (i = 0; i < row_width; i++)
- {
- png_byte red = png_ptr->gamma_to_1[*(sp++)];
- png_byte green = png_ptr->gamma_to_1[*(sp++)];
- png_byte blue = png_ptr->gamma_to_1[*(sp++)];
- if(red != green || red != blue)
- {
- rgb_error |= 1;
- *(dp++) = png_ptr->gamma_from_1[
- (rc*red+gc*green+bc*blue)>>15];
- }
- else
- *(dp++) = *(sp-1);
- }
- }
- else
-#endif
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+
+ if (red != green || red != blue)
{
- png_byte red = *(sp++);
- png_byte green = *(sp++);
- png_byte blue = *(sp++);
- if(red != green || red != blue)
- {
- rgb_error |= 1;
- *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
- }
- else
- *(dp++) = *(sp-1);
+ red = png_ptr->gamma_to_1[red];
+ green = png_ptr->gamma_to_1[green];
+ blue = png_ptr->gamma_to_1[blue];
+
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1[
+ (rc*red + gc*green + bc*blue + 16384)>>15];
}
+
+ else
+ {
+ /* If there is no overall correction the table will not be
+ * set.
+ */
+ if (png_ptr->gamma_table != NULL)
+ red = png_ptr->gamma_table[red];
+
+ *(dp++) = red;
+ }
+
+ if (have_alpha != 0)
+ *(dp++) = *(sp++);
}
}
-
- else /* RGB bit_depth == 16 */
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_16_to_1 != NULL &&
- png_ptr->gamma_16_from_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_uint_16 red, green, blue, w;
-
- red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
-
- if(red == green && red == blue)
- w = red;
- else
- {
- png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
- png_ptr->gamma_shift][red>>8];
- png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
- png_ptr->gamma_shift][green>>8];
- png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
- png_ptr->gamma_shift][blue>>8];
- png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
- + bc*blue_1)>>15);
- w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
- png_ptr->gamma_shift][gray16 >> 8];
- rgb_error |= 1;
- }
-
- *(dp++) = (png_byte)((w>>8) & 0xff);
- *(dp++) = (png_byte)(w & 0xff);
- }
- }
- else
+ else
#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+
+ if (red != green || red != blue)
{
- png_uint_16 red, green, blue, gray16;
-
- red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
-
- if(red != green || red != blue)
- rgb_error |= 1;
- gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = (png_byte)((gray16>>8) & 0xff);
- *(dp++) = (png_byte)(gray16 & 0xff);
+ rgb_error |= 1;
+ /* NOTE: this is the historical approach which simply
+ * truncates the results.
+ */
+ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
}
+
+ else
+ *(dp++) = red;
+
+ if (have_alpha != 0)
+ *(dp++) = *(sp++);
}
}
}
- if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+
+ else /* RGB bit_depth == 16 */
{
- if (row_info->bit_depth == 8)
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)
{
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_byte red = png_ptr->gamma_to_1[*(sp++)];
- png_byte green = png_ptr->gamma_to_1[*(sp++)];
- png_byte blue = png_ptr->gamma_to_1[*(sp++)];
- if(red != green || red != blue)
- rgb_error |= 1;
- *(dp++) = png_ptr->gamma_from_1
- [(rc*red + gc*green + bc*blue)>>15];
- *(dp++) = *(sp++); /* alpha */
- }
- }
- else
-#endif
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_byte red = *(sp++);
- png_byte green = *(sp++);
- png_byte blue = *(sp++);
- if(red != green || red != blue)
- rgb_error |= 1;
- *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = *(sp++); /* alpha */
- }
- }
- }
- else /* RGBA bit_depth == 16 */
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_16_to_1 != NULL &&
- png_ptr->gamma_16_from_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_uint_16 red, green, blue, w;
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
- red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+ png_byte hi,lo;
+
+ hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo));
+
+ if (red == green && red == blue)
+ {
+ if (png_ptr->gamma_16_table != NULL)
+ w = png_ptr->gamma_16_table[(red & 0xff)
+ >> png_ptr->gamma_shift][red >> 8];
- if(red == green && red == blue)
- w = red;
else
- {
- png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
- png_ptr->gamma_shift][red>>8];
- png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
- png_ptr->gamma_shift][green>>8];
- png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
- png_ptr->gamma_shift][blue>>8];
- png_uint_16 gray16 = (png_uint_16)((rc * red_1
- + gc * green_1 + bc * blue_1)>>15);
- w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
- png_ptr->gamma_shift][gray16 >> 8];
- rgb_error |= 1;
- }
+ w = red;
+ }
- *(dp++) = (png_byte)((w>>8) & 0xff);
- *(dp++) = (png_byte)(w & 0xff);
- *(dp++) = *(sp++); /* alpha */
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff)
+ >> png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 =
+ png_ptr->gamma_16_to_1[(green & 0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff)
+ >> png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
+ + bc*blue_1 + 16384)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+
+ if (have_alpha != 0)
+ {
+ *(dp++) = *(sp++);
*(dp++) = *(sp++);
}
}
- else
+ }
+ else
#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
+ png_uint_16 red, green, blue, gray16;
+ png_byte hi,lo;
+
+ hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo));
+
+ if (red != green || red != blue)
+ rgb_error |= 1;
+
+ /* From 1.5.5 in the 16-bit case do the accurate conversion even
+ * in the 'fast' case - this is because this is where the code
+ * ends up when handling linear 16-bit data.
+ */
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>
+ 15);
+ *(dp++) = (png_byte)((gray16 >> 8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
+
+ if (have_alpha != 0)
{
- png_uint_16 red, green, blue, gray16;
- red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
- green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
- blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
- if(red != green || red != blue)
- rgb_error |= 1;
- gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = (png_byte)((gray16>>8) & 0xff);
- *(dp++) = (png_byte)(gray16 & 0xff);
- *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
*(dp++) = *(sp++);
}
}
}
}
- row_info->channels -= (png_byte)2;
- row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
+
+ row_info->channels = (png_byte)(row_info->channels - 2);
+ row_info->color_type = (png_byte)(row_info->color_type &
+ ~PNG_COLOR_MASK_COLOR);
row_info->pixel_depth = (png_byte)(row_info->channels *
- row_info->bit_depth);
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ row_info->bit_depth);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
return rgb_error;
}
#endif
-/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
- * large of png_color. This lets grayscale images be treated as
- * paletted. Most useful for gamma correction and simplification
- * of code.
- */
-void PNGAPI
-png_build_grayscale_palette(int bit_depth, png_colorp palette)
-{
- int num_palette;
- int color_inc;
- int i;
- int v;
-
- png_debug(1, "in png_do_build_grayscale_palette\n");
- if (palette == NULL)
- return;
-
- switch (bit_depth)
- {
- case 1:
- num_palette = 2;
- color_inc = 0xff;
- break;
- case 2:
- num_palette = 4;
- color_inc = 0x55;
- break;
- case 4:
- num_palette = 16;
- color_inc = 0x11;
- break;
- case 8:
- num_palette = 256;
- color_inc = 1;
- break;
- default:
- num_palette = 0;
- color_inc = 0;
- break;
- }
-
- for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
- {
- palette[i].red = (png_byte)v;
- palette[i].green = (png_byte)v;
- palette[i].blue = (png_byte)v;
- }
-}
-
-/* This function is currently unused. Do we really need it? */
-#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
-void /* PRIVATE */
-png_correct_palette(png_structp png_ptr, png_colorp palette,
- int num_palette)
-{
- png_debug(1, "in png_correct_palette\n");
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
- defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
- if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
- {
- png_color back, back_1;
-
- if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
- {
- back.red = png_ptr->gamma_table[png_ptr->background.red];
- back.green = png_ptr->gamma_table[png_ptr->background.green];
- back.blue = png_ptr->gamma_table[png_ptr->background.blue];
-
- back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
- back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
- back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
- }
- else
- {
- double g;
-
- g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
-
- if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
- fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
- {
- back.red = png_ptr->background.red;
- back.green = png_ptr->background.green;
- back.blue = png_ptr->background.blue;
- }
- else
- {
- back.red =
- (png_byte)(pow((double)png_ptr->background.red/255, g) *
- 255.0 + 0.5);
- back.green =
- (png_byte)(pow((double)png_ptr->background.green/255, g) *
- 255.0 + 0.5);
- back.blue =
- (png_byte)(pow((double)png_ptr->background.blue/255, g) *
- 255.0 + 0.5);
- }
-
- g = 1.0 / png_ptr->background_gamma;
-
- back_1.red =
- (png_byte)(pow((double)png_ptr->background.red/255, g) *
- 255.0 + 0.5);
- back_1.green =
- (png_byte)(pow((double)png_ptr->background.green/255, g) *
- 255.0 + 0.5);
- back_1.blue =
- (png_byte)(pow((double)png_ptr->background.blue/255, g) *
- 255.0 + 0.5);
- }
-
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- {
- png_uint_32 i;
-
- for (i = 0; i < (png_uint_32)num_palette; i++)
- {
- if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
- {
- palette[i] = back;
- }
- else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
- {
- png_byte v, w;
-
- v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
- png_composite(w, v, png_ptr->trans[i], back_1.red);
- palette[i].red = png_ptr->gamma_from_1[w];
-
- v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
- png_composite(w, v, png_ptr->trans[i], back_1.green);
- palette[i].green = png_ptr->gamma_from_1[w];
-
- v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
- png_composite(w, v, png_ptr->trans[i], back_1.blue);
- palette[i].blue = png_ptr->gamma_from_1[w];
- }
- else
- {
- palette[i].red = png_ptr->gamma_table[palette[i].red];
- palette[i].green = png_ptr->gamma_table[palette[i].green];
- palette[i].blue = png_ptr->gamma_table[palette[i].blue];
- }
- }
- }
- else
- {
- int i;
-
- for (i = 0; i < num_palette; i++)
- {
- if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
- {
- palette[i] = back;
- }
- else
- {
- palette[i].red = png_ptr->gamma_table[palette[i].red];
- palette[i].green = png_ptr->gamma_table[palette[i].green];
- palette[i].blue = png_ptr->gamma_table[palette[i].blue];
- }
- }
- }
- }
- else
-#endif
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (png_ptr->transformations & PNG_GAMMA)
- {
- int i;
-
- for (i = 0; i < num_palette; i++)
- {
- palette[i].red = png_ptr->gamma_table[palette[i].red];
- palette[i].green = png_ptr->gamma_table[palette[i].green];
- palette[i].blue = png_ptr->gamma_table[palette[i].blue];
- }
- }
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- else
-#endif
-#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->transformations & PNG_BACKGROUND)
- {
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- {
- png_color back;
-
- back.red = (png_byte)png_ptr->background.red;
- back.green = (png_byte)png_ptr->background.green;
- back.blue = (png_byte)png_ptr->background.blue;
-
- for (i = 0; i < (int)png_ptr->num_trans; i++)
- {
- if (png_ptr->trans[i] == 0)
- {
- palette[i].red = back.red;
- palette[i].green = back.green;
- palette[i].blue = back.blue;
- }
- else if (png_ptr->trans[i] != 0xff)
- {
- png_composite(palette[i].red, png_ptr->palette[i].red,
- png_ptr->trans[i], back.red);
- png_composite(palette[i].green, png_ptr->palette[i].green,
- png_ptr->trans[i], back.green);
- png_composite(palette[i].blue, png_ptr->palette[i].blue,
- png_ptr->trans[i], back.blue);
- }
- }
- }
- else /* assume grayscale palette (what else could it be?) */
- {
- int i;
-
- for (i = 0; i < num_palette; i++)
- {
- if (i == (png_byte)png_ptr->trans_values.gray)
- {
- palette[i].red = (png_byte)png_ptr->background.red;
- palette[i].green = (png_byte)png_ptr->background.green;
- palette[i].blue = (png_byte)png_ptr->background.blue;
- }
- }
- }
- }
-#endif
-}
-#endif
-
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
/* Replace any alpha or transparency with the supplied background color.
* "background" is already in the screen gamma, while "background_1" is
* at a gamma of 1.0. Paletted files have already been taken care of.
*/
-void /* PRIVATE */
-png_do_background(png_row_infop row_info, png_bytep row,
- png_color_16p trans_values, png_color_16p background
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- , png_color_16p background_1,
- png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
- png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
- png_uint_16pp gamma_16_to_1, int gamma_shift
-#endif
- )
+static void
+png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
{
- png_bytep sp, dp;
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ png_const_bytep gamma_table = png_ptr->gamma_table;
+ png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;
+ png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;
+ png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;
+ png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;
+ png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;
+ int gamma_shift = png_ptr->gamma_shift;
+ int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
+#endif
+
+ png_bytep sp;
png_uint_32 i;
- png_uint_32 row_width=row_info->width;
+ png_uint_32 row_width = row_info->width;
int shift;
- png_debug(1, "in png_do_background\n");
- if (background != NULL &&
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
- (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
+ png_debug(1, "in png_do_compose");
+
+ switch (row_info->color_type)
{
- switch (row_info->color_type)
+ case PNG_COLOR_TYPE_GRAY:
{
- case PNG_COLOR_TYPE_GRAY:
+ switch (row_info->bit_depth)
{
- switch (row_info->bit_depth)
+ case 1:
{
- case 1:
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_width; i++)
{
- sp = row;
- shift = 7;
- for (i = 0; i < row_width; i++)
+ if ((png_uint_16)((*sp >> shift) & 0x01)
+ == png_ptr->trans_color.gray)
{
- if ((png_uint_16)((*sp >> shift) & 0x01)
- == trans_values->gray)
- {
- *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
- *sp |= (png_byte)(background->gray << shift);
- }
- if (!shift)
- {
- shift = 7;
- sp++;
- }
- else
- shift--;
+ unsigned int tmp = *sp & (0x7f7f >> (7 - shift));
+ tmp |=
+ (unsigned int)(png_ptr->background.gray << shift);
+ *sp = (png_byte)(tmp & 0xff);
}
- break;
- }
- case 2:
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_table != NULL)
- {
- sp = row;
- shift = 6;
- for (i = 0; i < row_width; i++)
- {
- if ((png_uint_16)((*sp >> shift) & 0x03)
- == trans_values->gray)
- {
- *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
- *sp |= (png_byte)(background->gray << shift);
- }
- else
- {
- png_byte p = (png_byte)((*sp >> shift) & 0x03);
- png_byte g = (png_byte)((gamma_table [p | (p << 2) |
- (p << 4) | (p << 6)] >> 6) & 0x03);
- *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
- *sp |= (png_byte)(g << shift);
- }
- if (!shift)
- {
- shift = 6;
- sp++;
- }
- else
- shift -= 2;
- }
- }
- else
-#endif
- {
- sp = row;
- shift = 6;
- for (i = 0; i < row_width; i++)
- {
- if ((png_uint_16)((*sp >> shift) & 0x03)
- == trans_values->gray)
- {
- *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
- *sp |= (png_byte)(background->gray << shift);
- }
- if (!shift)
- {
- shift = 6;
- sp++;
- }
- else
- shift -= 2;
- }
- }
- break;
- }
- case 4:
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_table != NULL)
- {
- sp = row;
- shift = 4;
- for (i = 0; i < row_width; i++)
- {
- if ((png_uint_16)((*sp >> shift) & 0x0f)
- == trans_values->gray)
- {
- *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
- *sp |= (png_byte)(background->gray << shift);
- }
- else
- {
- png_byte p = (png_byte)((*sp >> shift) & 0x0f);
- png_byte g = (png_byte)((gamma_table[p |
- (p << 4)] >> 4) & 0x0f);
- *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
- *sp |= (png_byte)(g << shift);
- }
- if (!shift)
- {
- shift = 4;
- sp++;
- }
- else
- shift -= 4;
- }
- }
- else
-#endif
- {
- sp = row;
- shift = 4;
- for (i = 0; i < row_width; i++)
- {
- if ((png_uint_16)((*sp >> shift) & 0x0f)
- == trans_values->gray)
- {
- *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
- *sp |= (png_byte)(background->gray << shift);
- }
- if (!shift)
- {
- shift = 4;
- sp++;
- }
- else
- shift -= 4;
- }
- }
- break;
- }
- case 8:
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_table != NULL)
- {
- sp = row;
- for (i = 0; i < row_width; i++, sp++)
- {
- if (*sp == trans_values->gray)
- {
- *sp = (png_byte)background->gray;
- }
- else
- {
- *sp = gamma_table[*sp];
- }
- }
- }
- else
-#endif
- {
- sp = row;
- for (i = 0; i < row_width; i++, sp++)
- {
- if (*sp == trans_values->gray)
- {
- *sp = (png_byte)background->gray;
- }
- }
- }
- break;
- }
- case 16:
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_16 != NULL)
- {
- sp = row;
- for (i = 0; i < row_width; i++, sp += 2)
- {
- png_uint_16 v;
- v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- if (v == trans_values->gray)
- {
- /* background is already in screen gamma */
- *sp = (png_byte)((background->gray >> 8) & 0xff);
- *(sp + 1) = (png_byte)(background->gray & 0xff);
- }
- else
- {
- v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
- *sp = (png_byte)((v >> 8) & 0xff);
- *(sp + 1) = (png_byte)(v & 0xff);
- }
- }
- }
- else
-#endif
+ if (shift == 0)
{
- sp = row;
- for (i = 0; i < row_width; i++, sp += 2)
- {
- png_uint_16 v;
-
- v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- if (v == trans_values->gray)
- {
- *sp = (png_byte)((background->gray >> 8) & 0xff);
- *(sp + 1) = (png_byte)(background->gray & 0xff);
- }
- }
+ shift = 7;
+ sp++;
}
- break;
+
+ else
+ shift--;
}
+ break;
}
- break;
- }
- case PNG_COLOR_TYPE_RGB:
- {
- if (row_info->bit_depth == 8)
+
+ case 2:
{
-#if defined(PNG_READ_GAMMA_SUPPORTED)
+#ifdef PNG_READ_GAMMA_SUPPORTED
if (gamma_table != NULL)
{
sp = row;
- for (i = 0; i < row_width; i++, sp += 3)
+ shift = 6;
+ for (i = 0; i < row_width; i++)
{
- if (*sp == trans_values->red &&
- *(sp + 1) == trans_values->green &&
- *(sp + 2) == trans_values->blue)
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == png_ptr->trans_color.gray)
{
- *sp = (png_byte)background->red;
- *(sp + 1) = (png_byte)background->green;
- *(sp + 2) = (png_byte)background->blue;
+ unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
+ tmp |=
+ (unsigned int)png_ptr->background.gray << shift;
+ *sp = (png_byte)(tmp & 0xff);
}
+
else
{
- *sp = gamma_table[*sp];
- *(sp + 1) = gamma_table[*(sp + 1)];
- *(sp + 2) = gamma_table[*(sp + 2)];
+ unsigned int p = (*sp >> shift) & 0x03;
+ unsigned int g = (gamma_table [p | (p << 2) |
+ (p << 4) | (p << 6)] >> 6) & 0x03;
+ unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
+ tmp |= (unsigned int)(g << shift);
+ *sp = (png_byte)(tmp & 0xff);
}
+
+ if (shift == 0)
+ {
+ shift = 6;
+ sp++;
+ }
+
+ else
+ shift -= 2;
+ }
+ }
+
+ else
+#endif
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == png_ptr->trans_color.gray)
+ {
+ unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
+ tmp |=
+ (unsigned int)png_ptr->background.gray << shift;
+ *sp = (png_byte)(tmp & 0xff);
+ }
+
+ if (shift == 0)
+ {
+ shift = 6;
+ sp++;
+ }
+
+ else
+ shift -= 2;
+ }
+ }
+ break;
+ }
+
+ case 4:
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == png_ptr->trans_color.gray)
+ {
+ unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
+ tmp |=
+ (unsigned int)(png_ptr->background.gray << shift);
+ *sp = (png_byte)(tmp & 0xff);
+ }
+
+ else
+ {
+ unsigned int p = (*sp >> shift) & 0x0f;
+ unsigned int g = (gamma_table[p | (p << 4)] >> 4) &
+ 0x0f;
+ unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
+ tmp |= (unsigned int)(g << shift);
+ *sp = (png_byte)(tmp & 0xff);
+ }
+
+ if (shift == 0)
+ {
+ shift = 4;
+ sp++;
+ }
+
+ else
+ shift -= 4;
+ }
+ }
+
+ else
+#endif
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == png_ptr->trans_color.gray)
+ {
+ unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
+ tmp |=
+ (unsigned int)(png_ptr->background.gray << shift);
+ *sp = (png_byte)(tmp & 0xff);
+ }
+
+ if (shift == 0)
+ {
+ shift = 4;
+ sp++;
+ }
+
+ else
+ shift -= 4;
+ }
+ }
+ break;
+ }
+
+ case 8:
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == png_ptr->trans_color.gray)
+ *sp = (png_byte)png_ptr->background.gray;
+
+ else
+ *sp = gamma_table[*sp];
}
}
else
#endif
{
sp = row;
- for (i = 0; i < row_width; i++, sp += 3)
+ for (i = 0; i < row_width; i++, sp++)
{
- if (*sp == trans_values->red &&
- *(sp + 1) == trans_values->green &&
- *(sp + 2) == trans_values->blue)
- {
- *sp = (png_byte)background->red;
- *(sp + 1) = (png_byte)background->green;
- *(sp + 2) = (png_byte)background->blue;
- }
+ if (*sp == png_ptr->trans_color.gray)
+ *sp = (png_byte)png_ptr->background.gray;
}
}
+ break;
}
- else /* if (row_info->bit_depth == 16) */
+
+ case 16:
{
-#if defined(PNG_READ_GAMMA_SUPPORTED)
+#ifdef PNG_READ_GAMMA_SUPPORTED
if (gamma_16 != NULL)
{
sp = row;
- for (i = 0; i < row_width; i++, sp += 6)
+ for (i = 0; i < row_width; i++, sp += 2)
{
- png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
- png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
- if (r == trans_values->red && g == trans_values->green &&
- b == trans_values->blue)
+ png_uint_16 v;
+
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+
+ if (v == png_ptr->trans_color.gray)
{
- /* background is already in screen gamma */
- *sp = (png_byte)((background->red >> 8) & 0xff);
- *(sp + 1) = (png_byte)(background->red & 0xff);
- *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(background->green & 0xff);
- *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
- *(sp + 5) = (png_byte)(background->blue & 0xff);
+ /* Background is already in screen gamma */
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray
+ & 0xff);
}
+
else
{
- png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
- v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
- *(sp + 2) = (png_byte)((v >> 8) & 0xff);
- *(sp + 3) = (png_byte)(v & 0xff);
- v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
- *(sp + 4) = (png_byte)((v >> 8) & 0xff);
- *(sp + 5) = (png_byte)(v & 0xff);
}
}
}
@@ -3014,386 +3443,514 @@ png_do_background(png_row_infop row_info, png_bytep row,
#endif
{
sp = row;
- for (i = 0; i < row_width; i++, sp += 6)
+ for (i = 0; i < row_width; i++, sp += 2)
{
- png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
- png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
- png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
+ png_uint_16 v;
- if (r == trans_values->red && g == trans_values->green &&
- b == trans_values->blue)
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+
+ if (v == png_ptr->trans_color.gray)
{
- *sp = (png_byte)((background->red >> 8) & 0xff);
- *(sp + 1) = (png_byte)(background->red & 0xff);
- *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(background->green & 0xff);
- *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
- *(sp + 5) = (png_byte)(background->blue & 0xff);
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray
+ & 0xff);
}
}
}
+ break;
}
- break;
- }
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- {
- if (row_info->bit_depth == 8)
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
- gamma_table != NULL)
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 2, dp++)
- {
- png_uint_16 a = *(sp + 1);
-
- if (a == 0xff)
- {
- *dp = gamma_table[*sp];
- }
- else if (a == 0)
- {
- /* background is already in screen gamma */
- *dp = (png_byte)background->gray;
- }
- else
- {
- png_byte v, w;
-
- v = gamma_to_1[*sp];
- png_composite(w, v, a, background_1->gray);
- *dp = gamma_from_1[w];
- }
- }
- }
- else
-#endif
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 2, dp++)
- {
- png_byte a = *(sp + 1);
-
- if (a == 0xff)
- {
- *dp = *sp;
- }
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- else if (a == 0)
- {
- *dp = (png_byte)background->gray;
- }
- else
- {
- png_composite(*dp, *sp, a, background_1->gray);
- }
-#else
- *dp = (png_byte)background->gray;
-#endif
- }
- }
- }
- else /* if (png_ptr->bit_depth == 16) */
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
- gamma_16_to_1 != NULL)
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 4, dp += 2)
- {
- png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
-
- if (a == (png_uint_16)0xffff)
- {
- png_uint_16 v;
-
- v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
- *dp = (png_byte)((v >> 8) & 0xff);
- *(dp + 1) = (png_byte)(v & 0xff);
- }
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- else if (a == 0)
-#else
- else
-#endif
- {
- /* background is already in screen gamma */
- *dp = (png_byte)((background->gray >> 8) & 0xff);
- *(dp + 1) = (png_byte)(background->gray & 0xff);
- }
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- else
- {
- png_uint_16 g, v, w;
-
- g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
- png_composite_16(v, g, a, background_1->gray);
- w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
- *dp = (png_byte)((w >> 8) & 0xff);
- *(dp + 1) = (png_byte)(w & 0xff);
- }
-#endif
- }
- }
- else
-#endif
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 4, dp += 2)
- {
- png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
- if (a == (png_uint_16)0xffff)
- {
- png_memcpy(dp, sp, 2);
- }
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- else if (a == 0)
-#else
- else
-#endif
- {
- *dp = (png_byte)((background->gray >> 8) & 0xff);
- *(dp + 1) = (png_byte)(background->gray & 0xff);
- }
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- else
- {
- png_uint_16 g, v;
-
- g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- png_composite_16(v, g, a, background_1->gray);
- *dp = (png_byte)((v >> 8) & 0xff);
- *(dp + 1) = (png_byte)(v & 0xff);
- }
-#endif
- }
- }
- }
- break;
- }
- case PNG_COLOR_TYPE_RGB_ALPHA:
- {
- if (row_info->bit_depth == 8)
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
- gamma_table != NULL)
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 4, dp += 3)
- {
- png_byte a = *(sp + 3);
-
- if (a == 0xff)
- {
- *dp = gamma_table[*sp];
- *(dp + 1) = gamma_table[*(sp + 1)];
- *(dp + 2) = gamma_table[*(sp + 2)];
- }
- else if (a == 0)
- {
- /* background is already in screen gamma */
- *dp = (png_byte)background->red;
- *(dp + 1) = (png_byte)background->green;
- *(dp + 2) = (png_byte)background->blue;
- }
- else
- {
- png_byte v, w;
-
- v = gamma_to_1[*sp];
- png_composite(w, v, a, background_1->red);
- *dp = gamma_from_1[w];
- v = gamma_to_1[*(sp + 1)];
- png_composite(w, v, a, background_1->green);
- *(dp + 1) = gamma_from_1[w];
- v = gamma_to_1[*(sp + 2)];
- png_composite(w, v, a, background_1->blue);
- *(dp + 2) = gamma_from_1[w];
- }
- }
- }
- else
-#endif
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 4, dp += 3)
- {
- png_byte a = *(sp + 3);
-
- if (a == 0xff)
- {
- *dp = *sp;
- *(dp + 1) = *(sp + 1);
- *(dp + 2) = *(sp + 2);
- }
- else if (a == 0)
- {
- *dp = (png_byte)background->red;
- *(dp + 1) = (png_byte)background->green;
- *(dp + 2) = (png_byte)background->blue;
- }
- else
- {
- png_composite(*dp, *sp, a, background->red);
- png_composite(*(dp + 1), *(sp + 1), a,
- background->green);
- png_composite(*(dp + 2), *(sp + 2), a,
- background->blue);
- }
- }
- }
- }
- else /* if (row_info->bit_depth == 16) */
- {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
- if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
- gamma_16_to_1 != NULL)
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 8, dp += 6)
- {
- png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
- << 8) + (png_uint_16)(*(sp + 7)));
- if (a == (png_uint_16)0xffff)
- {
- png_uint_16 v;
-
- v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
- *dp = (png_byte)((v >> 8) & 0xff);
- *(dp + 1) = (png_byte)(v & 0xff);
- v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
- *(dp + 2) = (png_byte)((v >> 8) & 0xff);
- *(dp + 3) = (png_byte)(v & 0xff);
- v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
- *(dp + 4) = (png_byte)((v >> 8) & 0xff);
- *(dp + 5) = (png_byte)(v & 0xff);
- }
- else if (a == 0)
- {
- /* background is already in screen gamma */
- *dp = (png_byte)((background->red >> 8) & 0xff);
- *(dp + 1) = (png_byte)(background->red & 0xff);
- *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
- *(dp + 3) = (png_byte)(background->green & 0xff);
- *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
- *(dp + 5) = (png_byte)(background->blue & 0xff);
- }
- else
- {
- png_uint_16 v, w, x;
-
- v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
- png_composite_16(w, v, a, background_1->red);
- x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
- *dp = (png_byte)((x >> 8) & 0xff);
- *(dp + 1) = (png_byte)(x & 0xff);
- v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
- png_composite_16(w, v, a, background_1->green);
- x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
- *(dp + 2) = (png_byte)((x >> 8) & 0xff);
- *(dp + 3) = (png_byte)(x & 0xff);
- v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
- png_composite_16(w, v, a, background_1->blue);
- x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
- *(dp + 4) = (png_byte)((x >> 8) & 0xff);
- *(dp + 5) = (png_byte)(x & 0xff);
- }
- }
- }
- else
-#endif
- {
- sp = row;
- dp = row;
- for (i = 0; i < row_width; i++, sp += 8, dp += 6)
- {
- png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
- << 8) + (png_uint_16)(*(sp + 7)));
- if (a == (png_uint_16)0xffff)
- {
- png_memcpy(dp, sp, 6);
- }
- else if (a == 0)
- {
- *dp = (png_byte)((background->red >> 8) & 0xff);
- *(dp + 1) = (png_byte)(background->red & 0xff);
- *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
- *(dp + 3) = (png_byte)(background->green & 0xff);
- *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
- *(dp + 5) = (png_byte)(background->blue & 0xff);
- }
- else
- {
- png_uint_16 v;
-
- png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
- + *(sp + 3));
- png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
- + *(sp + 5));
-
- png_composite_16(v, r, a, background->red);
- *dp = (png_byte)((v >> 8) & 0xff);
- *(dp + 1) = (png_byte)(v & 0xff);
- png_composite_16(v, g, a, background->green);
- *(dp + 2) = (png_byte)((v >> 8) & 0xff);
- *(dp + 3) = (png_byte)(v & 0xff);
- png_composite_16(v, b, a, background->blue);
- *(dp + 4) = (png_byte)((v >> 8) & 0xff);
- *(dp + 5) = (png_byte)(v & 0xff);
- }
- }
- }
- }
- break;
+
+ default:
+ break;
}
+ break;
}
- if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ case PNG_COLOR_TYPE_RGB:
{
- row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
- row_info->channels--;
- row_info->pixel_depth = (png_byte)(row_info->channels *
- row_info->bit_depth);
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ if (row_info->bit_depth == 8)
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == png_ptr->trans_color.red &&
+ *(sp + 1) == png_ptr->trans_color.green &&
+ *(sp + 2) == png_ptr->trans_color.blue)
+ {
+ *sp = (png_byte)png_ptr->background.red;
+ *(sp + 1) = (png_byte)png_ptr->background.green;
+ *(sp + 2) = (png_byte)png_ptr->background.blue;
+ }
+
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == png_ptr->trans_color.red &&
+ *(sp + 1) == png_ptr->trans_color.green &&
+ *(sp + 2) == png_ptr->trans_color.blue)
+ {
+ *sp = (png_byte)png_ptr->background.red;
+ *(sp + 1) = (png_byte)png_ptr->background.green;
+ *(sp + 2) = (png_byte)png_ptr->background.blue;
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+
+ png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+
+ png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
+ + *(sp + 5));
+
+ if (r == png_ptr->trans_color.red &&
+ g == png_ptr->trans_color.green &&
+ b == png_ptr->trans_color.blue)
+ {
+ /* Background is already in screen gamma */
+ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
+ *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
+ }
+
+ else
+ {
+ png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+
+ png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+
+ png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
+ + *(sp + 5));
+
+ if (r == png_ptr->trans_color.red &&
+ g == png_ptr->trans_color.green &&
+ b == png_ptr->trans_color.blue)
+ {
+ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
+ *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
+ }
+ }
+ }
+ }
+ break;
}
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 a = *(sp + 1);
+
+ if (a == 0xff)
+ *sp = gamma_table[*sp];
+
+ else if (a == 0)
+ {
+ /* Background is already in screen gamma */
+ *sp = (png_byte)png_ptr->background.gray;
+ }
+
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, png_ptr->background_1.gray);
+ if (optimize == 0)
+ w = gamma_from_1[w];
+ *sp = w;
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_byte a = *(sp + 1);
+
+ if (a == 0)
+ *sp = (png_byte)png_ptr->background.gray;
+
+ else if (a < 0xff)
+ png_composite(*sp, *sp, a, png_ptr->background.gray);
+ }
+ }
+ }
+ else /* if (png_ptr->bit_depth == 16) */
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 4)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+
+ else if (a == 0)
+ {
+ /* Background is already in screen gamma */
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+ }
+
+ else
+ {
+ png_uint_16 g, v, w;
+
+ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(v, g, a, png_ptr->background_1.gray);
+ if (optimize != 0)
+ w = v;
+ else
+ w = gamma_16_from_1[(v & 0xff) >>
+ gamma_shift][v >> 8];
+ *sp = (png_byte)((w >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(w & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 4)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+
+ if (a == 0)
+ {
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+ }
+
+ else if (a < 0xffff)
+ {
+ png_uint_16 g, v;
+
+ g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_composite_16(v, g, a, png_ptr->background.gray);
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 4)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+
+ else if (a == 0)
+ {
+ /* Background is already in screen gamma */
+ *sp = (png_byte)png_ptr->background.red;
+ *(sp + 1) = (png_byte)png_ptr->background.green;
+ *(sp + 2) = (png_byte)png_ptr->background.blue;
+ }
+
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, png_ptr->background_1.red);
+ if (optimize == 0) w = gamma_from_1[w];
+ *sp = w;
+
+ v = gamma_to_1[*(sp + 1)];
+ png_composite(w, v, a, png_ptr->background_1.green);
+ if (optimize == 0) w = gamma_from_1[w];
+ *(sp + 1) = w;
+
+ v = gamma_to_1[*(sp + 2)];
+ png_composite(w, v, a, png_ptr->background_1.blue);
+ if (optimize == 0) w = gamma_from_1[w];
+ *(sp + 2) = w;
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 4)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0)
+ {
+ *sp = (png_byte)png_ptr->background.red;
+ *(sp + 1) = (png_byte)png_ptr->background.green;
+ *(sp + 2) = (png_byte)png_ptr->background.blue;
+ }
+
+ else if (a < 0xff)
+ {
+ png_composite(*sp, *sp, a, png_ptr->background.red);
+
+ png_composite(*(sp + 1), *(sp + 1), a,
+ png_ptr->background.green);
+
+ png_composite(*(sp + 2), *(sp + 2), a,
+ png_ptr->background.blue);
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 8)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+
+ else if (a == 0)
+ {
+ /* Background is already in screen gamma */
+ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
+ *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
+ }
+
+ else
+ {
+ png_uint_16 v, w;
+
+ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(w, v, a, png_ptr->background_1.red);
+ if (optimize == 0)
+ w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
+ 8];
+ *sp = (png_byte)((w >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(w & 0xff);
+
+ v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ png_composite_16(w, v, a, png_ptr->background_1.green);
+ if (optimize == 0)
+ w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
+ 8];
+
+ *(sp + 2) = (png_byte)((w >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(w & 0xff);
+
+ v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ png_composite_16(w, v, a, png_ptr->background_1.blue);
+ if (optimize == 0)
+ w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
+ 8];
+
+ *(sp + 4) = (png_byte)((w >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(w & 0xff);
+ }
+ }
+ }
+
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 8)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+
+ if (a == 0)
+ {
+ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
+ *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
+ }
+
+ else if (a < 0xffff)
+ {
+ png_uint_16 v;
+
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+ png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
+ + *(sp + 5));
+
+ png_composite_16(v, r, a, png_ptr->background.red);
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+
+ png_composite_16(v, g, a, png_ptr->background.green);
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+
+ png_composite_16(v, b, a, png_ptr->background.blue);
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
}
}
-#endif
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE */
-#if defined(PNG_READ_GAMMA_SUPPORTED)
+#ifdef PNG_READ_GAMMA_SUPPORTED
/* Gamma correct the image, avoiding the alpha channel. Make sure
* you do this after you deal with the transparency issue on grayscale
* or RGB images. If your bit depth is 8, use gamma_table, if it
* is 16, use gamma_16_table and gamma_shift. Build these with
* build_gamma_table().
*/
-void /* PRIVATE */
-png_do_gamma(png_row_infop row_info, png_bytep row,
- png_bytep gamma_table, png_uint_16pp gamma_16_table,
- int gamma_shift)
+static void
+png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
{
+ png_const_bytep gamma_table = png_ptr->gamma_table;
+ png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;
+ int gamma_shift = png_ptr->gamma_shift;
+
png_bytep sp;
png_uint_32 i;
png_uint_32 row_width=row_info->width;
- png_debug(1, "in png_do_gamma\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
- (row_info->bit_depth == 16 && gamma_16_table != NULL)))
+ png_debug(1, "in png_do_gamma");
+
+ if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+ (row_info->bit_depth == 16 && gamma_16_table != NULL)))
{
switch (row_info->color_type)
{
@@ -3412,6 +3969,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
sp++;
}
}
+
else /* if (row_info->bit_depth == 16) */
{
sp = row;
@@ -3423,10 +3981,12 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
+
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
+
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
@@ -3435,6 +3995,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
}
break;
}
+
case PNG_COLOR_TYPE_RGB_ALPHA:
{
if (row_info->bit_depth == 8)
@@ -3444,13 +4005,17 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
{
*sp = gamma_table[*sp];
sp++;
+
*sp = gamma_table[*sp];
sp++;
+
*sp = gamma_table[*sp];
sp++;
+
sp++;
}
}
+
else /* if (row_info->bit_depth == 16) */
{
sp = row;
@@ -3460,10 +4025,12 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
+
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
+
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
@@ -3472,6 +4039,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
}
break;
}
+
case PNG_COLOR_TYPE_GRAY_ALPHA:
{
if (row_info->bit_depth == 8)
@@ -3483,6 +4051,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
sp += 2;
}
}
+
else /* if (row_info->bit_depth == 16) */
{
sp = row;
@@ -3496,6 +4065,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
}
break;
}
+
case PNG_COLOR_TYPE_GRAY:
{
if (row_info->bit_depth == 2)
@@ -3509,13 +4079,14 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
int d = *sp & 0x03;
*sp = (png_byte)(
- ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
- ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
- ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
- ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
+ ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
+ ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
+ ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
+ ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
sp++;
}
}
+
if (row_info->bit_depth == 4)
{
sp = row;
@@ -3525,10 +4096,11 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
int lsb = *sp & 0x0f;
*sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
- | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
+ | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
sp++;
}
}
+
else if (row_info->bit_depth == 8)
{
sp = row;
@@ -3538,6 +4110,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
sp++;
}
}
+
else if (row_info->bit_depth == 16)
{
sp = row;
@@ -3551,30 +4124,96 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
}
break;
}
+
+ default:
+ break;
}
}
}
#endif
-#if defined(PNG_READ_EXPAND_SUPPORTED)
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+/* Encode the alpha channel to the output gamma (the input channel is always
+ * linear.) Called only with color types that have an alpha channel. Needs the
+ * from_1 tables.
+ */
+static void
+png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
+{
+ png_uint_32 row_width = row_info->width;
+
+ png_debug(1, "in png_do_encode_alpha");
+
+ if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep table = png_ptr->gamma_from_1;
+
+ if (table != NULL)
+ {
+ int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;
+
+ /* The alpha channel is the last component: */
+ row += step - 1;
+
+ for (; row_width > 0; --row_width, row += step)
+ *row = table[*row];
+
+ return;
+ }
+ }
+
+ else if (row_info->bit_depth == 16)
+ {
+ png_uint_16pp table = png_ptr->gamma_16_from_1;
+ int gamma_shift = png_ptr->gamma_shift;
+
+ if (table != NULL)
+ {
+ int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;
+
+ /* The alpha channel is the last component: */
+ row += step - 2;
+
+ for (; row_width > 0; --row_width, row += step)
+ {
+ png_uint_16 v;
+
+ v = table[*(row + 1) >> gamma_shift][*row];
+ *row = (png_byte)((v >> 8) & 0xff);
+ *(row + 1) = (png_byte)(v & 0xff);
+ }
+
+ return;
+ }
+ }
+ }
+
+ /* Only get to here if called with a weird row_info; no harm has been done,
+ * so just issue a warning.
+ */
+ png_warning(png_ptr, "png_do_encode_alpha: unexpected call");
+}
+#endif
+
+#ifdef PNG_READ_EXPAND_SUPPORTED
/* Expands a palette row to an RGB or RGBA row depending
* upon whether you supply trans and num_trans.
*/
-void /* PRIVATE */
-png_do_expand_palette(png_row_infop row_info, png_bytep row,
- png_colorp palette, png_bytep trans, int num_trans)
+static void
+png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
+ png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha,
+ int num_trans)
{
int shift, value;
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width=row_info->width;
- png_debug(1, "in png_do_expand_palette\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_debug(1, "in png_do_expand_palette");
+
+ if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (row_info->bit_depth < 8)
{
@@ -3582,20 +4221,23 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
{
case 1:
{
- sp = row + (png_size_t)((row_width - 1) >> 3);
- dp = row + (png_size_t)row_width - 1;
+ sp = row + (size_t)((row_width - 1) >> 3);
+ dp = row + (size_t)row_width - 1;
shift = 7 - (int)((row_width + 7) & 0x07);
for (i = 0; i < row_width; i++)
{
if ((*sp >> shift) & 0x01)
*dp = 1;
+
else
*dp = 0;
+
if (shift == 7)
{
shift = 0;
sp--;
}
+
else
shift++;
@@ -3603,10 +4245,11 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
}
break;
}
+
case 2:
{
- sp = row + (png_size_t)((row_width - 1) >> 2);
- dp = row + (png_size_t)row_width - 1;
+ sp = row + (size_t)((row_width - 1) >> 2);
+ dp = row + (size_t)row_width - 1;
shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
for (i = 0; i < row_width; i++)
{
@@ -3617,6 +4260,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
shift = 0;
sp--;
}
+
else
shift += 2;
@@ -3624,10 +4268,11 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
}
break;
}
+
case 4:
{
- sp = row + (png_size_t)((row_width - 1) >> 1);
- dp = row + (png_size_t)row_width - 1;
+ sp = row + (size_t)((row_width - 1) >> 1);
+ dp = row + (size_t)row_width - 1;
shift = (int)((row_width & 0x01) << 2);
for (i = 0; i < row_width; i++)
{
@@ -3638,6 +4283,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
shift = 0;
sp--;
}
+
else
shift += 4;
@@ -3645,26 +4291,44 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
}
break;
}
+
+ default:
+ break;
}
row_info->bit_depth = 8;
row_info->pixel_depth = 8;
row_info->rowbytes = row_width;
}
- switch (row_info->bit_depth)
- {
- case 8:
- {
- if (trans != NULL)
- {
- sp = row + (png_size_t)row_width - 1;
- dp = row + (png_size_t)(row_width << 2) - 1;
- for (i = 0; i < row_width; i++)
+ if (row_info->bit_depth == 8)
+ {
+ {
+ if (num_trans > 0)
+ {
+ sp = row + (size_t)row_width - 1;
+ dp = row + ((size_t)row_width << 2) - 1;
+
+ i = 0;
+#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
+ if (png_ptr->riffled_palette != NULL)
+ {
+ /* The RGBA optimization works with png_ptr->bit_depth == 8
+ * but sometimes row_info->bit_depth has been changed to 8.
+ * In these cases, the palette hasn't been riffled.
+ */
+ i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row,
+ &sp, &dp);
+ }
+#else
+ PNG_UNUSED(png_ptr)
+#endif
+
+ for (; i < row_width; i++)
{
if ((int)(*sp) >= num_trans)
*dp-- = 0xff;
else
- *dp-- = trans[*sp];
+ *dp-- = trans_alpha[*sp];
*dp-- = palette[*sp].blue;
*dp-- = palette[*sp].green;
*dp-- = palette[*sp].red;
@@ -3676,25 +4340,33 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
row_info->color_type = 6;
row_info->channels = 4;
}
+
else
{
- sp = row + (png_size_t)row_width - 1;
- dp = row + (png_size_t)(row_width * 3) - 1;
+ sp = row + (size_t)row_width - 1;
+ dp = row + (size_t)(row_width * 3) - 1;
+ i = 0;
+#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
+ i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
+ &sp, &dp);
+#else
+ PNG_UNUSED(png_ptr)
+#endif
- for (i = 0; i < row_width; i++)
+ for (; i < row_width; i++)
{
*dp-- = palette[*sp].blue;
*dp-- = palette[*sp].green;
*dp-- = palette[*sp].red;
sp--;
}
+
row_info->bit_depth = 8;
row_info->pixel_depth = 24;
row_info->rowbytes = row_width * 3;
row_info->color_type = 2;
row_info->channels = 3;
}
- break;
}
}
}
@@ -3703,228 +4375,279 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
/* If the bit depth < 8, it is expanded to 8. Also, if the already
* expanded transparency value is supplied, an alpha channel is built.
*/
-void /* PRIVATE */
+static void
png_do_expand(png_row_infop row_info, png_bytep row,
- png_color_16p trans_value)
+ png_const_color_16p trans_color)
{
int shift, value;
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width=row_info->width;
- png_debug(1, "in png_do_expand\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_debug(1, "in png_do_expand");
+
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
- if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ unsigned int gray = trans_color != NULL ? trans_color->gray : 0;
+
+ if (row_info->bit_depth < 8)
{
- png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
-
- if (row_info->bit_depth < 8)
+ switch (row_info->bit_depth)
{
- switch (row_info->bit_depth)
+ case 1:
{
- case 1:
- {
- gray = (png_uint_16)((gray&0x01)*0xff);
- sp = row + (png_size_t)((row_width - 1) >> 3);
- dp = row + (png_size_t)row_width - 1;
- shift = 7 - (int)((row_width + 7) & 0x07);
- for (i = 0; i < row_width; i++)
- {
- if ((*sp >> shift) & 0x01)
- *dp = 0xff;
- else
- *dp = 0;
- if (shift == 7)
- {
- shift = 0;
- sp--;
- }
- else
- shift++;
-
- dp--;
- }
- break;
- }
- case 2:
- {
- gray = (png_uint_16)((gray&0x03)*0x55);
- sp = row + (png_size_t)((row_width - 1) >> 2);
- dp = row + (png_size_t)row_width - 1;
- shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
- for (i = 0; i < row_width; i++)
- {
- value = (*sp >> shift) & 0x03;
- *dp = (png_byte)(value | (value << 2) | (value << 4) |
- (value << 6));
- if (shift == 6)
- {
- shift = 0;
- sp--;
- }
- else
- shift += 2;
-
- dp--;
- }
- break;
- }
- case 4:
- {
- gray = (png_uint_16)((gray&0x0f)*0x11);
- sp = row + (png_size_t)((row_width - 1) >> 1);
- dp = row + (png_size_t)row_width - 1;
- shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
- for (i = 0; i < row_width; i++)
- {
- value = (*sp >> shift) & 0x0f;
- *dp = (png_byte)(value | (value << 4));
- if (shift == 4)
- {
- shift = 0;
- sp--;
- }
- else
- shift = 4;
-
- dp--;
- }
- break;
- }
- }
- row_info->bit_depth = 8;
- row_info->pixel_depth = 8;
- row_info->rowbytes = row_width;
- }
-
- if (trans_value != NULL)
- {
- if (row_info->bit_depth == 8)
- {
- gray = gray & 0xff;
- sp = row + (png_size_t)row_width - 1;
- dp = row + (png_size_t)(row_width << 1) - 1;
+ gray = (gray & 0x01) * 0xff;
+ sp = row + (size_t)((row_width - 1) >> 3);
+ dp = row + (size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 0x07);
for (i = 0; i < row_width; i++)
{
- if (*sp == gray)
- *dp-- = 0;
+ if ((*sp >> shift) & 0x01)
+ *dp = 0xff;
+
else
- *dp-- = 0xff;
- *dp-- = *sp--;
+ *dp = 0;
+
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+
+ else
+ shift++;
+
+ dp--;
}
+ break;
}
- else if (row_info->bit_depth == 16)
+
+ case 2:
{
- png_byte gray_high = (gray >> 8) & 0xff;
- png_byte gray_low = gray & 0xff;
- sp = row + row_info->rowbytes - 1;
- dp = row + (row_info->rowbytes << 1) - 1;
+ gray = (gray & 0x03) * 0x55;
+ sp = row + (size_t)((row_width - 1) >> 2);
+ dp = row + (size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
for (i = 0; i < row_width; i++)
{
- if (*(sp-1) == gray_high && *(sp) == gray_low)
+ value = (*sp >> shift) & 0x03;
+ *dp = (png_byte)(value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
{
- *dp-- = 0;
- *dp-- = 0;
+ shift = 0;
+ sp--;
}
+
else
- {
- *dp-- = 0xff;
- *dp-- = 0xff;
- }
- *dp-- = *sp--;
- *dp-- = *sp--;
+ shift += 2;
+
+ dp--;
}
+ break;
}
- row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
- row_info->channels = 2;
- row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
- row_width);
+
+ case 4:
+ {
+ gray = (gray & 0x0f) * 0x11;
+ sp = row + (size_t)((row_width - 1) >> 1);
+ dp = row + (size_t)row_width - 1;
+ shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x0f;
+ *dp = (png_byte)(value | (value << 4));
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+
+ default:
+ break;
}
+
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
}
- else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+
+ if (trans_color != NULL)
{
if (row_info->bit_depth == 8)
{
- png_byte red = trans_value->red & 0xff;
- png_byte green = trans_value->green & 0xff;
- png_byte blue = trans_value->blue & 0xff;
- sp = row + (png_size_t)row_info->rowbytes - 1;
- dp = row + (png_size_t)(row_width << 2) - 1;
+ gray = gray & 0xff;
+ sp = row + (size_t)row_width - 1;
+ dp = row + ((size_t)row_width << 1) - 1;
+
for (i = 0; i < row_width; i++)
{
- if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
+ if ((*sp & 0xffU) == gray)
*dp-- = 0;
+
else
*dp-- = 0xff;
- *dp-- = *sp--;
- *dp-- = *sp--;
+
*dp-- = *sp--;
}
}
+
else if (row_info->bit_depth == 16)
{
- png_byte red_high = (trans_value->red >> 8) & 0xff;
- png_byte green_high = (trans_value->green >> 8) & 0xff;
- png_byte blue_high = (trans_value->blue >> 8) & 0xff;
- png_byte red_low = trans_value->red & 0xff;
- png_byte green_low = trans_value->green & 0xff;
- png_byte blue_low = trans_value->blue & 0xff;
+ unsigned int gray_high = (gray >> 8) & 0xff;
+ unsigned int gray_low = gray & 0xff;
sp = row + row_info->rowbytes - 1;
- dp = row + (png_size_t)(row_width << 3) - 1;
+ dp = row + (row_info->rowbytes << 1) - 1;
for (i = 0; i < row_width; i++)
{
- if (*(sp - 5) == red_high &&
- *(sp - 4) == red_low &&
- *(sp - 3) == green_high &&
- *(sp - 2) == green_low &&
- *(sp - 1) == blue_high &&
- *(sp ) == blue_low)
+ if ((*(sp - 1) & 0xffU) == gray_high &&
+ (*(sp) & 0xffU) == gray_low)
{
*dp-- = 0;
*dp-- = 0;
}
+
else
{
*dp-- = 0xff;
*dp-- = 0xff;
}
- *dp-- = *sp--;
- *dp-- = *sp--;
- *dp-- = *sp--;
- *dp-- = *sp--;
+
*dp-- = *sp--;
*dp-- = *sp--;
}
}
- row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- row_info->channels = 4;
- row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+
+ row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ row_info->channels = 2;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
+ row_width);
}
}
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ trans_color != NULL)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte red = (png_byte)(trans_color->red & 0xff);
+ png_byte green = (png_byte)(trans_color->green & 0xff);
+ png_byte blue = (png_byte)(trans_color->blue & 0xff);
+ sp = row + (size_t)row_info->rowbytes - 1;
+ dp = row + ((size_t)row_width << 2) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
+ *dp-- = 0;
+
+ else
+ *dp-- = 0xff;
+
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);
+ png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);
+ png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);
+ png_byte red_low = (png_byte)(trans_color->red & 0xff);
+ png_byte green_low = (png_byte)(trans_color->green & 0xff);
+ png_byte blue_low = (png_byte)(trans_color->blue & 0xff);
+ sp = row + row_info->rowbytes - 1;
+ dp = row + ((size_t)row_width << 3) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 5) == red_high &&
+ *(sp - 4) == red_low &&
+ *(sp - 3) == green_high &&
+ *(sp - 2) == green_low &&
+ *(sp - 1) == blue_high &&
+ *(sp ) == blue_low)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ row_info->channels = 4;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
+ }
}
#endif
-#if defined(PNG_READ_DITHER_SUPPORTED)
-void /* PRIVATE */
-png_do_dither(png_row_infop row_info, png_bytep row,
- png_bytep palette_lookup, png_bytep dither_lookup)
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+/* If the bit depth is 8 and the color type is not a palette type expand the
+ * whole row to 16 bits. Has no effect otherwise.
+ */
+static void
+png_do_expand_16(png_row_infop row_info, png_bytep row)
+{
+ if (row_info->bit_depth == 8 &&
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ /* The row have a sequence of bytes containing [0..255] and we need
+ * to turn it into another row containing [0..65535], to do this we
+ * calculate:
+ *
+ * (input / 255) * 65535
+ *
+ * Which happens to be exactly input * 257 and this can be achieved
+ * simply by byte replication in place (copying backwards).
+ */
+ png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */
+ png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */
+ while (dp > sp)
+ {
+ dp[-2] = dp[-1] = *--sp; dp -= 2;
+ }
+
+ row_info->rowbytes *= 2;
+ row_info->bit_depth = 16;
+ row_info->pixel_depth = (png_byte)(row_info->channels * 16);
+ }
+}
+#endif
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+static void
+png_do_quantize(png_row_infop row_info, png_bytep row,
+ png_const_bytep palette_lookup, png_const_bytep quantize_lookup)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width=row_info->width;
- png_debug(1, "in png_do_dither\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_debug(1, "in png_do_quantize");
+
+ if (row_info->bit_depth == 8)
{
- if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
- palette_lookup && row_info->bit_depth == 8)
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)
{
int r, g, b, p;
sp = row;
@@ -3935,31 +4658,33 @@ png_do_dither(png_row_infop row_info, png_bytep row,
g = *sp++;
b = *sp++;
- /* this looks real messy, but the compiler will reduce
- it down to a reasonable formula. For example, with
- 5 bits per color, we get:
- p = (((r >> 3) & 0x1f) << 10) |
- (((g >> 3) & 0x1f) << 5) |
- ((b >> 3) & 0x1f);
- */
- p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
- ((1 << PNG_DITHER_RED_BITS) - 1)) <<
- (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
- (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
- ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
- (PNG_DITHER_BLUE_BITS)) |
- ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
- ((1 << PNG_DITHER_BLUE_BITS) - 1));
+ /* This looks real messy, but the compiler will reduce
+ * it down to a reasonable formula. For example, with
+ * 5 bits per color, we get:
+ * p = (((r >> 3) & 0x1f) << 10) |
+ * (((g >> 3) & 0x1f) << 5) |
+ * ((b >> 3) & 0x1f);
+ */
+ p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
+ ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
+ (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
+ (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
+ ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
+ (PNG_QUANTIZE_BLUE_BITS)) |
+ ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
+ ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
*dp++ = palette_lookup[p];
}
+
row_info->color_type = PNG_COLOR_TYPE_PALETTE;
row_info->channels = 1;
row_info->pixel_depth = row_info->bit_depth;
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
- palette_lookup != NULL && row_info->bit_depth == 8)
+ palette_lookup != NULL)
{
int r, g, b, p;
sp = row;
@@ -3971,314 +4696,345 @@ png_do_dither(png_row_infop row_info, png_bytep row,
b = *sp++;
sp++;
- p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
- ((1 << PNG_DITHER_RED_BITS) - 1)) <<
- (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
- (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
- ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
- (PNG_DITHER_BLUE_BITS)) |
- ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
- ((1 << PNG_DITHER_BLUE_BITS) - 1));
+ p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
+ ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
+ (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
+ (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
+ ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
+ (PNG_QUANTIZE_BLUE_BITS)) |
+ ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
+ ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
*dp++ = palette_lookup[p];
}
+
row_info->color_type = PNG_COLOR_TYPE_PALETTE;
row_info->channels = 1;
row_info->pixel_depth = row_info->bit_depth;
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
- dither_lookup && row_info->bit_depth == 8)
+ quantize_lookup)
{
sp = row;
+
for (i = 0; i < row_width; i++, sp++)
{
- *sp = dither_lookup[*sp];
+ *sp = quantize_lookup[*sp];
}
}
}
}
-#endif
+#endif /* READ_QUANTIZE */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-static PNG_CONST int png_gamma_shift[] =
- {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
-
-/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
- * 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.
+/* Transform the row. The order of transformations is significant,
+ * and is very touchy. If you add a transformation, take care to
+ * decide how it fits in with the other transformations here.
*/
void /* PRIVATE */
-png_build_gamma_table(png_structp png_ptr)
+png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
{
- png_debug(1, "in png_build_gamma_table\n");
+ png_debug(1, "in png_do_read_transformations");
- if (png_ptr->bit_depth <= 8)
- {
- int i;
- double g;
-
- if (png_ptr->screen_gamma > .000001)
- g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
- else
- g = 1.0;
-
- png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)256);
-
- for (i = 0; i < 256; i++)
- {
- png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
- g) * 255.0 + .5);
- }
-
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
- defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
- if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
- {
-
- g = 1.0 / (png_ptr->gamma);
-
- png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)256);
-
- for (i = 0; i < 256; i++)
- {
- png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
- g) * 255.0 + .5);
- }
-
-
- png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)256);
-
- if(png_ptr->screen_gamma > 0.000001)
- g = 1.0 / png_ptr->screen_gamma;
- else
- g = png_ptr->gamma; /* probably doing rgb_to_gray */
-
- for (i = 0; i < 256; i++)
- {
- png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
- g) * 255.0 + .5);
-
- }
- }
-#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
- }
- else
- {
- double g;
- int i, j, shift, num;
- int sig_bit;
- png_uint_32 ig;
-
- if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
- {
- sig_bit = (int)png_ptr->sig_bit.red;
- if ((int)png_ptr->sig_bit.green > sig_bit)
- sig_bit = png_ptr->sig_bit.green;
- if ((int)png_ptr->sig_bit.blue > sig_bit)
- sig_bit = png_ptr->sig_bit.blue;
- }
- else
- {
- sig_bit = (int)png_ptr->sig_bit.gray;
- }
-
- if (sig_bit > 0)
- shift = 16 - sig_bit;
- else
- shift = 0;
-
- if (png_ptr->transformations & PNG_16_TO_8)
- {
- if (shift < (16 - PNG_MAX_GAMMA_8))
- shift = (16 - PNG_MAX_GAMMA_8);
- }
-
- if (shift > 8)
- shift = 8;
- if (shift < 0)
- shift = 0;
-
- png_ptr->gamma_shift = (png_byte)shift;
-
- num = (1 << (8 - shift));
-
- if (png_ptr->screen_gamma > .000001)
- g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
- else
- g = 1.0;
-
- png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
- (png_uint_32)(num * png_sizeof (png_uint_16p)));
-
- if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
- {
- double fin, fout;
- png_uint_32 last, max;
-
- for (i = 0; i < num; i++)
- {
- png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(256 * png_sizeof (png_uint_16)));
- }
-
- g = 1.0 / g;
- last = 0;
- for (i = 0; i < 256; i++)
- {
- fout = ((double)i + 0.5) / 256.0;
- fin = pow(fout, g);
- max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
- while (last <= max)
- {
- png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
- [(int)(last >> (8 - shift))] = (png_uint_16)(
- (png_uint_16)i | ((png_uint_16)i << 8));
- last++;
- }
- }
- while (last < ((png_uint_32)num << 8))
- {
- png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
- [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
- last++;
- }
- }
- else
- {
- for (i = 0; i < num; i++)
- {
- png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(256 * png_sizeof (png_uint_16)));
-
- ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
- for (j = 0; j < 256; j++)
- {
- png_ptr->gamma_16_table[i][j] =
- (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
- 65535.0, g) * 65535.0 + .5);
- }
- }
- }
-
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
- defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
- if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
- {
-
- g = 1.0 / (png_ptr->gamma);
-
- png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
- (png_uint_32)(num * png_sizeof (png_uint_16p )));
-
- for (i = 0; i < num; i++)
- {
- png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(256 * png_sizeof (png_uint_16)));
-
- ig = (((png_uint_32)i *
- (png_uint_32)png_gamma_shift[shift]) >> 4);
- for (j = 0; j < 256; j++)
- {
- png_ptr->gamma_16_to_1[i][j] =
- (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
- 65535.0, g) * 65535.0 + .5);
- }
- }
-
- if(png_ptr->screen_gamma > 0.000001)
- g = 1.0 / png_ptr->screen_gamma;
- else
- g = png_ptr->gamma; /* probably doing rgb_to_gray */
-
- png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
- (png_uint_32)(num * png_sizeof (png_uint_16p)));
-
- for (i = 0; i < num; i++)
- {
- png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(256 * png_sizeof (png_uint_16)));
-
- ig = (((png_uint_32)i *
- (png_uint_32)png_gamma_shift[shift]) >> 4);
- for (j = 0; j < 256; j++)
- {
- png_ptr->gamma_16_from_1[i][j] =
- (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
- 65535.0, g) * 65535.0 + .5);
- }
- }
- }
-#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
- }
-}
-#endif
-/* To do: install integer version of png_build_gamma_table here */
-#endif
-
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
-/* undoes intrapixel differencing */
-void /* PRIVATE */
-png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
-{
- png_debug(1, "in png_do_read_intrapixel\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ if (png_ptr->row_buf == NULL)
{
- int bytes_per_pixel;
- png_uint_32 row_width = row_info->width;
- if (row_info->bit_depth == 8)
+ /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this
+ * error is incredibly rare and incredibly easy to debug without this
+ * information.
+ */
+ png_error(png_ptr, "NULL row buffer");
+ }
+
+ /* The following is debugging; prior to 1.5.4 the code was never compiled in;
+ * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro
+ * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for
+ * all transformations, however in practice the ROW_INIT always gets done on
+ * demand, if necessary.
+ */
+ if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&
+ (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
+ {
+ /* Application has failed to call either png_read_start_image() or
+ * png_read_update_info() after setting transforms that expand pixels.
+ * This check added to libpng-1.2.19 (but not enabled until 1.5.4).
+ */
+ png_error(png_ptr, "Uninitialized row");
+ }
+
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
{
- png_bytep rp;
- png_uint_32 i;
-
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
- bytes_per_pixel = 3;
- else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- bytes_per_pixel = 4;
- else
- return;
-
- for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
+ if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8))
{
- *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
- *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
+ if (png_ptr->riffled_palette == NULL)
+ {
+ /* Initialize the accelerated palette expansion. */
+ png_ptr->riffled_palette =
+ (png_bytep)png_malloc(png_ptr, 256 * 4);
+ png_riffle_palette_neon(png_ptr);
+ }
}
+#endif
+ png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1,
+ png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
}
- else if (row_info->bit_depth == 16)
+
+ else
{
- png_bytep rp;
- png_uint_32 i;
+ if (png_ptr->num_trans != 0 &&
+ (png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
+ png_do_expand(row_info, png_ptr->row_buf + 1,
+ &(png_ptr->trans_color));
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
- bytes_per_pixel = 6;
- else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- bytes_per_pixel = 8;
else
- return;
-
- for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
- {
- png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
- png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
- png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
- png_uint_32 red = (png_uint_32)((s0+s1+65536L) & 0xffffL);
- png_uint_32 blue = (png_uint_32)((s2+s1+65536L) & 0xffffL);
- *(rp ) = (png_byte)((red >> 8) & 0xff);
- *(rp+1) = (png_byte)(red & 0xff);
- *(rp+4) = (png_byte)((blue >> 8) & 0xff);
- *(rp+5) = (png_byte)(blue & 0xff);
- }
+ png_do_expand(row_info, png_ptr->row_buf + 1, NULL);
}
}
+#endif
+
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
+ (png_ptr->transformations & PNG_COMPOSE) == 0 &&
+ (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ png_do_strip_channel(row_info, png_ptr->row_buf + 1,
+ 0 /* at_start == false, because SWAP_ALPHA happens later */);
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
+ {
+ int rgb_error =
+ png_do_rgb_to_gray(png_ptr, row_info,
+ png_ptr->row_buf + 1);
+
+ if (rgb_error != 0)
+ {
+ png_ptr->rgb_to_gray_status=1;
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
+ PNG_RGB_TO_GRAY_WARN)
+ png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+
+ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
+ PNG_RGB_TO_GRAY_ERR)
+ png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ }
+ }
+#endif
+
+/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
+ *
+ * In most cases, the "simple transparency" should be done prior to doing
+ * gray-to-RGB, or you will have to test 3x as many bytes to check if a
+ * pixel is transparent. You would also need to make sure that the
+ * transparency information is upgraded to RGB.
+ *
+ * To summarize, the current flow is:
+ * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
+ * with background "in place" if transparent,
+ * convert to RGB if necessary
+ * - Gray + alpha -> composite with gray background and remove alpha bytes,
+ * convert to RGB if necessary
+ *
+ * To support RGB backgrounds for gray images we need:
+ * - Gray + simple transparency -> convert to RGB + simple transparency,
+ * compare 3 or 6 bytes and composite with
+ * background "in place" if transparent
+ * (3x compare/pixel compared to doing
+ * composite with gray bkgrnd)
+ * - Gray + alpha -> convert to RGB + alpha, composite with background and
+ * remove alpha bytes (3x float
+ * operations/pixel compared with composite
+ * on gray background)
+ *
+ * Greg's change will do this. The reason it wasn't done before is for
+ * performance, as this increases the per-pixel operations. If we would check
+ * in advance if the background was gray or RGB, and position the gray-to-RGB
+ * transform appropriately, then it would save a lot of work/time.
+ */
+
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+ /* If gray -> RGB, do so now only if background is non-gray; else do later
+ * for performance reasons
+ */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
+ (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0)
+ png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+ if ((png_ptr->transformations & PNG_COMPOSE) != 0)
+ png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
+#endif
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ if ((png_ptr->transformations & PNG_GAMMA) != 0 &&
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ /* Because RGB_TO_GRAY does the gamma transform. */
+ (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 &&
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+ /* Because PNG_COMPOSE does the gamma transform if there is something to
+ * do (if there is an alpha channel or transparency.)
+ */
+ !((png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ ((png_ptr->num_trans != 0) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) &&
+#endif
+ /* Because png_init_read_transformations transforms the palette, unless
+ * RGB_TO_GRAY will do the transform.
+ */
+ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
+ png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);
+#endif
+
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
+ (png_ptr->transformations & PNG_COMPOSE) != 0 &&
+ (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ png_do_strip_channel(row_info, png_ptr->row_buf + 1,
+ 0 /* at_start == false, because SWAP_ALPHA happens later */);
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+ if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
+ (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
+ png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);
+#endif
+
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+ if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
+ png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+ /* There is no harm in doing both of these because only one has any effect,
+ * by putting the 'scale' option first if the app asks for scale (either by
+ * calling the API or in a TRANSFORM flag) this is what happens.
+ */
+ if ((png_ptr->transformations & PNG_16_TO_8) != 0)
+ png_do_chop(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+ if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
+ {
+ png_do_quantize(row_info, png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->quantize_index);
+
+ if (row_info->rowbytes == 0)
+ png_error(png_ptr, "png_do_quantize returned rowbytes=0");
+ }
+#endif /* READ_QUANTIZE */
+
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+ /* Do the expansion now, after all the arithmetic has been done. Notice
+ * that previous transformations can handle the PNG_EXPAND_16 flag if this
+ * is efficient (particularly true in the case of gamma correction, where
+ * better accuracy results faster!)
+ */
+ if ((png_ptr->transformations & PNG_EXPAND_16) != 0)
+ png_do_expand_16(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+ /* NOTE: moved here in 1.5.4 (from much later in this list.) */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
+ (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0)
+ png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_INVERT_SUPPORTED
+ if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
+ png_do_invert(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
+ png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_SHIFT_SUPPORTED
+ if ((png_ptr->transformations & PNG_SHIFT) != 0)
+ png_do_unshift(row_info, png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#ifdef PNG_READ_PACK_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACK) != 0)
+ png_do_unpack(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Added at libpng-1.5.10 */
+ if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= 0)
+ png_do_check_palette_indexes(png_ptr, row_info);
+#endif
+
+#ifdef PNG_READ_BGR_SUPPORTED
+ if ((png_ptr->transformations & PNG_BGR) != 0)
+ png_do_bgr(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ png_do_packswap(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_FILLER_SUPPORTED
+ if ((png_ptr->transformations & PNG_FILLER) != 0)
+ png_do_read_filler(row_info, png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
+ png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_16BIT_SUPPORTED
+#ifdef PNG_READ_SWAP_SUPPORTED
+ if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
+ png_do_swap(row_info, png_ptr->row_buf + 1);
+#endif
+#endif
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+ if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
+ {
+ if (png_ptr->read_user_transform_fn != NULL)
+ (*(png_ptr->read_user_transform_fn)) /* User read transform function */
+ (png_ptr, /* png_ptr */
+ row_info, /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* size_t rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
+ if (png_ptr->user_transform_depth != 0)
+ row_info->bit_depth = png_ptr->user_transform_depth;
+
+ if (png_ptr->user_transform_channels != 0)
+ row_info->channels = png_ptr->user_transform_channels;
+#endif
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth *
+ row_info->channels);
+
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);
+ }
+#endif
}
-#endif /* PNG_MNG_FEATURES_SUPPORTED */
-#endif /* PNG_READ_SUPPORTED */
+
+#endif /* READ_TRANSFORMS */
+#endif /* READ */
diff --git a/PDF/src/pngrutil.c b/PDF/src/pngrutil.c
index dfb2365da..d31dc21da 100644
--- a/PDF/src/pngrutil.c
+++ b/PDF/src/pngrutil.c
@@ -1,365 +1,854 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.2.23 [November 6, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * 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 reading an image.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
-#if defined(PNG_READ_SUPPORTED)
-
-#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500)
-# define WIN32_WCE_OLD
-#endif
-
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-# if defined(WIN32_WCE_OLD)
-/* strtod() function is not supported on WindowsCE */
-__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, char **endptr)
-{
- double result = 0;
- int len;
- wchar_t *str, *end;
-
- len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
- str = (wchar_t *)png_malloc(png_ptr, len * sizeof(wchar_t));
- if ( NULL != str )
- {
- MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
- result = wcstod(str, &end);
- len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
- *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
- png_free(png_ptr, str);
- }
- return result;
-}
-# else
-# define png_strtod(p,a,b) strtod(a,b)
-# endif
-#endif
+#ifdef PNG_READ_SUPPORTED
png_uint_32 PNGAPI
-png_get_uint_31(png_structp png_ptr, png_bytep buf)
+png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
{
- png_uint_32 i = png_get_uint_32(buf);
- if (i > PNG_UINT_31_MAX)
- png_error(png_ptr, "PNG unsigned integer out of range.");
- return (i);
+ png_uint_32 uval = png_get_uint_32(buf);
+
+ if (uval > PNG_UINT_31_MAX)
+ png_error(png_ptr, "PNG unsigned integer out of range");
+
+ return uval;
}
-#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+
+#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,
+ * but the APIs will still be available externally.
+ *
+ * The parentheses around "PNGAPI function_name" in the following three
+ * functions are necessary because they allow the macros to co-exist with
+ * these (unused but exported) functions.
+ */
+
/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
-png_uint_32 PNGAPI
-png_get_uint_32(png_bytep buf)
+png_uint_32 (PNGAPI
+png_get_uint_32)(png_const_bytep buf)
{
- png_uint_32 i = ((png_uint_32)(*buf) << 24) +
- ((png_uint_32)(*(buf + 1)) << 16) +
- ((png_uint_32)(*(buf + 2)) << 8) +
- (png_uint_32)(*(buf + 3));
+ png_uint_32 uval =
+ ((png_uint_32)(*(buf )) << 24) +
+ ((png_uint_32)(*(buf + 1)) << 16) +
+ ((png_uint_32)(*(buf + 2)) << 8) +
+ ((png_uint_32)(*(buf + 3)) ) ;
- return (i);
+ return uval;
}
/* Grab a signed 32-bit integer from a buffer in big-endian format. The
- * data is stored in the PNG file in two's complement format, and it is
- * assumed that the machine format for signed integers is the same. */
-png_int_32 PNGAPI
-png_get_int_32(png_bytep buf)
+ * data is stored in the PNG file in two's complement format and there
+ * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
+ * the following code does a two's complement to native conversion.
+ */
+png_int_32 (PNGAPI
+png_get_int_32)(png_const_bytep buf)
{
- png_int_32 i = ((png_int_32)(*buf) << 24) +
- ((png_int_32)(*(buf + 1)) << 16) +
- ((png_int_32)(*(buf + 2)) << 8) +
- (png_int_32)(*(buf + 3));
+ png_uint_32 uval = png_get_uint_32(buf);
+ if ((uval & 0x80000000) == 0) /* non-negative */
+ return (png_int_32)uval;
- return (i);
+ uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
+ if ((uval & 0x80000000) == 0) /* no overflow */
+ return -(png_int_32)uval;
+ /* The following has to be safe; this function only gets called on PNG data
+ * and if we get here that data is invalid. 0 is the most safe value and
+ * if not then an attacker would surely just generate a PNG with 0 instead.
+ */
+ return 0;
}
/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
-png_uint_16 PNGAPI
-png_get_uint_16(png_bytep buf)
+png_uint_16 (PNGAPI
+png_get_uint_16)(png_const_bytep buf)
{
- png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
- (png_uint_16)(*(buf + 1)));
+ /* ANSI-C requires an int value to accommodate at least 16 bits so this
+ * works and allows the compiler not to worry about possible narrowing
+ * on 32-bit systems. (Pre-ANSI systems did not make integers smaller
+ * than 16 bits either.)
+ */
+ unsigned int val =
+ ((unsigned int)(*buf) << 8) +
+ ((unsigned int)(*(buf + 1)));
- return (i);
+ return (png_uint_16)val;
+}
+
+#endif /* READ_INT_FUNCTIONS */
+
+/* Read and check the PNG file signature */
+void /* PRIVATE */
+png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
+{
+ size_t num_checked, num_to_check;
+
+ /* Exit if the user application does not expect a signature. */
+ if (png_ptr->sig_bytes >= 8)
+ return;
+
+ num_checked = png_ptr->sig_bytes;
+ num_to_check = 8 - num_checked;
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;
+#endif
+
+ /* The signature must be serialized in a single I/O call. */
+ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
+ png_ptr->sig_bytes = 8;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ if (num_checked < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+}
+
+/* Read the chunk header (length + type name).
+ * Put the type name into png_ptr->chunk_name, and return the length.
+ */
+png_uint_32 /* PRIVATE */
+png_read_chunk_header(png_structrp png_ptr)
+{
+ png_byte buf[8];
+ png_uint_32 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.
+ */
+ png_read_data(png_ptr, buf, 8);
+ length = png_get_uint_31(png_ptr, buf);
+
+ /* Put the chunk name into png_ptr->chunk_name. */
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+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);
+
+ /* 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);
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
+#endif
+
+ return length;
}
-#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
/* Read data, and (optionally) run it through the CRC. */
void /* PRIVATE */
-png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
png_read_data(png_ptr, buf, length);
png_calculate_crc(png_ptr, buf, length);
}
/* Optionally skip data and then check the CRC. Depending on whether we
- are reading a 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. */
+ * 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.
+ */
int /* PRIVATE */
-png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
{
- png_size_t i;
- png_size_t istop = png_ptr->zbuf_size;
+ /* 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.
+ */
+ while (skip > 0)
+ {
+ png_uint_32 len;
+ png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
- for (i = (png_size_t)skip; i > istop; i -= istop)
- {
- png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
- }
- if (i)
- {
- png_crc_read(png_ptr, png_ptr->zbuf, i);
+ len = (sizeof tmpbuf);
+ if (len > skip)
+ len = skip;
+ skip -= len;
+
+ png_crc_read(png_ptr, tmpbuf, len);
}
- if (png_crc_error(png_ptr))
+ if (png_crc_error(png_ptr) != 0)
{
- if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
- !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
- (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
- (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
+ if (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");
- }
- return (1);
+
+ return 1;
}
- return (0);
+ return 0;
}
/* Compare the CRC stored in the PNG file with that calculated by libpng from
- the data it has read thus far. */
+ * the data it has read thus far.
+ */
int /* PRIVATE */
-png_crc_error(png_structp png_ptr)
+png_crc_error(png_structrp png_ptr)
{
png_byte crc_bytes[4];
png_uint_32 crc;
int need_crc = 1;
- if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ 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 */
+
+ else /* critical */
{
- if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ 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)
+ if (need_crc != 0)
{
crc = png_get_uint_32(crc_bytes);
- return ((int)(crc != png_ptr->crc));
+ return crc != png_ptr->crc;
}
+
else
- return (0);
+ return 0;
+}
+
+#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)
+/* 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').
+ */
+static png_bytep
+png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
+{
+ png_bytep buffer = png_ptr->read_buffer;
+
+ if (buffer != NULL && new_size > png_ptr->read_buffer_size)
+ {
+ png_ptr->read_buffer = NULL;
+ png_ptr->read_buffer_size = 0;
+ png_free(png_ptr, buffer);
+ buffer = NULL;
+ }
+
+ if (buffer == NULL)
+ {
+ buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size));
+
+ if (buffer != NULL)
+ {
+ memset(buffer, 0, new_size); /* just in case */
+ 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 */
+
+/* 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
+ * the owner but, in final release builds, just issues a warning if some other
+ * chunk apparently owns the stream. Prior to release it does a png_error.
+ */
+static int
+png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
+{
+ if (png_ptr->zowner != 0)
+ {
+ char msg[64];
+
+ PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner);
+ /* So the message that results is " using zstream"; this is an
+ * internal error, but is very useful for debugging. i18n requirements
+ * are minimal.
+ */
+ (void)png_safecat(msg, (sizeof msg), 4, " using zstream");
+#if PNG_RELEASE_BUILD
+ png_chunk_warning(png_ptr, msg);
+ png_ptr->zowner = 0;
+#else
+ png_chunk_error(png_ptr, msg);
+#endif
+ }
+
+ /* Implementation note: unlike 'png_deflate_claim' this internal function
+ * does not take the size of the data as an argument. Some efficiency could
+ * be gained by using this when it is known *if* the zlib stream itself does
+ * not record the number; however, this is an illusion: the original writer
+ * of the PNG may have selected a lower window size, and we really must
+ * follow that because, for systems with with limited capabilities, we
+ * would otherwise reject the application's attempts to use a smaller window
+ * size (zlib doesn't have an interface to say "this or lower"!).
+ *
+ * inflateReset2 was added to zlib 1.2.4; before this the window could not be
+ * reset, therefore it is necessary to always allocate the maximum window
+ * size with earlier zlibs just in case later compressed chunks need it.
+ */
+ {
+ int ret; /* zlib return code */
+#if ZLIB_VERNUM >= 0x1240
+ int window_bits = 0;
+
+# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW)
+ if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==
+ PNG_OPTION_ON)
+ {
+ window_bits = 15;
+ png_ptr->zstream_start = 0; /* fixed window size */
+ }
+
+ else
+ {
+ png_ptr->zstream_start = 1;
+ }
+# endif
+
+#endif /* ZLIB_VERNUM >= 0x1240 */
+
+ /* Set this for safety, just in case the previous owner left pointers to
+ * memory allocations.
+ */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->zstream.avail_out = 0;
+
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
+ {
+#if ZLIB_VERNUM >= 0x1240
+ ret = inflateReset2(&png_ptr->zstream, window_bits);
+#else
+ ret = inflateReset(&png_ptr->zstream);
+#endif
+ }
+
+ else
+ {
+#if ZLIB_VERNUM >= 0x1240
+ ret = inflateInit2(&png_ptr->zstream, window_bits);
+#else
+ ret = inflateInit(&png_ptr->zstream);
+#endif
+
+ if (ret == Z_OK)
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
+ }
+
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
+ if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON)
+ /* Turn off validation of the ADLER32 checksum in IDAT chunks */
+ ret = inflateValidate(&png_ptr->zstream, 0);
+#endif
+
+ if (ret == Z_OK)
+ png_ptr->zowner = owner;
+
+ else
+ png_zstream_error(png_ptr, ret);
+
+ return ret;
+ }
+
+#ifdef window_bits
+# undef window_bits
+#endif
+}
+
+#if ZLIB_VERNUM >= 0x1240
+/* Handle the start of the inflate stream if we called inflateInit2(strm,0);
+ * in this case some zlib versions skip validation of the CINFO field and, in
+ * certain circumstances, libpng may end up displaying an invalid image, in
+ * contrast to implementations that call zlib in the normal way (e.g. libpng
+ * 1.5).
+ */
+int /* PRIVATE */
+png_zlib_inflate(png_structrp png_ptr, int flush)
+{
+ if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0)
+ {
+ if ((*png_ptr->zstream.next_in >> 4) > 7)
+ {
+ png_ptr->zstream.msg = "invalid window size (libpng)";
+ return Z_DATA_ERROR;
+ }
+
+ png_ptr->zstream_start = 0;
+ }
+
+ return inflate(&png_ptr->zstream, flush);
+}
+#endif /* Zlib >= 1.2.4 */
+
+#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
+#if defined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_SUPPORTED)
+/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to
+ * allow the caller to do multiple calls if required. If the 'finish' flag is
+ * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must
+ * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and
+ * Z_OK or Z_STREAM_END will be returned on success.
+ *
+ * The input and output sizes are updated to the actual amounts of data consumed
+ * or written, not the amount available (as in a z_stream). The data pointers
+ * are not changed, so the next input is (data+input_size) and the next
+ * available output is (output+output_size).
+ */
+static int
+png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish,
+ /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr,
+ /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr)
+{
+ if (png_ptr->zowner == owner) /* Else not claimed */
+ {
+ int ret;
+ png_alloc_size_t avail_out = *output_size_ptr;
+ png_uint_32 avail_in = *input_size_ptr;
+
+ /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it
+ * can't even necessarily handle 65536 bytes) because the type uInt is
+ * "16 bits or more". Consequently it is necessary to chunk the input to
+ * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the
+ * maximum value that can be stored in a uInt.) It is possible to set
+ * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have
+ * a performance advantage, because it reduces the amount of data accessed
+ * at each step and that may give the OS more time to page it in.
+ */
+ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
+ /* avail_in and avail_out are set below from 'size' */
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.avail_out = 0;
+
+ /* Read directly into the output if it is available (this is set to
+ * a local buffer below if output is NULL).
+ */
+ if (output != NULL)
+ png_ptr->zstream.next_out = output;
+
+ do
+ {
+ uInt avail;
+ Byte local_buffer[PNG_INFLATE_BUF_SIZE];
+
+ /* zlib INPUT BUFFER */
+ /* The setting of 'avail_in' used to be outside the loop; by setting it
+ * inside it is possible to chunk the input to zlib and simply rely on
+ * zlib to advance the 'next_in' pointer. This allows arbitrary
+ * amounts of data to be passed through zlib at the unavoidable cost of
+ * requiring a window save (memcpy of up to 32768 output bytes)
+ * every ZLIB_IO_MAX input bytes.
+ */
+ avail_in += png_ptr->zstream.avail_in; /* not consumed last time */
+
+ avail = ZLIB_IO_MAX;
+
+ if (avail_in < avail)
+ avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */
+
+ avail_in -= avail;
+ png_ptr->zstream.avail_in = avail;
+
+ /* zlib OUTPUT BUFFER */
+ avail_out += png_ptr->zstream.avail_out; /* not written last time */
+
+ avail = ZLIB_IO_MAX; /* maximum zlib can process */
+
+ if (output == NULL)
+ {
+ /* Reset the output buffer each time round if output is NULL and
+ * make available the full buffer, up to 'remaining_space'
+ */
+ png_ptr->zstream.next_out = local_buffer;
+ if ((sizeof local_buffer) < avail)
+ avail = (sizeof local_buffer);
+ }
+
+ if (avail_out < avail)
+ avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */
+
+ png_ptr->zstream.avail_out = avail;
+ avail_out -= avail;
+
+ /* zlib inflate call */
+ /* In fact 'avail_out' may be 0 at this point, that happens at the end
+ * of the read when the final LZ end code was not passed at the end of
+ * the previous chunk of input data. Tell zlib if we have reached the
+ * end of the output buffer.
+ */
+ ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH :
+ (finish ? Z_FINISH : Z_SYNC_FLUSH));
+ } while (ret == Z_OK);
+
+ /* For safety kill the local buffer pointer now */
+ if (output == NULL)
+ png_ptr->zstream.next_out = NULL;
+
+ /* Claw back the 'size' and 'remaining_space' byte counts. */
+ avail_in += png_ptr->zstream.avail_in;
+ avail_out += png_ptr->zstream.avail_out;
+
+ /* Update the input and output sizes; the updated values are the amount
+ * consumed or written, effectively the inverse of what zlib uses.
+ */
+ if (avail_out > 0)
+ *output_size_ptr -= avail_out;
+
+ if (avail_in > 0)
+ *input_size_ptr -= avail_in;
+
+ /* Ensure png_ptr->zstream.msg is set (even in the success case!) */
+ png_zstream_error(png_ptr, ret);
+ return ret;
+ }
+
+ else
+ {
+ /* This is a bad internal error. The recovery assigns to the zstream msg
+ * pointer, which is not owned by the caller, but this is safe; it's only
+ * used on errors!
+ */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
+ return Z_STREAM_ERROR;
+ }
}
-#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
- defined(PNG_READ_iCCP_SUPPORTED)
/*
- * Decompress trailing data in a chunk. The assumption is that chunkdata
+ * Decompress trailing data in a chunk. The assumption is that read_buffer
* points at an allocated area holding the contents of a chunk with a
* trailing compressed part. What we get back is an allocated area
* holding the original prefix part and an uncompressed version of the
* trailing part (the malloc area passed in is freed).
*/
-png_charp /* PRIVATE */
-png_decompress_chunk(png_structp png_ptr, int comp_type,
- png_charp chunkdata, png_size_t chunklength,
- png_size_t prefix_size, png_size_t *newlength)
+static int
+png_decompress_chunk(png_structrp png_ptr,
+ png_uint_32 chunklength, png_uint_32 prefix_size,
+ png_alloc_size_t *newlength /* must be initialized to the maximum! */,
+ int terminate /*add a '\0' to the end of the uncompressed data*/)
{
- static PNG_CONST char msg[] = "Error decoding compressed text";
- png_charp text;
- png_size_t text_size;
+ /* TODO: implement different limits for different types of chunk.
+ *
+ * The caller supplies *newlength set to the maximum length of the
+ * uncompressed data, but this routine allocates space for the prefix and
+ * 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;
- if (comp_type == PNG_COMPRESSION_TYPE_BASE)
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
+# elif PNG_USER_CHUNK_MALLOC_MAX > 0
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
+# endif
+
+ if (limit >= prefix_size + (terminate != 0))
{
- int ret = Z_OK;
- png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
- png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ int ret;
- text_size = 0;
- text = NULL;
+ limit -= prefix_size + (terminate != 0);
- while (png_ptr->zstream.avail_in)
+ if (limit < *newlength)
+ *newlength = limit;
+
+ /* Now try to claim the stream. */
+ ret = png_inflate_claim(png_ptr, png_ptr->chunk_name);
+
+ if (ret == Z_OK)
{
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret != Z_OK && ret != Z_STREAM_END)
+ png_uint_32 lzsize = chunklength - prefix_size;
+
+ ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
+ /* input: */ png_ptr->read_buffer + prefix_size, &lzsize,
+ /* output: */ NULL, newlength);
+
+ if (ret == Z_STREAM_END)
{
- if (png_ptr->zstream.msg != NULL)
- png_warning(png_ptr, png_ptr->zstream.msg);
- else
- png_warning(png_ptr, msg);
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
-
- if (text == NULL)
+ /* Use 'inflateReset' here, not 'inflateReset2' because this
+ * preserves the previously decided window size (otherwise it would
+ * be necessary to store the previous window size.) In practice
+ * this doesn't matter anyway, because png_inflate will call inflate
+ * with Z_FINISH in almost all cases, so the window will not be
+ * maintained.
+ */
+ if (inflateReset(&png_ptr->zstream) == Z_OK)
{
- text_size = prefix_size + png_sizeof(msg) + 1;
- text = (png_charp)png_malloc_warn(png_ptr, text_size);
- if (text == NULL)
- {
- png_free(png_ptr,chunkdata);
- png_error(png_ptr,"Not enough memory to decompress chunk");
- }
- png_memcpy(text, chunkdata, prefix_size);
- }
+ /* Because of the limit checks above we know that the new,
+ * expanded, size will fit in a size_t (let alone an
+ * png_alloc_size_t). Use png_malloc_base here to avoid an
+ * extra OOM message.
+ */
+ png_alloc_size_t new_size = *newlength;
+ png_alloc_size_t buffer_size = prefix_size + new_size +
+ (terminate != 0);
+ png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr,
+ buffer_size));
- text[text_size - 1] = 0x00;
-
- /* Copy what we can of the error message into the text chunk */
- text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
- text_size = png_sizeof(msg) > text_size ? text_size :
- png_sizeof(msg);
- png_memcpy(text + prefix_size, msg, text_size + 1);
- break;
- }
- if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
- {
- if (text == NULL)
- {
- text_size = prefix_size +
- png_ptr->zbuf_size - png_ptr->zstream.avail_out;
- text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
- if (text == NULL)
- {
- png_free(png_ptr,chunkdata);
- png_error(png_ptr,"Not enough memory to decompress chunk.");
- }
- png_memcpy(text + prefix_size, png_ptr->zbuf,
- text_size - prefix_size);
- png_memcpy(text, chunkdata, prefix_size);
- *(text + text_size) = 0x00;
- }
- else
- {
- png_charp tmp;
-
- tmp = text;
- text = (png_charp)png_malloc_warn(png_ptr,
- (png_uint_32)(text_size +
- png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
- if (text == NULL)
+ if (text != NULL)
{
- png_free(png_ptr, tmp);
- png_free(png_ptr, chunkdata);
- png_error(png_ptr,"Not enough memory to decompress chunk..");
+ memset(text, 0, buffer_size);
+
+ ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
+ png_ptr->read_buffer + prefix_size, &lzsize,
+ text + prefix_size, newlength);
+
+ if (ret == Z_STREAM_END)
+ {
+ if (new_size == *newlength)
+ {
+ if (terminate != 0)
+ text[prefix_size + *newlength] = 0;
+
+ if (prefix_size > 0)
+ memcpy(text, png_ptr->read_buffer, prefix_size);
+
+ {
+ png_bytep old_ptr = png_ptr->read_buffer;
+
+ png_ptr->read_buffer = text;
+ png_ptr->read_buffer_size = buffer_size;
+ text = old_ptr; /* freed below */
+ }
+ }
+
+ else
+ {
+ /* The size changed on the second read, there can be no
+ * guarantee that anything is correct at this point.
+ * The 'msg' pointer has been set to "unexpected end of
+ * LZ stream", which is fine, but return an error code
+ * that the caller won't accept.
+ */
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+ }
+ }
+
+ else if (ret == Z_OK)
+ ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */
+
+ /* Free the text pointer (this is the old read_buffer on
+ * success)
+ */
+ png_free(png_ptr, text);
+
+ /* This really is very benign, but it's still an error because
+ * the extra space may otherwise be used as a Trojan Horse.
+ */
+ if (ret == Z_STREAM_END &&
+ chunklength - prefix_size != lzsize)
+ png_chunk_benign_error(png_ptr, "extra compressed data");
+ }
+
+ else
+ {
+ /* Out of memory allocating the buffer */
+ ret = Z_MEM_ERROR;
+ png_zstream_error(png_ptr, Z_MEM_ERROR);
}
- png_memcpy(text, tmp, text_size);
- png_free(png_ptr, tmp);
- png_memcpy(text + text_size, png_ptr->zbuf,
- (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
- text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
- *(text + text_size) = 0x00;
}
- if (ret == Z_STREAM_END)
- break;
+
else
{
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ /* inflateReset failed, store the error message */
+ png_zstream_error(png_ptr, ret);
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
}
}
- }
- if (ret != Z_STREAM_END)
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char umsg[52];
- if (ret == Z_BUF_ERROR)
- png_snprintf(umsg, 52,
- "Buffer error in compressed datastream in %s chunk",
- png_ptr->chunk_name);
- else if (ret == Z_DATA_ERROR)
- png_snprintf(umsg, 52,
- "Data error in compressed datastream in %s chunk",
- png_ptr->chunk_name);
- else
- png_snprintf(umsg, 52,
- "Incomplete compressed datastream in %s chunk",
- png_ptr->chunk_name);
- png_warning(png_ptr, umsg);
-#else
- png_warning(png_ptr,
- "Incomplete compressed datastream in chunk other than IDAT");
-#endif
- text_size=prefix_size;
- if (text == NULL)
- {
- text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
- if (text == NULL)
- {
- png_free(png_ptr, chunkdata);
- png_error(png_ptr,"Not enough memory for text.");
- }
- png_memcpy(text, chunkdata, prefix_size);
- }
- *(text + text_size) = 0x00;
+ else if (ret == Z_OK)
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+
+ /* Release the claimed stream */
+ png_ptr->zowner = 0;
}
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
+ else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
- png_free(png_ptr, chunkdata);
- chunkdata = text;
- *newlength=text_size;
+ return ret;
}
- else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
+
+ else
{
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char umsg[50];
+ /* Application/configuration limits exceeded */
+ png_zstream_error(png_ptr, Z_MEM_ERROR);
+ return Z_MEM_ERROR;
+ }
+}
+#endif /* READ_zTXt || READ_iTXt */
+#endif /* READ_COMPRESSED_TEXT */
- png_snprintf(umsg, 50,
- "Unknown zTXt compression type %d", comp_type);
- png_warning(png_ptr, umsg);
-#else
- png_warning(png_ptr, "Unknown zTXt compression type");
-#endif
+#ifdef PNG_READ_iCCP_SUPPORTED
+/* Perform a partial read and decompress, producing 'avail_out' bytes and
+ * reading from the current chunk as required.
+ */
+static int
+png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,
+ png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size,
+ int finish)
+{
+ if (png_ptr->zowner == png_ptr->chunk_name)
+ {
+ int ret;
- *(chunkdata + prefix_size) = 0x00;
- *newlength=prefix_size;
+ /* next_in and avail_in must have been initialized by the caller. */
+ png_ptr->zstream.next_out = next_out;
+ png_ptr->zstream.avail_out = 0; /* set in the loop */
+
+ do
+ {
+ if (png_ptr->zstream.avail_in == 0)
+ {
+ if (read_size > *chunk_bytes)
+ read_size = (uInt)*chunk_bytes;
+ *chunk_bytes -= read_size;
+
+ if (read_size > 0)
+ png_crc_read(png_ptr, read_buffer, read_size);
+
+ png_ptr->zstream.next_in = read_buffer;
+ png_ptr->zstream.avail_in = read_size;
+ }
+
+ if (png_ptr->zstream.avail_out == 0)
+ {
+ uInt avail = ZLIB_IO_MAX;
+ if (avail > *out_size)
+ avail = (uInt)*out_size;
+ *out_size -= avail;
+
+ png_ptr->zstream.avail_out = avail;
+ }
+
+ /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all
+ * the available output is produced; this allows reading of truncated
+ * streams.
+ */
+ ret = PNG_INFLATE(png_ptr, *chunk_bytes > 0 ?
+ Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH));
+ }
+ while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0));
+
+ *out_size += png_ptr->zstream.avail_out;
+ png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */
+
+ /* Ensure the error message pointer is always set: */
+ png_zstream_error(png_ptr, ret);
+ return ret;
}
- return chunkdata;
+ else
+ {
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
+ return Z_STREAM_ERROR;
+ }
}
-#endif
+#endif /* READ_iCCP */
+
+/* Read and check the IDHR chunk */
-/* read and check the IDHR chunk */
void /* PRIVATE */
-png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[13];
png_uint_32 width, height;
int bit_depth, color_type, compression_type, filter_type;
int interlace_type;
- png_debug(1, "in png_handle_IHDR\n");
+ png_debug(1, "in png_handle_IHDR");
- if (png_ptr->mode & PNG_HAVE_IHDR)
- png_error(png_ptr, "Out of place IHDR");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)
+ png_chunk_error(png_ptr, "out of place");
- /* check the length */
+ /* Check the length */
if (length != 13)
- png_error(png_ptr, "Invalid IHDR chunk");
+ png_chunk_error(png_ptr, "invalid");
png_ptr->mode |= PNG_HAVE_IHDR;
@@ -374,79 +863,92 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
filter_type = buf[11];
interlace_type = buf[12];
- /* set internal variables */
+ /* Set internal variables */
png_ptr->width = width;
png_ptr->height = height;
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->interlaced = (png_byte)interlace_type;
png_ptr->color_type = (png_byte)color_type;
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
+#ifdef PNG_MNG_FEATURES_SUPPORTED
png_ptr->filter_type = (png_byte)filter_type;
#endif
png_ptr->compression_type = (png_byte)compression_type;
- /* find number of channels */
+ /* Find number of channels */
switch (png_ptr->color_type)
{
+ default: /* invalid, png_set_IHDR calls png_error */
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_PALETTE:
png_ptr->channels = 1;
break;
+
case PNG_COLOR_TYPE_RGB:
png_ptr->channels = 3;
break;
+
case PNG_COLOR_TYPE_GRAY_ALPHA:
png_ptr->channels = 2;
break;
+
case PNG_COLOR_TYPE_RGB_ALPHA:
png_ptr->channels = 4;
break;
}
- /* set up other useful info */
- png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
- png_ptr->channels);
- png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
- png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
- png_debug1(3,"channels = %d\n", png_ptr->channels);
- png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
+ /* Set up other useful info */
+ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels);
+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
+ 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);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
- color_type, interlace_type, compression_type, filter_type);
+ color_type, interlace_type, compression_type, filter_type);
}
-/* read and check the palette */
+/* Read and check the palette */
void /* PRIVATE */
-png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_color palette[PNG_MAX_PALETTE_LENGTH];
- int num, i;
-#ifndef PNG_NO_POINTER_INDEXING
+ int max_palette_length, num, i;
+#ifdef PNG_POINTER_INDEXING_SUPPORTED
png_colorp pal_ptr;
#endif
- png_debug(1, "in png_handle_PLTE\n");
+ png_debug(1, "in png_handle_PLTE");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before PLTE");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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.)
+ */
+ else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
+ png_chunk_error(png_ptr, "duplicate");
+
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid PLTE after IDAT");
+ /* 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;
}
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- png_error(png_ptr, "Duplicate PLTE chunk");
png_ptr->mode |= PNG_HAVE_PLTE;
- if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
{
- png_warning(png_ptr,
- "Ignoring PLTE chunk in grayscale PNG");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");
return;
}
-#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+
+#ifndef PNG_READ_OPT_PLTE_SUPPORTED
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
{
png_crc_finish(png_ptr, length);
@@ -456,21 +958,34 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
{
+ png_crc_finish(png_ptr, length);
+
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
- {
- png_warning(png_ptr, "Invalid palette chunk");
- png_crc_finish(png_ptr, length);
- return;
- }
+ png_chunk_benign_error(png_ptr, "invalid");
+
else
- {
- png_error(png_ptr, "Invalid palette chunk");
- }
+ png_chunk_error(png_ptr, "invalid");
+
+ return;
}
+ /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
num = (int)length / 3;
-#ifndef PNG_NO_POINTER_INDEXING
+ /* 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;
+
+#ifdef PNG_POINTER_INDEXING_SUPPORTED
for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
{
png_byte buf[3];
@@ -486,229 +1001,225 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_byte buf[3];
png_crc_read(png_ptr, buf, 3);
- /* don't depend upon png_color being any order */
+ /* Don't depend upon png_color being any order */
palette[i].red = buf[0];
palette[i].green = buf[1];
palette[i].blue = buf[2];
}
#endif
- /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
- whatever the normal CRC configuration tells us. However, if we
- have an RGB image, the PLTE can be considered ancillary, so
- we will act as though it is. */
-#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ /* 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
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
#endif
{
- png_crc_finish(png_ptr, 0);
+ png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3));
}
-#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
- else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+
+#ifndef PNG_READ_OPT_PLTE_SUPPORTED
+ else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */
{
/* 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). */
- if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ * 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)
- {
- png_chunk_error(png_ptr, "CRC error");
- }
- else
- {
- png_chunk_warning(png_ptr, "CRC error");
+ 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))
- {
+ else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)
png_chunk_warning(png_ptr, "CRC error");
- }
}
#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.
+ */
png_set_PLTE(png_ptr, info_ptr, palette, num);
-#if defined(PNG_READ_tRNS_SUPPORTED)
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ /* 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))
{
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
- {
- if (png_ptr->num_trans > (png_uint_16)num)
- {
- png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
- png_ptr->num_trans = (png_uint_16)num;
- }
- if (info_ptr->num_trans > (png_uint_16)num)
- {
- png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
- info_ptr->num_trans = (png_uint_16)num;
- }
- }
+ /* 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
}
void /* PRIVATE */
-png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_debug(1, "in png_handle_IEND\n");
+ png_debug(1, "in png_handle_IEND");
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
- {
- png_error(png_ptr, "No image in file");
- }
+ 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);
- if (length != 0)
- {
- png_warning(png_ptr, "Incorrect IEND chunk length");
- }
png_crc_finish(png_ptr, length);
- info_ptr =info_ptr; /* quiet compiler warnings about unused info_ptr */
+ if (length != 0)
+ png_chunk_benign_error(png_ptr, "invalid");
+
+ PNG_UNUSED(info_ptr)
}
-#if defined(PNG_READ_gAMA_SUPPORTED)
+#ifdef PNG_READ_gAMA_SUPPORTED
void /* PRIVATE */
-png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_fixed_point igamma;
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float file_gamma;
-#endif
png_byte buf[4];
- png_debug(1, "in png_handle_gAMA\n");
+ png_debug(1, "in png_handle_gAMA");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before gAMA");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- png_warning(png_ptr, "Invalid gAMA after IDAT");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Out of place gAMA chunk");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
-#if defined(PNG_READ_sRGB_SUPPORTED)
- && !(info_ptr->valid & PNG_INFO_sRGB)
-#endif
- )
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Duplicate gAMA chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 4)
{
- png_warning(png_ptr, "Incorrect gAMA chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 4);
- if (png_crc_finish(png_ptr, 0))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- igamma = (png_fixed_point)png_get_uint_32(buf);
- /* check for zero gamma */
- if (igamma == 0)
- {
- png_warning(png_ptr,
- "Ignoring gAMA chunk with gamma=0");
- return;
- }
+ igamma = png_get_fixed_point(NULL, buf);
-#if defined(PNG_READ_sRGB_SUPPORTED)
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
- if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
- {
- png_warning(png_ptr,
- "Ignoring incorrect gAMA value when sRGB is also present");
-#ifndef PNG_NO_CONSOLE_IO
- fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
-#endif
- return;
- }
-#endif /* PNG_READ_sRGB_SUPPORTED */
-
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- file_gamma = (float)igamma / (float)100000.0;
-# ifdef PNG_READ_GAMMA_SUPPORTED
- png_ptr->gamma = file_gamma;
-# endif
- png_set_gAMA(png_ptr, info_ptr, file_gamma);
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
-#endif
+ png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);
+ png_colorspace_sync(png_ptr, info_ptr);
}
#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
+#ifdef PNG_READ_sBIT_SUPPORTED
void /* PRIVATE */
-png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t truelen;
+ unsigned int truelen, i;
+ png_byte sample_depth;
png_byte buf[4];
- png_debug(1, "in png_handle_sBIT\n");
+ png_debug(1, "in png_handle_sBIT");
- buf[0] = buf[1] = buf[2] = buf[3] = 0;
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sBIT");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Invalid sBIT after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (png_ptr->mode & PNG_HAVE_PLTE)
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0)
{
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Out of place sBIT chunk");
- }
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
- {
- png_warning(png_ptr, "Duplicate sBIT chunk");
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;
+ sample_depth = 8;
+ }
+
else
- truelen = (png_size_t)png_ptr->channels;
+ {
+ truelen = png_ptr->channels;
+ sample_depth = png_ptr->bit_depth;
+ }
if (length != truelen || length > 4)
{
- png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_chunk_benign_error(png_ptr, "invalid");
png_crc_finish(png_ptr, length);
return;
}
+ buf[0] = buf[1] = buf[2] = buf[3] = sample_depth;
png_crc_read(png_ptr, buf, truelen);
- if (png_crc_finish(png_ptr, 0))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ for (i=0; i sample_depth)
+ {
+ png_chunk_benign_error(png_ptr, "invalid");
+ return;
+ }
+ }
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_ptr->sig_bit.red = buf[0];
png_ptr->sig_bit.green = buf[1];
png_ptr->sig_bit.blue = buf[2];
png_ptr->sig_bit.alpha = buf[3];
}
+
else
{
png_ptr->sig_bit.gray = buf[0];
@@ -717,551 +1228,610 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_ptr->sig_bit.blue = buf[0];
png_ptr->sig_bit.alpha = buf[1];
}
+
png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
}
#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
+#ifdef PNG_READ_cHRM_SUPPORTED
void /* PRIVATE */
-png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_byte buf[4];
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
-#endif
- png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
- int_y_green, int_x_blue, int_y_blue;
+ png_byte buf[32];
+ png_xy xy;
- png_uint_32 uint_x, uint_y;
+ png_debug(1, "in png_handle_cHRM");
- png_debug(1, "in png_handle_cHRM\n");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before cHRM");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Invalid cHRM after IDAT");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Missing PLTE before cHRM");
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
-#if defined(PNG_READ_sRGB_SUPPORTED)
- && !(info_ptr->valid & PNG_INFO_sRGB)
-#endif
- )
- {
- png_warning(png_ptr, "Duplicate cHRM chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 32)
{
- png_warning(png_ptr, "Incorrect cHRM chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- png_crc_read(png_ptr, buf, 4);
- uint_x = png_get_uint_32(buf);
+ png_crc_read(png_ptr, buf, 32);
- png_crc_read(png_ptr, buf, 4);
- uint_y = png_get_uint_32(buf);
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return;
- if (uint_x > 80000L || uint_y > 80000L ||
- uint_x + uint_y > 100000L)
+ 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)
{
- png_warning(png_ptr, "Invalid cHRM white point");
- png_crc_finish(png_ptr, 24);
+ png_chunk_benign_error(png_ptr, "invalid values");
return;
}
- int_x_white = (png_fixed_point)uint_x;
- int_y_white = (png_fixed_point)uint_y;
- png_crc_read(png_ptr, buf, 4);
- uint_x = png_get_uint_32(buf);
+ /* If a colorspace error has already been output skip this chunk */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
+ return;
- png_crc_read(png_ptr, buf, 4);
- uint_y = png_get_uint_32(buf);
-
- if (uint_x + uint_y > 100000L)
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0)
{
- png_warning(png_ptr, "Invalid cHRM red point");
- png_crc_finish(png_ptr, 16);
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
+ png_colorspace_sync(png_ptr, info_ptr);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
- int_x_red = (png_fixed_point)uint_x;
- int_y_red = (png_fixed_point)uint_y;
- png_crc_read(png_ptr, buf, 4);
- uint_x = png_get_uint_32(buf);
-
- png_crc_read(png_ptr, buf, 4);
- uint_y = png_get_uint_32(buf);
-
- if (uint_x + uint_y > 100000L)
- {
- png_warning(png_ptr, "Invalid cHRM green point");
- png_crc_finish(png_ptr, 8);
- return;
- }
- int_x_green = (png_fixed_point)uint_x;
- int_y_green = (png_fixed_point)uint_y;
-
- png_crc_read(png_ptr, buf, 4);
- uint_x = png_get_uint_32(buf);
-
- png_crc_read(png_ptr, buf, 4);
- uint_y = png_get_uint_32(buf);
-
- if (uint_x + uint_y > 100000L)
- {
- png_warning(png_ptr, "Invalid cHRM blue point");
- png_crc_finish(png_ptr, 0);
- return;
- }
- int_x_blue = (png_fixed_point)uint_x;
- int_y_blue = (png_fixed_point)uint_y;
-
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- white_x = (float)int_x_white / (float)100000.0;
- white_y = (float)int_y_white / (float)100000.0;
- red_x = (float)int_x_red / (float)100000.0;
- red_y = (float)int_y_red / (float)100000.0;
- green_x = (float)int_x_green / (float)100000.0;
- green_y = (float)int_y_green / (float)100000.0;
- blue_x = (float)int_x_blue / (float)100000.0;
- blue_y = (float)int_y_blue / (float)100000.0;
-#endif
-
-#if defined(PNG_READ_sRGB_SUPPORTED)
- if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
- {
- if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
- PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
- PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
- PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
- PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
- PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
- {
- png_warning(png_ptr,
- "Ignoring incorrect cHRM value when sRGB is also present");
-#ifndef PNG_NO_CONSOLE_IO
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
- white_x, white_y, red_x, red_y);
- fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
- green_x, green_y, blue_x, blue_y);
-#else
- fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
- int_x_white, int_y_white, int_x_red, int_y_red);
- fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
- int_x_green, int_y_green, int_x_blue, int_y_blue);
-#endif
-#endif /* PNG_NO_CONSOLE_IO */
- }
- png_crc_finish(png_ptr, 0);
- return;
- }
-#endif /* PNG_READ_sRGB_SUPPORTED */
-
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- png_set_cHRM(png_ptr, info_ptr,
- white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_set_cHRM_fixed(png_ptr, info_ptr,
- int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
- int_y_green, int_x_blue, int_y_blue);
-#endif
- if (png_crc_finish(png_ptr, 0))
- return;
+ 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);
}
#endif
-#if defined(PNG_READ_sRGB_SUPPORTED)
+#ifdef PNG_READ_sRGB_SUPPORTED
void /* PRIVATE */
-png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- int intent;
- png_byte buf[1];
+ png_byte intent;
- png_debug(1, "in png_handle_sRGB\n");
+ png_debug(1, "in png_handle_sRGB");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sRGB");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid sRGB after IDAT");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Out of place sRGB chunk");
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
- {
- png_warning(png_ptr, "Duplicate sRGB chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 1)
{
- png_warning(png_ptr, "Incorrect sRGB chunk length");
+ 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;
+
+ /* If a colorspace error has already been output skip this chunk */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
+ return;
+
+ /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
+ * this.
+ */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)
+ {
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
+ png_colorspace_sync(png_ptr, info_ptr);
+ png_chunk_benign_error(png_ptr, "too many profiles");
+ return;
+ }
+
+ (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
+ png_colorspace_sync(png_ptr, info_ptr);
+}
+#endif /* READ_sRGB */
+
+#ifdef PNG_READ_iCCP_SUPPORTED
+void /* 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 */
+{
+ png_const_charp errmsg = NULL; /* error message output, or no error */
+ int finished = 0; /* crc checked */
+
+ 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.
+ */
+
+ /* 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;
}
- png_crc_read(png_ptr, buf, 1);
- if (png_crc_finish(png_ptr, 0))
- return;
-
- intent = buf[0];
- /* check for bad intent */
- if (intent >= PNG_sRGB_INTENT_LAST)
+ /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
+ * this.
+ */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)
{
- png_warning(png_ptr, "Unknown sRGB intent");
- return;
+ uInt read_length, keyword_length;
+ char keyword[81];
+
+ /* Find the keyword; the keyword plus separator and compression method
+ * bytes can be at most 81 characters long.
+ */
+ read_length = 81; /* maximum */
+ if (read_length > length)
+ read_length = (uInt)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)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "too short");
+ return;
+ }
+
+ keyword_length = 0;
+ while (keyword_length < 80 && keyword_length < read_length &&
+ keyword[keyword_length] != 0)
+ ++keyword_length;
+
+ /* TODO: make the keyword checking common */
+ if (keyword_length >= 1 && keyword_length <= 79)
+ {
+ /* We only understand '0' compression - deflate - so if we get a
+ * different value we can't safely decode the chunk.
+ */
+ if (keyword_length+1 < read_length &&
+ keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE)
+ {
+ read_length -= keyword_length+2;
+
+ if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)
+ {
+ Byte profile_header[132]={0};
+ Byte local_buffer[PNG_INFLATE_BUF_SIZE];
+ png_alloc_size_t size = (sizeof profile_header);
+
+ png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2);
+ png_ptr->zstream.avail_in = read_length;
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length, profile_header, &size,
+ 0/*finish: don't, because the output is too small*/);
+
+ if (size == 0)
+ {
+ /* We have the ICC profile header; do the basic header checks.
+ */
+ 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)
+ {
+ /* 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)
+ {
+ /* Now read the tag table; a variable size buffer is
+ * needed at this point, allocate one for the whole
+ * profile. The header check has already validated
+ * that none of this stuff will overflow.
+ */
+ png_uint_32 tag_count =
+ png_get_uint_32(profile_header + 128);
+ png_bytep profile = png_read_buffer(png_ptr,
+ profile_length, 2/*silent*/);
+
+ if (profile != NULL)
+ {
+ memcpy(profile, profile_header,
+ (sizeof profile_header));
+
+ size = 12 * tag_count;
+
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length,
+ profile + (sizeof profile_header), &size, 0);
+
+ /* Still expect a buffer error because we expect
+ * there to be some tag data!
+ */
+ if (size == 0)
+ {
+ if (png_icc_check_tag_table(png_ptr,
+ &png_ptr->colorspace, keyword, profile_length,
+ profile) != 0)
+ {
+ /* The profile has been validated for basic
+ * security issues, so read the whole thing in.
+ */
+ size = profile_length - (sizeof profile_header)
+ - 12 * tag_count;
+
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length,
+ profile + (sizeof profile_header) +
+ 12 * tag_count, &size, 1/*finish*/);
+
+ if (length > 0 && !(png_ptr->flags &
+ PNG_FLAG_BENIGN_ERRORS_WARN))
+ errmsg = "extra compressed data";
+
+ /* But otherwise allow extra data: */
+ else if (size == 0)
+ {
+ if (length > 0)
+ {
+ /* This can be handled completely, so
+ * keep going.
+ */
+ png_chunk_warning(png_ptr,
+ "extra compressed data");
+ }
+
+ 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)
+ {
+ png_free_data(png_ptr, info_ptr,
+ PNG_FREE_ICCP, 0);
+
+ info_ptr->iccp_name = png_voidcast(char*,
+ png_malloc_base(png_ptr,
+ keyword_length+1));
+ if (info_ptr->iccp_name != NULL)
+ {
+ memcpy(info_ptr->iccp_name, keyword,
+ keyword_length+1);
+ info_ptr->iccp_proflen =
+ profile_length;
+ info_ptr->iccp_profile = profile;
+ png_ptr->read_buffer = NULL; /*steal*/
+ info_ptr->free_me |= PNG_FREE_ICCP;
+ info_ptr->valid |= PNG_INFO_iCCP;
+ }
+
+ else
+ {
+ png_ptr->colorspace.flags |=
+ PNG_COLORSPACE_INVALID;
+ errmsg = "out of memory";
+ }
+ }
+
+ /* else the profile remains in the read
+ * buffer which gets reused for subsequent
+ * chunks.
+ */
+
+ if (info_ptr != NULL)
+ png_colorspace_sync(png_ptr, info_ptr);
+
+ if (errmsg == NULL)
+ {
+ png_ptr->zowner = 0;
+ return;
+ }
+ }
+ if (errmsg == NULL)
+ errmsg = png_ptr->zstream.msg;
+ }
+ /* else png_icc_check_tag_table output an error */
+ }
+ else /* profile truncated */
+ errmsg = png_ptr->zstream.msg;
+ }
+
+ else
+ errmsg = "out of memory";
+ }
+
+ /* else png_icc_check_header output an error */
+ }
+
+ /* else png_icc_check_length output an error */
+ }
+
+ else /* profile truncated */
+ errmsg = png_ptr->zstream.msg;
+
+ /* Release the stream */
+ png_ptr->zowner = 0;
+ }
+
+ else /* png_inflate_claim failed */
+ errmsg = png_ptr->zstream.msg;
+ }
+
+ else
+ errmsg = "bad compression method"; /* or missing */
+ }
+
+ else
+ errmsg = "bad keyword";
}
-#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
+ 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);
+}
+#endif /* READ_iCCP */
+
+#ifdef PNG_READ_sPLT_SUPPORTED
+void /* 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 */
+{
+ png_bytep entry_start, buffer;
+ png_sPLT_t new_palette;
+ png_sPLT_entryp pp;
+ png_uint_32 data_length;
+ int entry_size, i;
+ png_uint_32 skip = 0;
+ png_uint_32 dl;
+ size_t max_dl;
+
+ png_debug(1, "in png_handle_sPLT");
+
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_cache_max != 0)
{
- png_fixed_point igamma;
-#ifdef PNG_FIXED_POINT_SUPPORTED
- igamma=info_ptr->int_gamma;
-#else
-# ifdef PNG_FLOATING_POINT_SUPPORTED
- igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
-# endif
-#endif
- if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
+ if (png_ptr->user_chunk_cache_max == 1)
{
- png_warning(png_ptr,
- "Ignoring incorrect gAMA value when sRGB is also present");
-#ifndef PNG_NO_CONSOLE_IO
-# ifdef PNG_FIXED_POINT_SUPPORTED
- fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
-# else
-# ifdef PNG_FLOATING_POINT_SUPPORTED
- fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
-# endif
-# endif
-#endif
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ 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;
}
}
-#endif /* PNG_READ_gAMA_SUPPORTED */
+#endif
-#ifdef PNG_READ_cHRM_SUPPORTED
-#ifdef PNG_FIXED_POINT_SUPPORTED
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
- if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
- {
- png_warning(png_ptr,
- "Ignoring incorrect cHRM value when sRGB is also present");
- }
-#endif /* PNG_FIXED_POINT_SUPPORTED */
-#endif /* PNG_READ_cHRM_SUPPORTED */
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
-}
-#endif /* PNG_READ_sRGB_SUPPORTED */
-
-#if defined(PNG_READ_iCCP_SUPPORTED)
-void /* PRIVATE */
-png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
-/* Note: this does not properly handle chunks that are > 64K under DOS */
-{
- png_charp chunkdata;
- png_byte compression_type;
- png_bytep pC;
- png_charp profile;
- png_uint_32 skip = 0;
- png_uint_32 profile_size, profile_length;
- png_size_t slength, prefix_length, data_length;
-
- png_debug(1, "in png_handle_iCCP\n");
-
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before iCCP");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid iCCP after IDAT");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Out of place iCCP chunk");
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
- {
- png_warning(png_ptr, "Duplicate iCCP chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+ if (length > 65535U)
{
- png_warning(png_ptr, "iCCP chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
-
- chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
-
- if (png_crc_finish(png_ptr, skip))
- {
- png_free(png_ptr, chunkdata);
- return;
- }
-
- chunkdata[slength] = 0x00;
-
- for (profile = chunkdata; *profile; profile++)
- /* empty loop to find end of name */ ;
-
- ++profile;
-
- /* there should be at least one zero (the compression type byte)
- following the separator, and we should be on it */
- if ( profile >= chunkdata + slength - 1)
- {
- png_free(png_ptr, chunkdata);
- png_warning(png_ptr, "Malformed iCCP chunk");
- return;
- }
-
- /* compression_type should always be zero */
- compression_type = *profile++;
- if (compression_type)
- {
- png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
- compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
- wrote nonzero) */
- }
-
- prefix_length = profile - chunkdata;
- chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
- slength, prefix_length, &data_length);
-
- profile_length = data_length - prefix_length;
-
- if ( prefix_length > data_length || profile_length < 4)
- {
- png_free(png_ptr, chunkdata);
- png_warning(png_ptr, "Profile size field missing from iCCP chunk");
- return;
- }
-
- /* Check the profile_size recorded in the first 32 bits of the ICC profile */
- pC = (png_bytep)(chunkdata+prefix_length);
- profile_size = ((*(pC ))<<24) |
- ((*(pC+1))<<16) |
- ((*(pC+2))<< 8) |
- ((*(pC+3)) );
-
- if(profile_size < profile_length)
- profile_length = profile_size;
-
- if(profile_size > profile_length)
- {
- png_free(png_ptr, chunkdata);
- png_warning(png_ptr, "Ignoring truncated iCCP profile.");
- return;
- }
-
- png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
- chunkdata + prefix_length, profile_length);
- png_free(png_ptr, chunkdata);
-}
-#endif /* PNG_READ_iCCP_SUPPORTED */
-
-#if defined(PNG_READ_sPLT_SUPPORTED)
-void /* PRIVATE */
-png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
-/* Note: this does not properly handle chunks that are > 64K under DOS */
-{
- png_bytep chunkdata;
- png_bytep entry_start;
- png_sPLT_t new_palette;
-#ifdef PNG_NO_POINTER_INDEXING
- png_sPLT_entryp pp;
-#endif
- int data_length, entry_size, i;
- png_uint_32 skip = 0;
- png_size_t slength;
-
- png_debug(1, "in png_handle_sPLT\n");
-
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sPLT");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- png_warning(png_ptr, "Invalid sPLT after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "too large to fit in memory");
return;
}
-
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr, "sPLT chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
#endif
- chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
-
- if (png_crc_finish(png_ptr, skip))
+ buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+ if (buffer == NULL)
{
- png_free(png_ptr, chunkdata);
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- chunkdata[slength] = 0x00;
- for (entry_start = chunkdata; *entry_start; entry_start++)
- /* empty loop to find end of name */ ;
+ /* WARNING: this may break if size_t is less than 32 bits; it is assumed
+ * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
+ * potential breakage point if the types in pngconf.h aren't exactly right.
+ */
+ png_crc_read(png_ptr, buffer, length);
+
+ if (png_crc_finish(png_ptr, skip) != 0)
+ return;
+
+ buffer[length] = 0;
+
+ for (entry_start = buffer; *entry_start; entry_start++)
+ /* Empty loop to find end of name */ ;
+
++entry_start;
- /* a sample depth should follow the separator, and we should be on it */
- if (entry_start > chunkdata + slength - 2)
+ /* A sample depth should follow the separator, and we should be on it */
+ if (length < 2U || entry_start > buffer + (length - 2U))
{
- png_free(png_ptr, chunkdata);
png_warning(png_ptr, "malformed sPLT chunk");
return;
}
new_palette.depth = *entry_start++;
entry_size = (new_palette.depth == 8 ? 6 : 10);
- data_length = (slength - (entry_start - chunkdata));
+ /* This must fit in a png_uint_32 because it is derived from the original
+ * chunk data length.
+ */
+ data_length = length - (png_uint_32)(entry_start - buffer);
- /* integrity-check the data length */
- if (data_length % entry_size)
+ /* Integrity-check the data length */
+ if ((data_length % (unsigned int)entry_size) != 0)
{
- png_free(png_ptr, chunkdata);
png_warning(png_ptr, "sPLT chunk has bad length");
return;
}
- new_palette.nentries = (png_int_32) ( data_length / entry_size);
- if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX /
- png_sizeof(png_sPLT_entry)))
+ dl = (png_uint_32)(data_length / (unsigned int)entry_size);
+ max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));
+
+ if (dl > max_dl)
{
- png_warning(png_ptr, "sPLT chunk too long");
- return;
- }
- new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
- png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
- if (new_palette.entries == NULL)
- {
- png_warning(png_ptr, "sPLT chunk requires too much memory");
- return;
+ png_warning(png_ptr, "sPLT chunk too long");
+ return;
}
-#ifndef PNG_NO_POINTER_INDEXING
+ new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size);
+
+ new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
+ (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry)));
+
+ if (new_palette.entries == NULL)
+ {
+ png_warning(png_ptr, "sPLT chunk requires too much memory");
+ return;
+ }
+
+#ifdef PNG_POINTER_INDEXING_SUPPORTED
for (i = 0; i < new_palette.nentries; i++)
{
- png_sPLT_entryp pp = new_palette.entries + i;
+ pp = new_palette.entries + i;
if (new_palette.depth == 8)
{
- pp->red = *entry_start++;
- pp->green = *entry_start++;
- pp->blue = *entry_start++;
- pp->alpha = *entry_start++;
+ pp->red = *entry_start++;
+ pp->green = *entry_start++;
+ pp->blue = *entry_start++;
+ pp->alpha = *entry_start++;
}
+
else
{
- pp->red = png_get_uint_16(entry_start); entry_start += 2;
- pp->green = png_get_uint_16(entry_start); entry_start += 2;
- pp->blue = png_get_uint_16(entry_start); entry_start += 2;
- pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
+ pp->red = png_get_uint_16(entry_start); entry_start += 2;
+ pp->green = png_get_uint_16(entry_start); entry_start += 2;
+ pp->blue = png_get_uint_16(entry_start); entry_start += 2;
+ pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
}
+
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++;
+ 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].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->frequency = 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)chunkdata;
+ /* Discard all chunk data except the name and stash that */
+ new_palette.name = (png_charp)buffer;
png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
- png_free(png_ptr, chunkdata);
png_free(png_ptr, new_palette.entries);
}
-#endif /* PNG_READ_sPLT_SUPPORTED */
+#endif /* READ_sPLT */
-#if defined(PNG_READ_tRNS_SUPPORTED)
+#ifdef PNG_READ_tRNS_SUPPORTED
void /* PRIVATE */
-png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
- int bit_mask;
- png_debug(1, "in png_handle_tRNS\n");
+ png_debug(1, "in png_handle_tRNS");
- /* For non-indexed color, mask off any bits in the tRNS value that
- * exceed the bit depth. Some creators were writing extra bits there.
- * This is not needed for indexed color. */
- bit_mask = (1 << png_ptr->bit_depth) - 1;
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before tRNS");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid tRNS after IDAT");
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))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)
{
- png_warning(png_ptr, "Duplicate tRNS chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
@@ -1271,197 +1841,296 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length != 2)
{
- png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 2);
png_ptr->num_trans = 1;
- png_ptr->trans_values.gray = png_get_uint_16(buf) & bit_mask;
+ png_ptr->trans_color.gray = png_get_uint_16(buf);
}
+
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
png_byte buf[6];
if (length != 6)
{
- png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- png_crc_read(png_ptr, buf, (png_size_t)length);
+
+ png_crc_read(png_ptr, buf, length);
png_ptr->num_trans = 1;
- png_ptr->trans_values.red = png_get_uint_16(buf) & bit_mask;
- png_ptr->trans_values.green = png_get_uint_16(buf + 2) & bit_mask;
- png_ptr->trans_values.blue = png_get_uint_16(buf + 4) & bit_mask;
+ png_ptr->trans_color.red = png_get_uint_16(buf);
+ png_ptr->trans_color.green = png_get_uint_16(buf + 2);
+ png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
}
+
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
{
- /* Should be an error, but we can cope with it. */
- png_warning(png_ptr, "Missing PLTE before tRNS");
- }
- if (length > (png_uint_32)png_ptr->num_palette ||
- length > PNG_MAX_PALETTE_LENGTH)
- {
- png_warning(png_ptr, "Incorrect tRNS chunk length");
+ /* 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;
}
- if (length == 0)
+
+ if (length > (unsigned int) png_ptr->num_palette ||
+ length > (unsigned int) PNG_MAX_PALETTE_LENGTH ||
+ length == 0)
{
- png_warning(png_ptr, "Zero length tRNS chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- png_crc_read(png_ptr, readbuf, (png_size_t)length);
+
+ png_crc_read(png_ptr, readbuf, length);
png_ptr->num_trans = (png_uint_16)length;
}
+
else
{
- png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid with alpha channel");
return;
}
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
{
png_ptr->num_trans = 0;
return;
}
+ /* TODO: this is a horrible side effect in the palette case because the
+ * png_struct ends up with a pointer to the tRNS buffer owned by the
+ * png_info. Fix this.
+ */
png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
- &(png_ptr->trans_values));
+ &(png_ptr->trans_color));
}
#endif
-#if defined(PNG_READ_bKGD_SUPPORTED)
+#ifdef PNG_READ_bKGD_SUPPORTED
void /* PRIVATE */
-png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t truelen;
+ unsigned int truelen;
png_byte buf[6];
+ png_color_16 background;
- png_debug(1, "in png_handle_bKGD\n");
+ png_debug(1, "in png_handle_bKGD");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before bKGD");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid bKGD after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
{
- png_warning(png_ptr, "Missing PLTE before bKGD");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
- {
- png_warning(png_ptr, "Duplicate bKGD chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
truelen = 1;
- else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+
+ else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
truelen = 6;
+
else
truelen = 2;
if (length != truelen)
{
- png_warning(png_ptr, "Incorrect bKGD chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, truelen);
- if (png_crc_finish(png_ptr, 0))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
/* We convert the index value into RGB components so that we can allow
* arbitrary RGB values for background when we have transparency, and
* so it is easy to determine the RGB values of the background color
- * from the info_ptr struct. */
+ * from the info_ptr struct.
+ */
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- png_ptr->background.index = buf[0];
- if(info_ptr->num_palette)
+ background.index = buf[0];
+
+ if (info_ptr != NULL && info_ptr->num_palette != 0)
{
- if(buf[0] > info_ptr->num_palette)
- {
- png_warning(png_ptr, "Incorrect bKGD chunk index value");
- return;
- }
- png_ptr->background.red =
- (png_uint_16)png_ptr->palette[buf[0]].red;
- png_ptr->background.green =
- (png_uint_16)png_ptr->palette[buf[0]].green;
- png_ptr->background.blue =
- (png_uint_16)png_ptr->palette[buf[0]].blue;
+ if (buf[0] >= info_ptr->num_palette)
+ {
+ png_chunk_benign_error(png_ptr, "invalid index");
+ return;
+ }
+
+ background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
+ background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
+ background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
}
- }
- else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
- {
- png_ptr->background.red =
- png_ptr->background.green =
- png_ptr->background.blue =
- png_ptr->background.gray = png_get_uint_16(buf);
- }
- else
- {
- png_ptr->background.red = png_get_uint_16(buf);
- png_ptr->background.green = png_get_uint_16(buf + 2);
- png_ptr->background.blue = png_get_uint_16(buf + 4);
+
+ else
+ background.red = background.green = background.blue = 0;
+
+ background.gray = 0;
}
- png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+ else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */
+ {
+ if (png_ptr->bit_depth <= 8)
+ {
+ if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth))
+ {
+ png_chunk_benign_error(png_ptr, "invalid gray level");
+ return;
+ }
+ }
+
+ background.index = 0;
+ background.red =
+ background.green =
+ background.blue =
+ background.gray = png_get_uint_16(buf);
+ }
+
+ else
+ {
+ if (png_ptr->bit_depth <= 8)
+ {
+ if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0)
+ {
+ png_chunk_benign_error(png_ptr, "invalid color");
+ return;
+ }
+ }
+
+ background.index = 0;
+ background.red = png_get_uint_16(buf);
+ background.green = png_get_uint_16(buf + 2);
+ background.blue = png_get_uint_16(buf + 4);
+ background.gray = 0;
+ }
+
+ png_set_bKGD(png_ptr, info_ptr, &background);
}
#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
+#ifdef PNG_READ_eXIf_SUPPORTED
void /* PRIVATE */
-png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
+{
+ unsigned int i;
+
+ 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;
+ }
+
+ else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
+ return;
+ }
+
+ info_ptr->free_me |= PNG_FREE_EXIF;
+
+ info_ptr->eXIf_buf = png_voidcast(png_bytep,
+ png_malloc_warn(png_ptr, length));
+
+ if (info_ptr->eXIf_buf == NULL)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return;
+ }
+
+ 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)
+ {
+ 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;
+ }
+ }
+ }
+
+ 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;
+}
+#endif
+
+#ifdef PNG_READ_hIST_SUPPORTED
+void /* PRIVATE */
+png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
unsigned int num, i;
png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
- png_debug(1, "in png_handle_hIST\n");
+ png_debug(1, "in png_handle_hIST");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before hIST");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid hIST after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
{
- png_warning(png_ptr, "Missing PLTE before hIST");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
- {
- png_warning(png_ptr, "Duplicate hIST chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
num = length / 2 ;
- if (num != (unsigned int) png_ptr->num_palette || num >
- (unsigned int) PNG_MAX_PALETTE_LENGTH)
+
+ if (length != num * 2 ||
+ num != (unsigned int)png_ptr->num_palette ||
+ num > (unsigned int)PNG_MAX_PALETTE_LENGTH)
{
- png_warning(png_ptr, "Incorrect hIST chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
@@ -1473,47 +2142,50 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
readbuf[i] = png_get_uint_16(buf);
}
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
png_set_hIST(png_ptr, info_ptr, readbuf);
}
#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
+#ifdef PNG_READ_pHYs_SUPPORTED
void /* PRIVATE */
-png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[9];
png_uint_32 res_x, res_y;
int unit_type;
- png_debug(1, "in png_handle_pHYs\n");
+ png_debug(1, "in png_handle_pHYs");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before pHYs");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid pHYs after IDAT");
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))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_warning(png_ptr, "Duplicate pHYs chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
- png_warning(png_ptr, "Incorrect pHYs chunk length");
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))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
res_x = png_get_uint_32(buf);
@@ -1523,40 +2195,43 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
+#ifdef PNG_READ_oFFs_SUPPORTED
void /* PRIVATE */
-png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[9];
png_int_32 offset_x, offset_y;
int unit_type;
- png_debug(1, "in png_handle_oFFs\n");
+ png_debug(1, "in png_handle_oFFs");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before oFFs");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid oFFs after IDAT");
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))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_warning(png_ptr, "Duplicate oFFs chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
- png_warning(png_ptr, "Incorrect oFFs chunk length");
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))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
offset_x = png_get_int_32(buf);
@@ -1566,303 +2241,261 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif
-#if defined(PNG_READ_pCAL_SUPPORTED)
-/* read the pCAL chunk (described in the PNG Extensions document) */
+#ifdef PNG_READ_pCAL_SUPPORTED
+/* Read the pCAL chunk (described in the PNG Extensions document) */
void /* PRIVATE */
-png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_charp purpose;
png_int_32 X0, X1;
png_byte type, nparams;
- png_charp buf, units, endptr;
+ png_bytep buffer, buf, units, endptr;
png_charpp params;
- png_size_t slength;
int i;
- png_debug(1, "in png_handle_pCAL\n");
+ png_debug(1, "in png_handle_pCAL");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before pCAL");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid pCAL after IDAT");
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))
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0)
{
- png_warning(png_ptr, "Duplicate pCAL chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
- png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
- length + 1);
- purpose = (png_charp)png_malloc_warn(png_ptr, length + 1);
- if (purpose == NULL)
- {
- png_warning(png_ptr, "No memory for pCAL purpose.");
- return;
- }
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)purpose, slength);
+ png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
+ length + 1);
- if (png_crc_finish(png_ptr, 0))
+ buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+
+ if (buffer == NULL)
{
- png_free(png_ptr, purpose);
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- purpose[slength] = 0x00; /* null terminate the last string */
+ png_crc_read(png_ptr, buffer, length);
- png_debug(3, "Finding end of pCAL purpose string\n");
- for (buf = purpose; *buf; buf++)
- /* empty loop */ ;
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return;
- endptr = purpose + slength;
+ buffer[length] = 0; /* Null terminate the last string */
+
+ png_debug(3, "Finding end of pCAL purpose string");
+ for (buf = buffer; *buf; buf++)
+ /* Empty loop */ ;
+
+ endptr = buffer + length;
/* We need to have at least 12 bytes after the purpose string
- in order to get the parameter information. */
- if (endptr <= buf + 12)
+ * in order to get the parameter information.
+ */
+ if (endptr - buf <= 12)
{
- png_warning(png_ptr, "Invalid pCAL data");
- png_free(png_ptr, purpose);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+ png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
X0 = png_get_int_32((png_bytep)buf+1);
X1 = png_get_int_32((png_bytep)buf+5);
type = buf[9];
nparams = buf[10];
units = buf + 11;
- png_debug(3, "Checking pCAL equation type and number of parameters\n");
+ png_debug(3, "Checking pCAL equation type and number of parameters");
/* Check that we have the right number of parameters for known
- equation types. */
+ * equation types.
+ */
if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
(type == PNG_EQUATION_BASE_E && nparams != 3) ||
(type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
(type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
{
- png_warning(png_ptr, "Invalid pCAL parameters for equation type");
- png_free(png_ptr, purpose);
+ png_chunk_benign_error(png_ptr, "invalid parameter count");
return;
}
+
else if (type >= PNG_EQUATION_LAST)
{
- png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ png_chunk_benign_error(png_ptr, "unrecognized equation type");
}
for (buf = units; *buf; buf++)
/* Empty loop to move past the units string. */ ;
- png_debug(3, "Allocating pCAL parameters array\n");
- params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams
- *png_sizeof(png_charp))) ;
+ png_debug(3, "Allocating pCAL parameters array");
+
+ params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
+ nparams * (sizeof (png_charp))));
+
if (params == NULL)
- {
- png_free(png_ptr, purpose);
- png_warning(png_ptr, "No memory for pCAL params.");
- return;
- }
+ {
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return;
+ }
/* Get pointers to the start of each parameter string. */
- for (i = 0; i < (int)nparams; i++)
+ for (i = 0; i < nparams; i++)
{
buf++; /* Skip the null string terminator from previous parameter. */
- png_debug1(3, "Reading pCAL parameter %d\n", i);
- for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
+ png_debug1(3, "Reading pCAL parameter %d", i);
+
+ for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++)
/* Empty loop to move past each parameter string */ ;
/* Make sure we haven't run out of data yet */
if (buf > endptr)
{
- png_warning(png_ptr, "Invalid pCAL data");
- png_free(png_ptr, purpose);
png_free(png_ptr, params);
+ png_chunk_benign_error(png_ptr, "invalid data");
return;
}
}
- png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
- units, params);
+ png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,
+ (png_charp)units, params);
- png_free(png_ptr, purpose);
png_free(png_ptr, params);
}
#endif
-#if defined(PNG_READ_sCAL_SUPPORTED)
-/* read the sCAL chunk */
+#ifdef PNG_READ_sCAL_SUPPORTED
+/* Read the sCAL chunk */
void /* PRIVATE */
-png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_charp buffer, ep;
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- double width, height;
- png_charp vp;
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_charp swidth, sheight;
-#endif
-#endif
- png_size_t slength;
+ png_bytep buffer;
+ size_t i;
+ int state;
- png_debug(1, "in png_handle_sCAL\n");
+ png_debug(1, "in png_handle_sCAL");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sCAL");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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_warning(png_ptr, "Invalid sCAL after IDAT");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
- {
- png_warning(png_ptr, "Duplicate sCAL chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
- length + 1);
- buffer = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ 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*/);
+
if (buffer == NULL)
- {
- png_warning(png_ptr, "Out of memory while processing sCAL chunk");
- return;
- }
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)buffer, slength);
-
- if (png_crc_finish(png_ptr, 0))
{
- png_free(png_ptr, buffer);
+ png_chunk_benign_error(png_ptr, "out of memory");
+ png_crc_finish(png_ptr, length);
return;
}
- buffer[slength] = 0x00; /* null terminate the last string */
+ png_crc_read(png_ptr, buffer, length);
+ buffer[length] = 0; /* Null terminate the last string */
- ep = buffer + 1; /* skip unit byte */
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return;
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- width = png_strtod(png_ptr, ep, &vp);
- if (*vp)
+ /* Validate the unit. */
+ if (buffer[0] != 1 && buffer[0] != 2)
{
- png_warning(png_ptr, "malformed width string in sCAL chunk");
- return;
- }
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
- swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
- if (swidth == NULL)
- {
- png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
- return;
- }
- png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
-#endif
-#endif
-
- for (ep = buffer; *ep; ep++)
- /* empty loop */ ;
- ep++;
-
- if (buffer + slength < ep)
- {
- png_warning(png_ptr, "Truncated sCAL chunk");
-#if defined(PNG_FIXED_POINT_SUPPORTED) && \
- !defined(PNG_FLOATING_POINT_SUPPORTED)
- png_free(png_ptr, swidth);
-#endif
- png_free(png_ptr, buffer);
- return;
- }
-
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- height = png_strtod(png_ptr, ep, &vp);
- if (*vp)
- {
- png_warning(png_ptr, "malformed height string in sCAL chunk");
- return;
- }
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
- sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
- if (swidth == NULL)
- {
- png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
- return;
- }
- png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
-#endif
-#endif
-
- if (buffer + slength < ep
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- || width <= 0. || height <= 0.
-#endif
- )
- {
- png_warning(png_ptr, "Invalid sCAL data");
- png_free(png_ptr, buffer);
-#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
- png_free(png_ptr, swidth);
- png_free(png_ptr, sheight);
-#endif
+ png_chunk_benign_error(png_ptr, "invalid unit");
return;
}
+ /* Validate the ASCII numbers, need two ASCII numbers separated by
+ * a '\0' and they need to fit exactly in the chunk data.
+ */
+ i = 1;
+ state = 0;
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
-#endif
-#endif
+ if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 ||
+ i >= length || buffer[i++] != 0)
+ png_chunk_benign_error(png_ptr, "bad width format");
- png_free(png_ptr, buffer);
-#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
- png_free(png_ptr, swidth);
- png_free(png_ptr, sheight);
-#endif
+ else if (PNG_FP_IS_POSITIVE(state) == 0)
+ png_chunk_benign_error(png_ptr, "non-positive width");
+
+ else
+ {
+ size_t heighti = i;
+
+ state = 0;
+ if (png_check_fp_number((png_const_charp)buffer, length,
+ &state, &i) == 0 || i != length)
+ png_chunk_benign_error(png_ptr, "bad height format");
+
+ else if (PNG_FP_IS_POSITIVE(state) == 0)
+ 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);
+ }
}
#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
+#ifdef PNG_READ_tIME_SUPPORTED
void /* PRIVATE */
-png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[7];
png_time mod_time;
- png_debug(1, "in png_handle_tIME\n");
+ png_debug(1, "in png_handle_tIME");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Out of place tIME chunk");
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_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_warning(png_ptr, "Duplicate tIME chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
png_ptr->mode |= PNG_AFTER_IDAT;
if (length != 7)
{
- png_warning(png_ptr, "Incorrect tIME chunk length");
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))
+
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
mod_time.second = buf[6];
@@ -1876,646 +2509,1186 @@ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
+#ifdef PNG_READ_tEXt_SUPPORTED
/* Note: this does not properly handle chunks that are > 64K under DOS */
void /* PRIVATE */
-png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
+ png_text text_info;
+ png_bytep buffer;
png_charp key;
png_charp text;
png_uint_32 skip = 0;
- png_size_t slength;
- int ret;
- png_debug(1, "in png_handle_tEXt\n");
+ png_debug(1, "in png_handle_tEXt");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before tEXt");
-
- if (png_ptr->mode & PNG_HAVE_IDAT)
- png_ptr->mode |= PNG_AFTER_IDAT;
-
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_cache_max != 0)
{
- png_warning(png_ptr, "tEXt chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
+ if (png_ptr->user_chunk_cache_max == 1)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ 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;
+ }
}
#endif
- key = (png_charp)png_malloc_warn(png_ptr, length + 1);
- if (key == NULL)
- {
- png_warning(png_ptr, "No memory to process text chunk.");
- return;
- }
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)key, slength);
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (png_crc_finish(png_ptr, skip))
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > 65535U)
{
- png_free(png_ptr, key);
+ 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*/);
+
+ if (buffer == NULL)
+ {
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- key[slength] = 0x00;
+ png_crc_read(png_ptr, buffer, length);
+
+ if (png_crc_finish(png_ptr, skip) != 0)
+ return;
+
+ key = (png_charp)buffer;
+ key[length] = 0;
for (text = key; *text; text++)
- /* empty loop to find end of key */ ;
+ /* Empty loop to find end of key */ ;
- if (text != key + slength)
+ if (text != key + length)
text++;
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- if (text_ptr == NULL)
- {
- png_warning(png_ptr, "Not enough memory to process text chunk.");
- png_free(png_ptr, key);
- return;
- }
- text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr->key = key;
-#ifdef PNG_iTXt_SUPPORTED
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->itxt_length = 0;
-#endif
- text_ptr->text = text;
- text_ptr->text_length = png_strlen(text);
+ text_info.compression = PNG_TEXT_COMPRESSION_NONE;
+ text_info.key = key;
+ text_info.lang = NULL;
+ text_info.lang_key = NULL;
+ text_info.itxt_length = 0;
+ text_info.text = text;
+ text_info.text_length = strlen(text);
- ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, key);
- png_free(png_ptr, text_ptr);
- if (ret)
- png_warning(png_ptr, "Insufficient memory to process text chunk.");
+ if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0)
+ png_warning(png_ptr, "Insufficient memory to process text chunk");
}
#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
-/* note: this does not correctly handle chunks that are > 64K under DOS */
+#ifdef PNG_READ_zTXt_SUPPORTED
+/* Note: this does not correctly handle chunks that are > 64K under DOS */
void /* PRIVATE */
-png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
- png_charp chunkdata;
- png_charp text;
- int comp_type;
- int ret;
- png_size_t slength, prefix_len, data_len;
+ png_const_charp errmsg = NULL;
+ png_bytep buffer;
+ png_uint_32 keyword_length;
- png_debug(1, "in png_handle_zTXt\n");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before zTXt");
+ png_debug(1, "in png_handle_zTXt");
- if (png_ptr->mode & PNG_HAVE_IDAT)
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_cache_max != 0)
+ {
+ if (png_ptr->user_chunk_cache_max == 1)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ 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;
+ }
+ }
+#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
- /* We will no doubt have problems with chunks even half this size, but
- there is no hard and fast rule to tell us where to stop. */
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr,"zTXt chunk too large to fit in memory");
- png_crc_finish(png_ptr, length);
- return;
- }
-#endif
+ /* Note, "length" is sufficient here; we won't be adding
+ * a null terminator later.
+ */
+ buffer = png_read_buffer(png_ptr, length, 2/*silent*/);
- chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
- if (chunkdata == NULL)
+ if (buffer == NULL)
{
- png_warning(png_ptr,"Out of memory processing zTXt chunk.");
- return;
- }
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, chunkdata);
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- chunkdata[slength] = 0x00;
+ png_crc_read(png_ptr, buffer, length);
- for (text = chunkdata; *text; text++)
- /* empty loop */ ;
-
- /* zTXt must have some text after the chunkdataword */
- if (text >= chunkdata + slength - 2)
- {
- png_warning(png_ptr, "Truncated zTXt chunk");
- png_free(png_ptr, chunkdata);
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- }
+
+ /* TODO: also check that the keyword contents match the spec! */
+ for (keyword_length = 0;
+ keyword_length < length && buffer[keyword_length] != 0;
+ ++keyword_length)
+ /* Empty loop to find end of name */ ;
+
+ if (keyword_length > 79 || keyword_length < 1)
+ errmsg = "bad keyword";
+
+ /* zTXt must have some LZ data after the keyword, although it may expand to
+ * zero bytes; we need a '\0' at the end of the keyword, the compression type
+ * then the LZ data:
+ */
+ else if (keyword_length + 3 > length)
+ errmsg = "truncated";
+
+ else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)
+ errmsg = "unknown compression type";
+
else
{
- comp_type = *(++text);
- if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
- {
- png_warning(png_ptr, "Unknown compression type in zTXt chunk");
- comp_type = PNG_TEXT_COMPRESSION_zTXt;
- }
- text++; /* skip the compression_method byte */
+ png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;
+
+ /* TODO: at present png_decompress_chunk imposes a single application
+ * level memory limit, this should be split to different values for iCCP
+ * and text chunks.
+ */
+ if (png_decompress_chunk(png_ptr, length, keyword_length+2,
+ &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
+ {
+ png_text text;
+
+ if (png_ptr->read_buffer == NULL)
+ errmsg="Read failure in png_handle_zTXt";
+ else
+ {
+ /* It worked; png_ptr->read_buffer now looks like a tEXt chunk
+ * except for the extra compression type byte and the fact that
+ * it isn't necessarily '\0' terminated.
+ */
+ buffer = png_ptr->read_buffer;
+ buffer[uncompressed_length+(keyword_length+2)] = 0;
+
+ text.compression = PNG_TEXT_COMPRESSION_zTXt;
+ text.key = (png_charp)buffer;
+ text.text = (png_charp)(buffer + keyword_length+2);
+ text.text_length = uncompressed_length;
+ text.itxt_length = 0;
+ text.lang = NULL;
+ text.lang_key = NULL;
+
+ if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
+ errmsg = "insufficient memory";
+ }
+ }
+
+ else
+ errmsg = png_ptr->zstream.msg;
}
- prefix_len = text - chunkdata;
- chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
- (png_size_t)length, prefix_len, &data_len);
-
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- if (text_ptr == NULL)
- {
- png_warning(png_ptr,"Not enough memory to process zTXt chunk.");
- png_free(png_ptr, chunkdata);
- return;
- }
- text_ptr->compression = comp_type;
- text_ptr->key = chunkdata;
-#ifdef PNG_iTXt_SUPPORTED
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->itxt_length = 0;
-#endif
- text_ptr->text = chunkdata + prefix_len;
- text_ptr->text_length = data_len;
-
- ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, text_ptr);
- png_free(png_ptr, chunkdata);
- if (ret)
- png_error(png_ptr, "Insufficient memory to store zTXt chunk.");
+ if (errmsg != NULL)
+ png_chunk_benign_error(png_ptr, errmsg);
}
#endif
-#if defined(PNG_READ_iTXt_SUPPORTED)
-/* note: this does not correctly handle chunks that are > 64K under DOS */
+#ifdef PNG_READ_iTXt_SUPPORTED
+/* Note: this does not correctly handle chunks that are > 64K under DOS */
void /* PRIVATE */
-png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
- png_charp chunkdata;
- png_charp key, lang, text, lang_key;
- int comp_flag;
- int comp_type = 0;
- int ret;
- png_size_t slength, prefix_len, data_len;
+ png_const_charp errmsg = NULL;
+ png_bytep buffer;
+ png_uint_32 prefix_length;
- png_debug(1, "in png_handle_iTXt\n");
+ png_debug(1, "in png_handle_iTXt");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before iTXt");
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_cache_max != 0)
+ {
+ if (png_ptr->user_chunk_cache_max == 1)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ 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;
+ }
+ }
+#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
- /* We will no doubt have problems with chunks even half this size, but
- there is no hard and fast rule to tell us where to stop. */
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr,"iTXt chunk too large to fit in memory");
- png_crc_finish(png_ptr, length);
- return;
- }
-#endif
+ buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
- chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
- if (chunkdata == NULL)
+ if (buffer == NULL)
{
- png_warning(png_ptr, "No memory to process iTXt chunk.");
- return;
- }
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, chunkdata);
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- chunkdata[slength] = 0x00;
+ png_crc_read(png_ptr, buffer, length);
- for (lang = chunkdata; *lang; lang++)
- /* empty loop */ ;
- lang++; /* skip NUL separator */
-
- /* iTXt must have a language tag (possibly empty), two compression bytes,
- translated keyword (possibly empty), and possibly some text after the
- keyword */
-
- if (lang >= chunkdata + slength - 3)
- {
- png_warning(png_ptr, "Truncated iTXt chunk");
- png_free(png_ptr, chunkdata);
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
+
+ /* First the keyword. */
+ for (prefix_length=0;
+ prefix_length < length && buffer[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
+
+ /* Perform a basic check on the keyword length here. */
+ if (prefix_length > 79 || prefix_length < 1)
+ errmsg = "bad keyword";
+
+ /* Expect keyword, compression flag, compression type, language, translated
+ * keyword (both may be empty but are 0 terminated) then the text, which may
+ * be empty.
+ */
+ else if (prefix_length + 5 > length)
+ errmsg = "truncated";
+
+ else if (buffer[prefix_length+1] == 0 ||
+ (buffer[prefix_length+1] == 1 &&
+ buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE))
+ {
+ int compressed = buffer[prefix_length+1] != 0;
+ png_uint_32 language_offset, translated_keyword_offset;
+ png_alloc_size_t uncompressed_length = 0;
+
+ /* Now the language tag */
+ prefix_length += 3;
+ language_offset = prefix_length;
+
+ for (; prefix_length < length && buffer[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
+
+ /* WARNING: the length may be invalid here, this is checked below. */
+ translated_keyword_offset = ++prefix_length;
+
+ for (; prefix_length < length && buffer[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
+
+ /* prefix_length should now be at the trailing '\0' of the translated
+ * keyword, but it may already be over the end. None of this arithmetic
+ * can overflow because chunks are at most 2^31 bytes long, but on 16-bit
+ * systems the available allocation may overflow.
+ */
+ ++prefix_length;
+
+ if (compressed == 0 && prefix_length <= length)
+ uncompressed_length = length - prefix_length;
+
+ else if (compressed != 0 && prefix_length < length)
+ {
+ uncompressed_length = PNG_SIZE_MAX;
+
+ /* TODO: at present png_decompress_chunk imposes a single application
+ * level memory limit, this should be split to different values for
+ * iCCP and text chunks.
+ */
+ if (png_decompress_chunk(png_ptr, length, prefix_length,
+ &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
+ buffer = png_ptr->read_buffer;
+
+ else
+ errmsg = png_ptr->zstream.msg;
+ }
+
+ else
+ errmsg = "truncated";
+
+ if (errmsg == NULL)
+ {
+ png_text text;
+
+ buffer[uncompressed_length+prefix_length] = 0;
+
+ if (compressed == 0)
+ text.compression = PNG_ITXT_COMPRESSION_NONE;
+
+ else
+ text.compression = PNG_ITXT_COMPRESSION_zTXt;
+
+ text.key = (png_charp)buffer;
+ text.lang = (png_charp)buffer + language_offset;
+ text.lang_key = (png_charp)buffer + translated_keyword_offset;
+ text.text = (png_charp)buffer + prefix_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";
+ }
}
+
else
- {
- comp_flag = *lang++;
- comp_type = *lang++;
- }
+ errmsg = "bad compression info";
- for (lang_key = lang; *lang_key; lang_key++)
- /* empty loop */ ;
- lang_key++; /* skip NUL separator */
-
- if (lang_key >= chunkdata + slength)
- {
- png_warning(png_ptr, "Truncated iTXt chunk");
- png_free(png_ptr, chunkdata);
- return;
- }
-
- for (text = lang_key; *text; text++)
- /* empty loop */ ;
- text++; /* skip NUL separator */
- if (text >= chunkdata + slength)
- {
- png_warning(png_ptr, "Malformed iTXt chunk");
- png_free(png_ptr, chunkdata);
- return;
- }
-
- prefix_len = text - chunkdata;
-
- key=chunkdata;
- if (comp_flag)
- chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
- (size_t)length, prefix_len, &data_len);
- else
- data_len=png_strlen(chunkdata + prefix_len);
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- (png_uint_32)png_sizeof(png_text));
- if (text_ptr == NULL)
- {
- png_warning(png_ptr,"Not enough memory to process iTXt chunk.");
- png_free(png_ptr, chunkdata);
- return;
- }
- text_ptr->compression = (int)comp_flag + 1;
- text_ptr->lang_key = chunkdata+(lang_key-key);
- text_ptr->lang = chunkdata+(lang-key);
- text_ptr->itxt_length = data_len;
- text_ptr->text_length = 0;
- text_ptr->key = chunkdata;
- text_ptr->text = chunkdata + prefix_len;
-
- ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, text_ptr);
- png_free(png_ptr, chunkdata);
- if (ret)
- png_error(png_ptr, "Insufficient memory to store iTXt chunk.");
+ if (errmsg != NULL)
+ png_chunk_benign_error(png_ptr, errmsg);
}
#endif
-/* This function is called when we haven't found a handler for a
- chunk. If there isn't a problem with the chunk itself (ie bad
- chunk name, CRC, or a critical chunk), the chunk is silently ignored
- -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
- case it will be saved away to be written out later. */
-void /* PRIVATE */
-png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+static int
+png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
{
- png_uint_32 skip = 0;
+ png_alloc_size_t limit = PNG_SIZE_MAX;
- png_debug(1, "in png_handle_unknown\n");
-
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if (png_ptr->unknown_chunk.data != NULL)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IDAT;
-#endif
- if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
- png_ptr->mode |= PNG_AFTER_IDAT;
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
}
- png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
- if (!(png_ptr->chunk_name[0] & 0x20))
+# elif PNG_USER_CHUNK_MALLOC_MAX > 0
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
+# endif
+
+ if (length <= limit)
{
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
- if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS
-#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
- && png_ptr->read_user_chunk_fn == NULL
-#endif
- )
-#endif
- png_chunk_error(png_ptr, "unknown critical chunk");
+ PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
+ /* The following is safe because of the PNG_SIZE_MAX init above */
+ png_ptr->unknown_chunk.size = (size_t)length/*SAFE*/;
+ /* 'mode' is a flag array, only the bottom four bits matter here */
+ png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/;
+
+ if (length == 0)
+ png_ptr->unknown_chunk.data = NULL;
+
+ else
+ {
+ /* Do a 'warn' here - it is handled below. */
+ png_ptr->unknown_chunk.data = png_voidcast(png_bytep,
+ png_malloc_warn(png_ptr, length));
+ }
}
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
- if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) ||
- (png_ptr->read_user_chunk_fn != NULL))
+ if (png_ptr->unknown_chunk.data == NULL && length > 0)
{
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr, "unknown chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
- png_memcpy((png_charp)png_ptr->unknown_chunk.name,
- (png_charp)png_ptr->chunk_name,
- png_sizeof(png_ptr->unknown_chunk.name));
- png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] = '\0';
- png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
- png_ptr->unknown_chunk.size = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
-#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
- if(png_ptr->read_user_chunk_fn != NULL)
- {
- /* callback to user unknown chunk handler */
- int ret;
- ret = (*(png_ptr->read_user_chunk_fn))
- (png_ptr, &png_ptr->unknown_chunk);
- if (ret < 0)
- png_chunk_error(png_ptr, "error in user chunk");
- if (ret == 0)
- {
- if (!(png_ptr->chunk_name[0] & 0x20))
- if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS)
- png_chunk_error(png_ptr, "unknown critical chunk");
- png_set_unknown_chunks(png_ptr, info_ptr,
- &png_ptr->unknown_chunk, 1);
- }
- }
-#else
- png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
-#endif
- png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
+ /* This is benign because we clean up correctly */
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits");
+ return 0;
}
+
else
-#endif
- skip = length;
+ {
+ if (length > 0)
+ png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);
+ png_crc_finish(png_ptr, 0);
+ return 1;
+ }
+}
+#endif /* READ_UNKNOWN_CHUNKS */
- png_crc_finish(png_ptr, skip);
+/* Handle an unknown, or known but disabled, chunk */
+void /* 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 */
-#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
- info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
-#endif
+ png_debug(1, "in png_handle_unknown");
+
+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing
+ * the bug which meant that setting a non-default behavior for a specific
+ * chunk would be ignored (the default was always used unless a user
+ * callback was installed).
+ *
+ * 'keep' is the value from the png_chunk_unknown_handling, the setting for
+ * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it
+ * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here.
+ * This is just an optimization to avoid multiple calls to the lookup
+ * function.
+ */
+# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name);
+# endif
+# endif
+
+ /* One of the following methods will read the chunk or skip it (at least one
+ * of these is always defined because this is the only way to switch on
+ * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ */
+# ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ /* The user callback takes precedence over the chunk keep value, but the
+ * keep value is still required to validate a save of a critical chunk.
+ */
+ if (png_ptr->read_user_chunk_fn != NULL)
+ {
+ if (png_cache_unknown_chunk(png_ptr, length) != 0)
+ {
+ /* Callback to user unknown chunk handler */
+ int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr,
+ &png_ptr->unknown_chunk);
+
+ /* ret is:
+ * negative: An error occurred; png_chunk_error will be called.
+ * zero: The chunk was not handled, the chunk will be discarded
+ * unless png_set_keep_unknown_chunks has been used to set
+ * a 'keep' behavior for this particular chunk, in which
+ * case that will be used. A critical chunk will cause an
+ * error at this point unless it is to be saved.
+ * positive: The chunk was handled, libpng will ignore/discard it.
+ */
+ if (ret < 0)
+ png_chunk_error(png_ptr, "error in user chunk");
+
+ else if (ret == 0)
+ {
+ /* If the keep value is 'default' or 'never' override it, but
+ * still error out on critical chunks unless the keep value is
+ * 'always' While this is weird it is the behavior in 1.4.12.
+ * A possible improvement would be to obey the value set for the
+ * chunk, but this would be an API change that would probably
+ * damage some applications.
+ *
+ * The png_app_warning below catches the case that matters, where
+ * the application has not set specific save or ignore for this
+ * chunk or global save or ignore.
+ */
+ if (keep < PNG_HANDLE_CHUNK_IF_SAFE)
+ {
+# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE)
+ {
+ png_chunk_warning(png_ptr, "Saving unknown chunk:");
+ png_app_warning(png_ptr,
+ "forcing save of an unhandled chunk;"
+ " please call png_set_keep_unknown_chunks");
+ /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */
+ }
+# endif
+ keep = PNG_HANDLE_CHUNK_IF_SAFE;
+ }
+ }
+
+ else /* chunk was handled */
+ {
+ handled = 1;
+ /* Critical chunks can be safely discarded at this point. */
+ keep = PNG_HANDLE_CHUNK_NEVER;
+ }
+ }
+
+ else
+ keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */
+ }
+
+ else
+ /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */
+# endif /* READ_USER_CHUNKS */
+
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+ {
+ /* keep is currently just the per-chunk setting, if there was no
+ * setting change it to the global default now (not that this may
+ * still be AS_DEFAULT) then obtain the cache of the chunk if required,
+ * if not simply skip the chunk.
+ */
+ if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT)
+ keep = png_ptr->unknown_default;
+
+ if (keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (keep == PNG_HANDLE_CHUNK_IF_SAFE &&
+ PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))
+ {
+ if (png_cache_unknown_chunk(png_ptr, length) == 0)
+ keep = PNG_HANDLE_CHUNK_NEVER;
+ }
+
+ else
+ png_crc_finish(png_ptr, length);
+ }
+# else
+# ifndef PNG_READ_USER_CHUNKS_SUPPORTED
+# error no method to support READ_UNKNOWN_CHUNKS
+# endif
+
+ {
+ /* If here there is no read callback pointer set and no support is
+ * compiled in to just save the unknown chunks, so simply skip this
+ * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then
+ * the app has erroneously asked for unknown chunk saving when there
+ * is no support.
+ */
+ if (keep > PNG_HANDLE_CHUNK_NEVER)
+ png_app_error(png_ptr, "no unknown chunk support available");
+
+ png_crc_finish(png_ptr, length);
+ }
+# endif
+
+# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ /* Now store the chunk in the chunk list if appropriate, and if the limits
+ * permit it.
+ */
+ if (keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (keep == PNG_HANDLE_CHUNK_IF_SAFE &&
+ PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))
+ {
+# ifdef PNG_USER_LIMITS_SUPPORTED
+ switch (png_ptr->user_chunk_cache_max)
+ {
+ case 2:
+ png_ptr->user_chunk_cache_max = 1;
+ png_chunk_benign_error(png_ptr, "no space in chunk cache");
+ /* FALLTHROUGH */
+ case 1:
+ /* NOTE: prior to 1.6.0 this case resulted in an unknown critical
+ * chunk being skipped, now there will be a hard error below.
+ */
+ break;
+
+ default: /* not at limit */
+ --(png_ptr->user_chunk_cache_max);
+ /* FALLTHROUGH */
+ case 0: /* no limit */
+# endif /* USER_LIMITS */
+ /* Here when the limit isn't reached or when limits are compiled
+ * out; store the chunk.
+ */
+ png_set_unknown_chunks(png_ptr, info_ptr,
+ &png_ptr->unknown_chunk, 1);
+ handled = 1;
+# ifdef PNG_USER_LIMITS_SUPPORTED
+ break;
+ }
+# endif
+ }
+# else /* no store support: the chunk must be handled by the user callback */
+ PNG_UNUSED(info_ptr)
+# endif
+
+ /* Regardless of the error handling below the cached data (if any) can be
+ * freed now. Notice that the data is not freed if there is a png_error, but
+ * it will be freed by destroy_read_struct.
+ */
+ if (png_ptr->unknown_chunk.data != NULL)
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+
+#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */
+ /* There is no support to read an unknown chunk, so just skip it. */
+ png_crc_finish(png_ptr, length);
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(keep)
+#endif /* !READ_UNKNOWN_CHUNKS */
+
+ /* Check for unhandled critical chunks */
+ if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
+ png_chunk_error(png_ptr, "unhandled critical chunk");
}
/* 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. */
+ * 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.
+ */
-#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:
+ *
+ * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+ */
void /* PRIVATE */
-png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
+png_check_chunk_name(png_const_structrp png_ptr, png_uint_32 chunk_name)
{
- png_debug(1, "in png_check_chunk_name\n");
- if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
- isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+ int i;
+ png_uint_32 cn=chunk_name;
+
+ png_debug(1, "in png_check_chunk_name");
+
+ for (i=1; i<=4; ++i)
{
- png_chunk_error(png_ptr, "invalid chunk type");
+ int c = cn & 0xff;
+
+ if (c < 65 || c > 122 || (c > 90 && c < 97))
+ png_chunk_error(png_ptr, "invalid chunk type");
+
+ cn >>= 8;
}
}
-/* Combines the row recently read in with the existing pixels in the
- row. This routine takes care of alpha and transparency if requested.
- This routine also handles the two methods of progressive display
- of interlaced images, depending on the mask value.
- The mask value describes which pixels are to be combined with
- the row. The pattern always repeats every 8 pixels, so just 8
- bits are needed. A one indicates the pixel is to be combined,
- a zero indicates the pixel is to be skipped. This is in addition
- to any alpha or transparency value associated with the pixel. If
- you want all pixels to be combined, pass 0xff (255) in mask. */
-
void /* PRIVATE */
-png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+png_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length)
{
- png_debug(1,"in png_combine_row\n");
- if (mask == 0xff)
+ 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)
{
- png_memcpy(row, png_ptr->row_buf + 1,
- PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
+ 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;
}
- else
+
+ if (length > limit)
{
- switch (png_ptr->row_info.pixel_depth)
+ png_debug2(0," length = %lu, limit = %lu",
+ (unsigned long)length,(unsigned long)limit);
+ png_benign_error(png_ptr, "chunk data is too large");
+ }
+}
+
+/* Combines the row recently read in with the existing pixels in the row. This
+ * routine takes care of alpha and transparency if requested. This routine also
+ * handles the two methods of progressive display of interlaced images,
+ * depending on the 'display' value; if 'display' is true then the whole row
+ * (dp) is filled from the start by replicating the available pixels. If
+ * 'display' is false only those pixels present in the pass are filled in.
+ */
+void /* PRIVATE */
+png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display)
+{
+ unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
+ png_const_bytep sp = png_ptr->row_buf + 1;
+ png_alloc_size_t row_width = png_ptr->width;
+ unsigned int pass = png_ptr->pass;
+ png_bytep end_ptr = 0;
+ png_byte end_byte = 0;
+ unsigned int end_mask;
+
+ png_debug(1, "in png_combine_row");
+
+ /* Added in 1.5.6: it should not be possible to enter this routine until at
+ * least one row has been read from the PNG data and transformed.
+ */
+ if (pixel_depth == 0)
+ png_error(png_ptr, "internal row logic error");
+
+ /* Added in 1.5.4: the pixel depth should match the information returned by
+ * any call to png_read_update_info at this point. Do not continue if we got
+ * this wrong.
+ */
+ if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=
+ PNG_ROWBYTES(pixel_depth, row_width))
+ png_error(png_ptr, "internal row size calculation error");
+
+ /* Don't expect this to ever happen: */
+ if (row_width == 0)
+ png_error(png_ptr, "internal row width error");
+
+ /* Preserve the last byte in cases where only part of it will be overwritten,
+ * the multiply below may overflow, we don't care because ANSI-C guarantees
+ * we get the low bits.
+ */
+ end_mask = (pixel_depth * row_width) & 7;
+ if (end_mask != 0)
+ {
+ /* end_ptr == NULL is a flag to say do nothing */
+ end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;
+ end_byte = *end_ptr;
+# ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ /* little-endian byte */
+ end_mask = (unsigned int)(0xff << end_mask);
+
+ else /* big-endian byte */
+# endif
+ end_mask = 0xff >> end_mask;
+ /* end_mask is now the bits to *keep* from the destination row */
+ }
+
+ /* For non-interlaced images this reduces to a memcpy(). A memcpy()
+ * will also happen if interlacing isn't supported or if the application
+ * does not call png_set_interlace_handling(). In the latter cases the
+ * caller just gets a sequence of the unexpanded rows from each interlace
+ * pass.
+ */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0 &&
+ pass < 6 && (display == 0 ||
+ /* The following copies everything for 'display' on passes 0, 2 and 4. */
+ (display == 1 && (pass & 1) != 0)))
+ {
+ /* Narrow images may have no bits in a pass; the caller should handle
+ * this, but this test is cheap:
+ */
+ if (row_width <= PNG_PASS_START_COL(pass))
+ return;
+
+ if (pixel_depth < 8)
{
- case 1:
+ /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit
+ * into 32 bits, then a single loop over the bytes using the four byte
+ * values in the 32-bit mask can be used. For the 'display' option the
+ * expanded mask may also not require any masking within a byte. To
+ * make this work the PACKSWAP option must be taken into account - it
+ * simply requires the pixels to be reversed in each byte.
+ *
+ * The 'regular' case requires a mask for each of the first 6 passes,
+ * the 'display' case does a copy for the even passes in the range
+ * 0..6. This has already been handled in the test above.
+ *
+ * The masks are arranged as four bytes with the first byte to use in
+ * the lowest bits (little-endian) regardless of the order (PACKSWAP or
+ * not) of the pixels in each byte.
+ *
+ * NOTE: the whole of this logic depends on the caller of this function
+ * only calling it on rows appropriate to the pass. This function only
+ * understands the 'x' logic; the 'y' logic is handled by the caller.
+ *
+ * The following defines allow generation of compile time constant bit
+ * masks for each pixel depth and each possibility of swapped or not
+ * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index,
+ * is in the range 0..7; and the result is 1 if the pixel is to be
+ * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B'
+ * for the block method.
+ *
+ * With some compilers a compile time expression of the general form:
+ *
+ * (shift >= 32) ? (a >> (shift-32)) : (b >> shift)
+ *
+ * Produces warnings with values of 'shift' in the range 33 to 63
+ * because the right hand side of the ?: expression is evaluated by
+ * the compiler even though it isn't used. Microsoft Visual C (various
+ * versions) and the Intel C compiler are known to do this. To avoid
+ * this the following macros are used in 1.5.6. This is a temporary
+ * solution to avoid destabilizing the code during the release process.
+ */
+# if PNG_USE_COMPILE_TIME_MASKS
+# define PNG_LSR(x,s) ((x)>>((s) & 0x1f))
+# define PNG_LSL(x,s) ((x)<<((s) & 0x1f))
+# else
+# define PNG_LSR(x,s) ((x)>>(s))
+# define PNG_LSL(x,s) ((x)<<(s))
+# endif
+# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\
+ PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1)
+# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\
+ PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1)
+
+ /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is
+ * little endian - the first pixel is at bit 0 - however the extra
+ * parameter 's' can be set to cause the mask position to be swapped
+ * within each byte, to match the PNG format. This is done by XOR of
+ * the shift with 7, 6 or 4 for bit depths 1, 2 and 4.
+ */
+# define PIXEL_MASK(p,x,d,s) \
+ (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0))))
+
+ /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask.
+ */
+# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
+# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
+
+ /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp
+ * cases the result needs replicating, for the 4-bpp case the above
+ * generates a full 32 bits.
+ */
+# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1)))
+
+# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\
+ S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\
+ S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d)
+
+# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\
+ B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\
+ B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d)
+
+#if PNG_USE_COMPILE_TIME_MASKS
+ /* Utility macros to construct all the masks for a depth/swap
+ * combination. The 's' parameter says whether the format is PNG
+ * (big endian bytes) or not. Only the three odd-numbered passes are
+ * required for the display/block algorithm.
+ */
+# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\
+ S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }
+
+# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) }
+
+# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
+
+ /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and
+ * then pass:
+ */
+ static const png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] =
{
- png_bytep sp = png_ptr->row_buf + 1;
- png_bytep dp = row;
- int s_inc, s_start, s_end;
- int m = 0x80;
- int shift;
- png_uint_32 i;
- png_uint_32 row_width = png_ptr->width;
+ /* Little-endian byte masks for PACKSWAP */
+ { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) },
+ /* Normal (big-endian byte) masks - PNG format */
+ { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) }
+ };
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- {
- s_start = 0;
- s_end = 7;
- s_inc = 1;
- }
- else
-#endif
- {
- s_start = 7;
- s_end = 0;
- s_inc = -1;
- }
-
- shift = s_start;
-
- for (i = 0; i < row_width; i++)
- {
- if (m & mask)
- {
- int value;
-
- value = (*sp >> shift) & 0x01;
- *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
- *dp |= (png_byte)(value << shift);
- }
-
- if (shift == s_end)
- {
- shift = s_start;
- sp++;
- dp++;
- }
- else
- shift += s_inc;
-
- if (m == 1)
- m = 0x80;
- else
- m >>= 1;
- }
- break;
- }
- case 2:
+ /* display_mask has only three entries for the odd passes, so index by
+ * pass>>1.
+ */
+ static const png_uint_32 display_mask[2][3][3] =
{
- png_bytep sp = png_ptr->row_buf + 1;
- png_bytep dp = row;
- int s_start, s_end, s_inc;
- int m = 0x80;
- int shift;
- png_uint_32 i;
- png_uint_32 row_width = png_ptr->width;
- int value;
+ /* Little-endian byte masks for PACKSWAP */
+ { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) },
+ /* Normal (big-endian byte) masks - PNG format */
+ { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) }
+ };
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- {
- s_start = 0;
- s_end = 6;
- s_inc = 2;
- }
- else
-#endif
- {
- s_start = 6;
- s_end = 0;
- s_inc = -2;
- }
+# define MASK(pass,depth,display,png)\
+ ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\
+ row_mask[png][DEPTH_INDEX(depth)][pass])
- shift = s_start;
+#else /* !PNG_USE_COMPILE_TIME_MASKS */
+ /* This is the runtime alternative: it seems unlikely that this will
+ * ever be either smaller or faster than the compile time approach.
+ */
+# define MASK(pass,depth,display,png)\
+ ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))
+#endif /* !USE_COMPILE_TIME_MASKS */
- for (i = 0; i < row_width; i++)
- {
- if (m & mask)
- {
- value = (*sp >> shift) & 0x03;
- *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
- *dp |= (png_byte)(value << shift);
- }
+ /* Use the appropriate mask to copy the required bits. In some cases
+ * the byte mask will be 0 or 0xff; optimize these cases. row_width is
+ * the number of pixels, but the code copies bytes, so it is necessary
+ * to special case the end.
+ */
+ png_uint_32 pixels_per_byte = 8 / pixel_depth;
+ png_uint_32 mask;
- if (shift == s_end)
- {
- shift = s_start;
- sp++;
- dp++;
- }
- else
- shift += s_inc;
- if (m == 1)
- m = 0x80;
- else
- m >>= 1;
- }
- break;
- }
- case 4:
+# ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ mask = MASK(pass, pixel_depth, display, 0);
+
+ else
+# endif
+ mask = MASK(pass, pixel_depth, display, 1);
+
+ for (;;)
{
- png_bytep sp = png_ptr->row_buf + 1;
- png_bytep dp = row;
- int s_start, s_end, s_inc;
- int m = 0x80;
- int shift;
- png_uint_32 i;
- png_uint_32 row_width = png_ptr->width;
- int value;
+ png_uint_32 m;
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- {
- s_start = 0;
- s_end = 4;
- s_inc = 4;
- }
- else
-#endif
- {
- s_start = 4;
- s_end = 0;
- s_inc = -4;
- }
- shift = s_start;
+ /* It doesn't matter in the following if png_uint_32 has more than
+ * 32 bits because the high bits always match those in m<<24; it is,
+ * however, essential to use OR here, not +, because of this.
+ */
+ m = mask;
+ mask = (m >> 8) | (m << 24); /* rotate right to good compilers */
+ m &= 0xff;
- for (i = 0; i < row_width; i++)
+ if (m != 0) /* something to copy */
{
- if (m & mask)
- {
- value = (*sp >> shift) & 0xf;
- *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
- *dp |= (png_byte)(value << shift);
- }
-
- if (shift == s_end)
- {
- shift = s_start;
- sp++;
- dp++;
- }
+ if (m != 0xff)
+ *dp = (png_byte)((*dp & ~m) | (*sp & m));
else
- shift += s_inc;
- if (m == 1)
- m = 0x80;
- else
- m >>= 1;
+ *dp = *sp;
}
- break;
- }
- default:
- {
- png_bytep sp = png_ptr->row_buf + 1;
- png_bytep dp = row;
- png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
- png_uint_32 i;
- png_uint_32 row_width = png_ptr->width;
- png_byte m = 0x80;
+ /* NOTE: this may overwrite the last byte with garbage if the image
+ * is not an exact number of bytes wide; libpng has always done
+ * this.
+ */
+ if (row_width <= pixels_per_byte)
+ break; /* May need to restore part of the last byte */
- for (i = 0; i < row_width; i++)
- {
- if (m & mask)
- {
- png_memcpy(dp, sp, pixel_bytes);
- }
-
- sp += pixel_bytes;
- dp += pixel_bytes;
-
- if (m == 1)
- m = 0x80;
- else
- m >>= 1;
- }
- break;
+ row_width -= pixels_per_byte;
+ ++dp;
+ ++sp;
}
}
+
+ else /* pixel_depth >= 8 */
+ {
+ unsigned int bytes_to_copy, bytes_to_jump;
+
+ /* Validate the depth - it must be a multiple of 8 */
+ if (pixel_depth & 7)
+ png_error(png_ptr, "invalid user transform pixel depth");
+
+ pixel_depth >>= 3; /* now in bytes */
+ row_width *= pixel_depth;
+
+ /* Regardless of pass number the Adam 7 interlace always results in a
+ * fixed number of pixels to copy then to skip. There may be a
+ * different number of pixels to skip at the start though.
+ */
+ {
+ unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth;
+
+ row_width -= offset;
+ dp += offset;
+ sp += offset;
+ }
+
+ /* Work out the bytes to copy. */
+ if (display != 0)
+ {
+ /* When doing the 'block' algorithm the pixel in the pass gets
+ * replicated to adjacent pixels. This is why the even (0,2,4,6)
+ * passes are skipped above - the entire expanded row is copied.
+ */
+ bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;
+
+ /* But don't allow this number to exceed the actual row width. */
+ if (bytes_to_copy > row_width)
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
+ }
+
+ else /* normal row; Adam7 only ever gives us one pixel to copy. */
+ bytes_to_copy = pixel_depth;
+
+ /* In Adam7 there is a constant offset between where the pixels go. */
+ bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;
+
+ /* And simply copy these bytes. Some optimization is possible here,
+ * depending on the value of 'bytes_to_copy'. Special case the low
+ * byte counts, which we know to be frequent.
+ *
+ * Notice that these cases all 'return' rather than 'break' - this
+ * avoids an unnecessary test on whether to restore the last byte
+ * below.
+ */
+ switch (bytes_to_copy)
+ {
+ case 1:
+ for (;;)
+ {
+ *dp = *sp;
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ dp += bytes_to_jump;
+ sp += bytes_to_jump;
+ row_width -= bytes_to_jump;
+ }
+
+ case 2:
+ /* There is a possibility of a partial copy at the end here; this
+ * slows the code down somewhat.
+ */
+ do
+ {
+ dp[0] = sp[0]; dp[1] = sp[1];
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ sp += bytes_to_jump;
+ dp += bytes_to_jump;
+ row_width -= bytes_to_jump;
+ }
+ while (row_width > 1);
+
+ /* And there can only be one byte left at this point: */
+ *dp = *sp;
+ return;
+
+ case 3:
+ /* This can only be the RGB case, so each copy is exactly one
+ * pixel and it is not necessary to check for a partial copy.
+ */
+ for (;;)
+ {
+ dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2];
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ sp += bytes_to_jump;
+ dp += bytes_to_jump;
+ row_width -= bytes_to_jump;
+ }
+
+ default:
+#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE
+ /* Check for double byte alignment and, if possible, use a
+ * 16-bit copy. Don't attempt this for narrow images - ones that
+ * are less than an interlace panel wide. Don't attempt it for
+ * wide bytes_to_copy either - use the memcpy there.
+ */
+ if (bytes_to_copy < 16 /*else use memcpy*/ &&
+ png_isaligned(dp, png_uint_16) &&
+ png_isaligned(sp, png_uint_16) &&
+ bytes_to_copy % (sizeof (png_uint_16)) == 0 &&
+ bytes_to_jump % (sizeof (png_uint_16)) == 0)
+ {
+ /* Everything is aligned for png_uint_16 copies, but try for
+ * png_uint_32 first.
+ */
+ if (png_isaligned(dp, png_uint_32) &&
+ png_isaligned(sp, png_uint_32) &&
+ bytes_to_copy % (sizeof (png_uint_32)) == 0 &&
+ bytes_to_jump % (sizeof (png_uint_32)) == 0)
+ {
+ png_uint_32p dp32 = png_aligncast(png_uint_32p,dp);
+ png_const_uint_32p sp32 = png_aligncastconst(
+ png_const_uint_32p, sp);
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
+ (sizeof (png_uint_32));
+
+ do
+ {
+ size_t c = bytes_to_copy;
+ do
+ {
+ *dp32++ = *sp32++;
+ c -= (sizeof (png_uint_32));
+ }
+ while (c > 0);
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ dp32 += skip;
+ sp32 += skip;
+ row_width -= bytes_to_jump;
+ }
+ while (bytes_to_copy <= row_width);
+
+ /* Get to here when the row_width truncates the final copy.
+ * There will be 1-3 bytes left to copy, so don't try the
+ * 16-bit loop below.
+ */
+ dp = (png_bytep)dp32;
+ sp = (png_const_bytep)sp32;
+ do
+ *dp++ = *sp++;
+ while (--row_width > 0);
+ return;
+ }
+
+ /* Else do it in 16-bit quantities, but only if the size is
+ * not too large.
+ */
+ else
+ {
+ png_uint_16p dp16 = png_aligncast(png_uint_16p, dp);
+ png_const_uint_16p sp16 = png_aligncastconst(
+ png_const_uint_16p, sp);
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
+ (sizeof (png_uint_16));
+
+ do
+ {
+ size_t c = bytes_to_copy;
+ do
+ {
+ *dp16++ = *sp16++;
+ c -= (sizeof (png_uint_16));
+ }
+ while (c > 0);
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ dp16 += skip;
+ sp16 += skip;
+ row_width -= bytes_to_jump;
+ }
+ while (bytes_to_copy <= row_width);
+
+ /* End of row - 1 byte left, bytes_to_copy > row_width: */
+ dp = (png_bytep)dp16;
+ sp = (png_const_bytep)sp16;
+ do
+ *dp++ = *sp++;
+ while (--row_width > 0);
+ return;
+ }
+ }
+#endif /* ALIGN_TYPE code */
+
+ /* The true default - use a memcpy: */
+ for (;;)
+ {
+ memcpy(dp, sp, bytes_to_copy);
+
+ if (row_width <= bytes_to_jump)
+ return;
+
+ sp += bytes_to_jump;
+ dp += bytes_to_jump;
+ row_width -= bytes_to_jump;
+ if (bytes_to_copy > row_width)
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
+ }
+ }
+
+ /* NOT REACHED*/
+ } /* pixel_depth >= 8 */
+
+ /* Here if pixel_depth < 8 to check 'end_ptr' below. */
}
+ else
+#endif /* READ_INTERLACING */
+
+ /* If here then the switch above wasn't used so just memcpy the whole row
+ * from the temporary row buffer (notice that this overwrites the end of the
+ * destination row if it is a partial byte.)
+ */
+ memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
+
+ /* Restore the overwritten bits from the last byte if necessary. */
+ if (end_ptr != NULL)
+ *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask));
}
#ifdef PNG_READ_INTERLACING_SUPPORTED
-/* OLD pre-1.0.9 interface:
-void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
- png_uint_32 transformations)
- */
void /* PRIVATE */
-png_do_read_interlace(png_structp png_ptr)
+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 */)
{
- png_row_infop row_info = &(png_ptr->row_info);
- png_bytep row = png_ptr->row_buf + 1;
- int pass = png_ptr->pass;
- png_uint_32 transformations = png_ptr->transformations;
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* offset to next interlace block */
- PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-#endif
+ /* 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\n");
+ png_debug(1, "in png_do_read_interlace");
if (row != NULL && row_info != NULL)
{
png_uint_32 final_width;
@@ -2526,29 +3699,31 @@ png_do_read_interlace(png_structp png_ptr)
{
case 1:
{
- png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
- png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
- int sshift, dshift;
- int s_start, s_end, s_inc;
- int jstop = png_pass_inc[pass];
+ png_bytep sp = row + (size_t)((row_info->width - 1) >> 3);
+ png_bytep dp = row + (size_t)((final_width - 1) >> 3);
+ unsigned int sshift, dshift;
+ unsigned int s_start, s_end;
+ int s_inc;
+ int jstop = (int)png_pass_inc[pass];
png_byte v;
png_uint_32 i;
int j;
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (transformations & PNG_PACKSWAP)
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((transformations & PNG_PACKSWAP) != 0)
{
- sshift = (int)((row_info->width + 7) & 0x07);
- dshift = (int)((final_width + 7) & 0x07);
+ sshift = ((row_info->width + 7) & 0x07);
+ dshift = ((final_width + 7) & 0x07);
s_start = 7;
s_end = 0;
s_inc = -1;
}
+
else
#endif
{
- sshift = 7 - (int)((row_info->width + 7) & 0x07);
- dshift = 7 - (int)((final_width + 7) & 0x07);
+ sshift = 7 - ((row_info->width + 7) & 0x07);
+ dshift = 7 - ((final_width + 7) & 0x07);
s_start = 0;
s_end = 7;
s_inc = 1;
@@ -2559,49 +3734,57 @@ png_do_read_interlace(png_structp png_ptr)
v = (png_byte)((*sp >> sshift) & 0x01);
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));
+ tmp |= (unsigned int)(v << dshift);
+ *dp = (png_byte)(tmp & 0xff);
+
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
+
else
- dshift += s_inc;
+ dshift = (unsigned int)((int)dshift + s_inc);
}
+
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
+
else
- sshift += s_inc;
+ sshift = (unsigned int)((int)sshift + s_inc);
}
break;
}
+
case 2:
{
png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
- int sshift, dshift;
- int s_start, s_end, s_inc;
- int jstop = png_pass_inc[pass];
+ unsigned int sshift, dshift;
+ unsigned int s_start, s_end;
+ int s_inc;
+ int jstop = (int)png_pass_inc[pass];
png_uint_32 i;
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (transformations & PNG_PACKSWAP)
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((transformations & PNG_PACKSWAP) != 0)
{
- sshift = (int)(((row_info->width + 3) & 0x03) << 1);
- dshift = (int)(((final_width + 3) & 0x03) << 1);
+ sshift = (((row_info->width + 3) & 0x03) << 1);
+ dshift = (((final_width + 3) & 0x03) << 1);
s_start = 6;
s_end = 0;
s_inc = -2;
}
+
else
#endif
{
- sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
- dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
+ sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1);
+ dshift = ((3 - ((final_width + 3) & 0x03)) << 1);
s_start = 0;
s_end = 6;
s_inc = 2;
@@ -2615,49 +3798,57 @@ png_do_read_interlace(png_structp png_ptr)
v = (png_byte)((*sp >> sshift) & 0x03);
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));
+ tmp |= (unsigned int)(v << dshift);
+ *dp = (png_byte)(tmp & 0xff);
+
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
+
else
- dshift += s_inc;
+ dshift = (unsigned int)((int)dshift + s_inc);
}
+
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
+
else
- sshift += s_inc;
+ sshift = (unsigned int)((int)sshift + s_inc);
}
break;
}
+
case 4:
{
- png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
- png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
- int sshift, dshift;
- int s_start, s_end, s_inc;
+ png_bytep sp = row + (size_t)((row_info->width - 1) >> 1);
+ png_bytep dp = row + (size_t)((final_width - 1) >> 1);
+ unsigned int sshift, dshift;
+ unsigned int s_start, s_end;
+ int s_inc;
png_uint_32 i;
- int jstop = png_pass_inc[pass];
+ int jstop = (int)png_pass_inc[pass];
-#if defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (transformations & PNG_PACKSWAP)
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+ if ((transformations & PNG_PACKSWAP) != 0)
{
- sshift = (int)(((row_info->width + 1) & 0x01) << 2);
- dshift = (int)(((final_width + 1) & 0x01) << 2);
+ sshift = (((row_info->width + 1) & 0x01) << 2);
+ dshift = (((final_width + 1) & 0x01) << 2);
s_start = 4;
s_end = 0;
s_inc = -4;
}
+
else
#endif
{
- sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
- dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
+ sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2);
+ dshift = ((1 - ((final_width + 1) & 0x01)) << 2);
s_start = 0;
s_end = 4;
s_inc = 4;
@@ -2665,393 +3856,624 @@ png_do_read_interlace(png_structp png_ptr)
for (i = 0; i < row_info->width; i++)
{
- png_byte v = (png_byte)((*sp >> sshift) & 0xf);
+ png_byte v = (png_byte)((*sp >> sshift) & 0x0f);
int j;
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0xf0f >> (4 - dshift));
+ tmp |= (unsigned int)(v << dshift);
+ *dp = (png_byte)(tmp & 0xff);
+
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
+
else
- dshift += s_inc;
+ dshift = (unsigned int)((int)dshift + s_inc);
}
+
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
+
else
- sshift += s_inc;
+ sshift = (unsigned int)((int)sshift + s_inc);
}
break;
}
+
default:
{
- png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
- png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
- png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
+ size_t pixel_bytes = (row_info->pixel_depth >> 3);
- int jstop = png_pass_inc[pass];
+ png_bytep sp = row + (size_t)(row_info->width - 1)
+ * pixel_bytes;
+
+ png_bytep dp = row + (size_t)(final_width - 1) * pixel_bytes;
+
+ int jstop = (int)png_pass_inc[pass];
png_uint_32 i;
for (i = 0; i < row_info->width; i++)
{
- png_byte v[8];
+ png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */
int j;
- png_memcpy(v, sp, pixel_bytes);
+ memcpy(v, sp, pixel_bytes);
+
for (j = 0; j < jstop; j++)
{
- png_memcpy(dp, v, pixel_bytes);
+ memcpy(dp, v, pixel_bytes);
dp -= pixel_bytes;
}
+
sp -= pixel_bytes;
}
break;
}
}
+
row_info->width = final_width;
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
}
-#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
- transformations = transformations; /* silence compiler warning */
+#ifndef PNG_READ_PACKSWAP_SUPPORTED
+ PNG_UNUSED(transformations) /* Silence compiler warning */
#endif
}
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
+#endif /* READ_INTERLACING */
-void /* PRIVATE */
-png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
- png_bytep prev_row, int filter)
+static void
+png_read_filter_row_sub(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row)
{
- png_debug(1, "in png_read_filter_row\n");
- png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
- switch (filter)
+ size_t i;
+ size_t istop = row_info->rowbytes;
+ unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+
+ PNG_UNUSED(prev_row)
+
+ for (i = bpp; i < istop; i++)
{
- case PNG_FILTER_VALUE_NONE:
- break;
- case PNG_FILTER_VALUE_SUB:
- {
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
- png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
- png_bytep rp = row + bpp;
- png_bytep lp = row;
+ *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
+ rp++;
+ }
+}
- for (i = bpp; i < istop; i++)
- {
- *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
- rp++;
- }
- break;
- }
- case PNG_FILTER_VALUE_UP:
- {
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
- png_bytep rp = row;
- png_bytep pp = prev_row;
+static void
+png_read_filter_row_up(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row)
+{
+ size_t i;
+ size_t istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_const_bytep pp = prev_row;
- for (i = 0; i < istop; i++)
- {
- *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
- rp++;
- }
- break;
- }
- case PNG_FILTER_VALUE_AVG:
- {
- png_uint_32 i;
- png_bytep rp = row;
- png_bytep pp = prev_row;
- png_bytep lp = row;
- png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
- png_uint_32 istop = row_info->rowbytes - bpp;
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+}
- for (i = 0; i < bpp; i++)
- {
- *rp = (png_byte)(((int)(*rp) +
- ((int)(*pp++) / 2 )) & 0xff);
- rp++;
- }
+static void
+png_read_filter_row_avg(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row)
+{
+ size_t i;
+ png_bytep rp = row;
+ png_const_bytep pp = prev_row;
+ unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
+ size_t istop = row_info->rowbytes - bpp;
- for (i = 0; i < istop; i++)
- {
- *rp = (png_byte)(((int)(*rp) +
- (int)(*pp++ + *lp++) / 2 ) & 0xff);
- rp++;
- }
- break;
- }
- case PNG_FILTER_VALUE_PAETH:
- {
- png_uint_32 i;
- png_bytep rp = row;
- png_bytep pp = prev_row;
- png_bytep lp = row;
- png_bytep cp = prev_row;
- png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
- png_uint_32 istop=row_info->rowbytes - bpp;
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) / 2 )) & 0xff);
- for (i = 0; i < bpp; i++)
- {
- *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
- rp++;
- }
+ rp++;
+ }
- for (i = 0; i < istop; i++) /* use leftover rp,pp */
- {
- int a, b, c, pa, pb, pc, p;
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
- a = *lp++;
- b = *pp++;
- c = *cp++;
+ rp++;
+ }
+}
- p = b - c;
- pc = a - c;
+static void
+png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row)
+{
+ png_bytep rp_end = row + row_info->rowbytes;
+ int a, c;
+
+ /* First pixel/byte */
+ c = *prev_row++;
+ a = *row + c;
+ *row++ = (png_byte)a;
+
+ /* Remainder */
+ while (row < rp_end)
+ {
+ int b, pa, pb, pc, p;
+
+ a &= 0xff; /* From previous iteration or start */
+ b = *prev_row++;
+
+ p = b - c;
+ pc = a - c;
#ifdef PNG_USE_ABS
- pa = abs(p);
- pb = abs(pc);
- pc = abs(p + pc);
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
#else
- pa = p < 0 ? -p : p;
- pb = pc < 0 ? -pc : pc;
- pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif
- /*
- if (pa <= pb && pa <= pc)
- p = a;
- else if (pb <= pc)
- p = b;
- else
- p = c;
+ /* Find the best predictor, the least of pa, pb, pc favoring the earlier
+ * ones in the case of a tie.
+ */
+ if (pb < pa)
+ {
+ pa = pb; a = b;
+ }
+ if (pc < pa) a = c;
+
+ /* Calculate the current pixel in a, and move the previous row pixel to c
+ * for the next time round the loop
+ */
+ c = b;
+ a += *row;
+ *row++ = (png_byte)a;
+ }
+}
+
+static void
+png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row)
+{
+ unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp_end = row + bpp;
+
+ /* Process the first pixel in the row completely (this is the same as 'up'
+ * because there is only one candidate predictor for the first row).
+ */
+ while (row < rp_end)
+ {
+ int a = *row + *prev_row++;
+ *row++ = (png_byte)a;
+ }
+
+ /* Remainder */
+ rp_end = rp_end + (row_info->rowbytes - bpp);
+
+ while (row < rp_end)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ c = *(prev_row - bpp);
+ a = *(row - bpp);
+ b = *prev_row++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ if (pb < pa)
+ {
+ pa = pb; a = b;
+ }
+ if (pc < pa) a = c;
+
+ a += *row;
+ *row++ = (png_byte)a;
+ }
+}
+
+static void
+png_init_filter_functions(png_structrp pp)
+ /* This function is called once for every PNG image (except for PNG images
+ * that only use PNG_FILTER_VALUE_NONE for all rows) to set the
+ * implementations required to reverse the filtering of PNG rows. Reversing
+ * the filter is the first transformation performed on the row data. It is
+ * performed in place, therefore an implementation can be selected based on
+ * the image pixel format. If the implementation depends on image width then
+ * take care to ensure that it works correctly if the image is interlaced -
+ * interlacing causes the actual row width to vary.
+ */
+{
+ unsigned int bpp = (pp->pixel_depth + 7) >> 3;
+
+ pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub;
+ pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up;
+ pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg;
+ if (bpp == 1)
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth_1byte_pixel;
+ else
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth_multibyte_pixel;
+
+#ifdef PNG_FILTER_OPTIMIZATIONS
+ /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to
+ * call to install hardware optimizations for the above functions; simply
+ * replace whatever elements of the pp->read_filter[] array with a hardware
+ * specific (or, for that matter, generic) optimization.
+ *
+ * To see an example of this examine what configure.ac does when
+ * --enable-arm-neon is specified on the command line.
+ */
+ PNG_FILTER_OPTIMIZATIONS(pp, bpp);
+#endif
+}
+
+void /* PRIVATE */
+png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row,
+ png_const_bytep prev_row, int filter)
+{
+ /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define
+ * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic
+ * implementations. See png_init_filter_functions above.
+ */
+ if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
+ {
+ if (pp->read_filter[0] == NULL)
+ png_init_filter_functions(pp);
+
+ pp->read_filter[filter-1](row_info, row, prev_row);
+ }
+}
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+void /* PRIVATE */
+png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
+ png_alloc_size_t avail_out)
+{
+ /* Loop reading IDATs and decompressing the result into output[avail_out] */
+ png_ptr->zstream.next_out = output;
+ png_ptr->zstream.avail_out = 0; /* safety: set below */
+
+ if (output == NULL)
+ avail_out = 0;
+
+ do
+ {
+ int ret;
+ png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
+
+ if (png_ptr->zstream.avail_in == 0)
+ {
+ uInt avail_in;
+ png_bytep buffer;
+
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+
+ png_ptr->idat_size = png_read_chunk_header(png_ptr);
+ /* This is an error even in the 'check' case because the code just
+ * consumed a non-IDAT header.
*/
-
- p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
-
- *rp = (png_byte)(((int)(*rp) + p) & 0xff);
- rp++;
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
}
+
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+ avail_in = (uInt)png_ptr->idat_size;
+
+ /* A PNG with a gradually increasing IDAT size will defeat this attempt
+ * 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.
+ */
+ buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);
+
+ png_crc_read(png_ptr, buffer, avail_in);
+ png_ptr->idat_size -= avail_in;
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = avail_in;
+ }
+
+ /* And set up the output side. */
+ if (output != NULL) /* standard read */
+ {
+ uInt out = ZLIB_IO_MAX;
+
+ if (out > avail_out)
+ out = (uInt)avail_out;
+
+ avail_out -= out;
+ png_ptr->zstream.avail_out = out;
+ }
+
+ else /* after last row, checking for end */
+ {
+ png_ptr->zstream.next_out = tmpbuf;
+ png_ptr->zstream.avail_out = (sizeof tmpbuf);
+ }
+
+ /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the
+ * process. If the LZ stream is truncated the sequential reader will
+ * terminally damage the stream, above, by reading the chunk header of the
+ * following chunk (it then exits with png_error).
+ *
+ * TODO: deal more elegantly with truncated IDAT lists.
+ */
+ ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH);
+
+ /* Take the unconsumed output back. */
+ if (output != NULL)
+ avail_out += png_ptr->zstream.avail_out;
+
+ else /* avail_out counts the extra bytes */
+ avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out;
+
+ png_ptr->zstream.avail_out = 0;
+
+ if (ret == Z_STREAM_END)
+ {
+ /* Do this for safety; we won't read any more into this row. */
+ png_ptr->zstream.next_out = NULL;
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
break;
}
- default:
- png_warning(png_ptr, "Ignoring bad adaptive filter type");
- *row=0;
- break;
+
+ if (ret != Z_OK)
+ {
+ png_zstream_error(png_ptr, ret);
+
+ if (output != NULL)
+ png_chunk_error(png_ptr, png_ptr->zstream.msg);
+
+ else /* checking */
+ {
+ png_chunk_benign_error(png_ptr, png_ptr->zstream.msg);
+ return;
+ }
+ }
+ } while (avail_out > 0);
+
+ if (avail_out > 0)
+ {
+ /* The stream ended before the image; this is the same as too few IDATs so
+ * should be handled the same way.
+ */
+ if (output != NULL)
+ png_error(png_ptr, "Not enough image data");
+
+ else /* the deflate stream contained extra data */
+ png_chunk_benign_error(png_ptr, "Too much image data");
}
}
void /* PRIVATE */
-png_read_finish_row(png_structp png_ptr)
+png_read_finish_IDAT(png_structrp png_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* We don't need any more data and the stream should have ended, however the
+ * LZ end code may actually not have been processed. In this case we must
+ * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk
+ * may still remain to be consumed.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ {
+ /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in
+ * the compressed stream, but the stream may be damaged too, so even after
+ * this call we may need to terminate the zstream ownership.
+ */
+ png_read_IDAT_data(png_ptr, NULL, 0);
+ png_ptr->zstream.next_out = NULL; /* safety */
- /* start of interlace block */
- PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Now clear everything out for safety; the following may not have been
+ * done.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ {
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+ }
+ }
- /* offset to next interlace block */
- PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+ /* If the zstream has not been released do it now *and* terminate the reading
+ * of the final IDAT chunk.
+ */
+ if (png_ptr->zowner == png_IDAT)
+ {
+ /* Always do this; the pointers otherwise point into the read buffer. */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
- /* start of interlace block in the y direction */
- PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+ /* Now we no longer own the zstream. */
+ png_ptr->zowner = 0;
- /* offset to next interlace block in the y direction */
- PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
+ /* The slightly weird semantics of the sequential IDAT reading is that we
+ * are always in or at the end of an IDAT chunk, so we always need to do a
+ * crc_finish here. If idat_size is non-zero we also need to read the
+ * spurious bytes at the end of the chunk now.
+ */
+ (void)png_crc_finish(png_ptr, png_ptr->idat_size);
+ }
+}
- png_debug(1, "in png_read_finish_row\n");
+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)
return;
- if (png_ptr->interlaced)
+ if (png_ptr->interlaced != 0)
{
png_ptr->row_number = 0;
- png_memset_check(png_ptr, png_ptr->prev_row, 0,
- png_ptr->rowbytes + 1);
+
+ /* TO DO: don't do this if prev_row isn't needed (requires
+ * read-ahead of the next row's filter byte.
+ */
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
do
{
png_ptr->pass++;
+
if (png_ptr->pass >= 7)
break;
+
png_ptr->iwidth = (png_ptr->width +
png_pass_inc[png_ptr->pass] - 1 -
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
- png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
- png_ptr->iwidth) + 1;
-
- if (!(png_ptr->transformations & PNG_INTERLACE))
+ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
{
png_ptr->num_rows = (png_ptr->height +
- png_pass_yinc[png_ptr->pass] - 1 -
- png_pass_ystart[png_ptr->pass]) /
- png_pass_yinc[png_ptr->pass];
- if (!(png_ptr->num_rows))
- continue;
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
}
+
else /* if (png_ptr->transformations & PNG_INTERLACE) */
- break;
- } while (png_ptr->iwidth == 0);
+ break; /* libpng deinterlacing sees every row */
+
+ } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0);
if (png_ptr->pass < 7)
return;
}
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
- {
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_CONST PNG_IDAT;
-#endif
- char extra;
- int ret;
-
- png_ptr->zstream.next_out = (Byte *)&extra;
- png_ptr->zstream.avail_out = (uInt)1;
- for(;;)
- {
- if (!(png_ptr->zstream.avail_in))
- {
- while (!png_ptr->idat_size)
- {
- png_byte chunk_length[4];
-
- png_crc_finish(png_ptr, 0);
-
- png_read_data(png_ptr, chunk_length, 4);
- png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
- png_reset_crc(png_ptr);
- png_crc_read(png_ptr, png_ptr->chunk_name, 4);
- if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
- png_error(png_ptr, "Not enough image data");
-
- }
- png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_in = png_ptr->zbuf;
- if (png_ptr->zbuf_size > png_ptr->idat_size)
- png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
- png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
- png_ptr->idat_size -= png_ptr->zstream.avail_in;
- }
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret == Z_STREAM_END)
- {
- if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
- png_ptr->idat_size)
- png_warning(png_ptr, "Extra compressed data");
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
- if (ret != Z_OK)
- png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
- "Decompression Error");
-
- if (!(png_ptr->zstream.avail_out))
- {
- png_warning(png_ptr, "Extra compressed data.");
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
-
- }
- png_ptr->zstream.avail_out = 0;
- }
-
- if (png_ptr->idat_size || png_ptr->zstream.avail_in)
- png_warning(png_ptr, "Extra compression data");
-
- inflateReset(&png_ptr->zstream);
-
- png_ptr->mode |= PNG_AFTER_IDAT;
+ /* Here after at the end of the last row of the last pass. */
+ png_read_finish_IDAT(png_ptr);
}
+#endif /* SEQUENTIAL_READ */
void /* PRIVATE */
-png_read_start_row(png_structp png_ptr)
+png_read_start_row(png_structrp png_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* start of interlace block */
- PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Start of interlace block */
+ static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
- /* offset to next interlace block */
- PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+ /* 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 */
- PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 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 */
- PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
+ /* Offset to next interlace block in the y direction */
+ static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
- int max_pixel_depth;
- png_uint_32 row_bytes;
+ unsigned int max_pixel_depth;
+ size_t row_bytes;
- png_debug(1, "in png_read_start_row\n");
- png_ptr->zstream.avail_in = 0;
+ png_debug(1, "in png_read_start_row");
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
png_init_read_transformations(png_ptr);
- if (png_ptr->interlaced)
+#endif
+ if (png_ptr->interlaced != 0)
{
- if (!(png_ptr->transformations & PNG_INTERLACE))
+ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
- png_pass_ystart[0]) / png_pass_yinc[0];
+ png_pass_ystart[0]) / png_pass_yinc[0];
+
else
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = (png_ptr->width +
- png_pass_inc[png_ptr->pass] - 1 -
- png_pass_start[png_ptr->pass]) /
- png_pass_inc[png_ptr->pass];
-
- row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
-
- png_ptr->irowbytes = (png_size_t)row_bytes;
- if((png_uint_32)png_ptr->irowbytes != row_bytes)
- png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
}
+
else
{
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = png_ptr->width;
- png_ptr->irowbytes = png_ptr->rowbytes + 1;
}
- max_pixel_depth = png_ptr->pixel_depth;
-#if defined(PNG_READ_PACK_SUPPORTED)
- if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ max_pixel_depth = (unsigned int)png_ptr->pixel_depth;
+
+ /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of
+ * calculations to calculate the final pixel depth, then
+ * png_do_read_transforms actually does the transforms. This means that the
+ * code which effectively calculates this value is actually repeated in three
+ * separate places. They must all match. Innocent changes to the order of
+ * transformations can and will break libpng in a way that causes memory
+ * overwrites.
+ *
+ * TODO: fix this.
+ */
+#ifdef PNG_READ_PACK_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8)
max_pixel_depth = 8;
#endif
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- if (png_ptr->transformations & PNG_EXPAND)
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
max_pixel_depth = 32;
+
else
max_pixel_depth = 24;
}
+
else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
if (max_pixel_depth < 8)
max_pixel_depth = 8;
- if (png_ptr->num_trans)
+
+ if (png_ptr->num_trans != 0)
max_pixel_depth *= 2;
}
+
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
{
max_pixel_depth *= 4;
max_pixel_depth /= 3;
@@ -3060,56 +4482,82 @@ png_read_start_row(png_structp png_ptr)
}
#endif
-#if defined(PNG_READ_FILLER_SUPPORTED)
- if (png_ptr->transformations & (PNG_FILLER))
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND_16) != 0)
{
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- max_pixel_depth = 32;
- else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+# ifdef PNG_READ_EXPAND_SUPPORTED
+ /* In fact it is an error if it isn't supported, but checking is
+ * the safe way.
+ */
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
+ {
+ if (png_ptr->bit_depth < 16)
+ max_pixel_depth *= 2;
+ }
+ else
+# endif
+ png_ptr->transformations &= ~PNG_EXPAND_16;
+ }
+#endif
+
+#ifdef PNG_READ_FILLER_SUPPORTED
+ if ((png_ptr->transformations & (PNG_FILLER)) != 0)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
if (max_pixel_depth <= 8)
max_pixel_depth = 16;
+
else
max_pixel_depth = 32;
}
- else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+ png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (max_pixel_depth <= 32)
max_pixel_depth = 32;
+
else
max_pixel_depth = 64;
}
}
#endif
-#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
- if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
{
if (
-#if defined(PNG_READ_EXPAND_SUPPORTED)
- (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+#ifdef PNG_READ_EXPAND_SUPPORTED
+ (png_ptr->num_trans != 0 &&
+ (png_ptr->transformations & PNG_EXPAND) != 0) ||
#endif
-#if defined(PNG_READ_FILLER_SUPPORTED)
- (png_ptr->transformations & (PNG_FILLER)) ||
+#ifdef PNG_READ_FILLER_SUPPORTED
+ (png_ptr->transformations & (PNG_FILLER)) != 0 ||
#endif
- png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if (max_pixel_depth <= 16)
max_pixel_depth = 32;
+
else
max_pixel_depth = 64;
}
+
else
{
if (max_pixel_depth <= 8)
- {
- if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
max_pixel_depth = 32;
- else
+
+ else
max_pixel_depth = 24;
- }
+ }
+
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
max_pixel_depth = 64;
+
else
max_pixel_depth = 48;
}
@@ -3118,47 +4566,115 @@ png_read_start_row(png_structp png_ptr)
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
- if(png_ptr->transformations & PNG_USER_TRANSFORM)
- {
- int user_pixel_depth=png_ptr->user_transform_depth*
+ if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
+ {
+ unsigned int user_pixel_depth = png_ptr->user_transform_depth *
png_ptr->user_transform_channels;
- if(user_pixel_depth > max_pixel_depth)
- max_pixel_depth=user_pixel_depth;
- }
+
+ if (user_pixel_depth > max_pixel_depth)
+ max_pixel_depth = user_pixel_depth;
+ }
#endif
- /* align the width on the next larger 8 pixels. Mainly used
- for interlacing */
+ /* This value is stored in png_struct and double checked in the row read
+ * code.
+ */
+ png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth;
+ png_ptr->transformed_pixel_depth = 0; /* calculated on demand */
+
+ /* Align the width on the next larger 8 pixels. Mainly used
+ * for interlacing
+ */
row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
- /* calculate the maximum bytes needed, adding a byte and a pixel
- for safety's sake */
- row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) +
- 1 + ((max_pixel_depth + 7) >> 3);
+ /* Calculate the maximum bytes needed, adding a byte and a pixel
+ * for safety's sake
+ */
+ row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
+ 1 + ((max_pixel_depth + 7) >> 3U);
+
#ifdef PNG_MAX_MALLOC_64K
if (row_bytes > (png_uint_32)65536L)
png_error(png_ptr, "This image requires a row greater than 64KB");
#endif
- png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
- png_ptr->row_buf = png_ptr->big_row_buf+32;
+
+ if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
+ {
+ png_free(png_ptr, png_ptr->big_row_buf);
+ png_free(png_ptr, png_ptr->big_prev_row);
+
+ if (png_ptr->interlaced != 0)
+ png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
+ row_bytes + 48);
+
+ else
+ png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
+
+ png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
+
+#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
+ /* Use 16-byte aligned memory for row_buf with at least 16 bytes
+ * of padding before and after row_buf; treat prev_row similarly.
+ * NOTE: the alignment is to the start of the pixels, one beyond the start
+ * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this
+ * was incorrect; the filter byte was aligned, which had the exact
+ * opposite effect of that intended.
+ */
+ {
+ png_bytep temp = png_ptr->big_row_buf + 32;
+ size_t extra = (size_t)temp & 0x0f;
+ png_ptr->row_buf = temp - extra - 1/*filter byte*/;
+
+ temp = png_ptr->big_prev_row + 32;
+ extra = (size_t)temp & 0x0f;
+ png_ptr->prev_row = temp - extra - 1/*filter byte*/;
+ }
+#else
+ /* Use 31 bytes of padding before and 17 bytes after row_buf. */
+ png_ptr->row_buf = png_ptr->big_row_buf + 31;
+ png_ptr->prev_row = png_ptr->big_prev_row + 31;
+#endif
+ png_ptr->old_big_row_buf_size = row_bytes + 48;
+ }
#ifdef PNG_MAX_MALLOC_64K
- if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
+ if (png_ptr->rowbytes > 65535)
png_error(png_ptr, "This image requires a row greater than 64KB");
+
#endif
- if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
- png_error(png_ptr, "Row has too many bytes to allocate in memory.");
- png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
- png_ptr->rowbytes + 1));
+ if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
+ png_error(png_ptr, "Row has too many bytes to allocate in memory");
- png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
- png_debug1(3, "width = %lu,\n", png_ptr->width);
- png_debug1(3, "height = %lu,\n", png_ptr->height);
- png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
- png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
- png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
- png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
+ png_debug1(3, "width = %u,", png_ptr->width);
+ png_debug1(3, "height = %u,", png_ptr->height);
+ png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
+ png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
+ png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes);
+ png_debug1(3, "irowbytes = %lu",
+ (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
+
+ /* The sequential reader needs a buffer for IDAT, but the progressive reader
+ * does not, so free the read buffer now regardless; the sequential reader
+ * reallocates it on demand.
+ */
+ if (png_ptr->read_buffer != NULL)
+ {
+ png_bytep buffer = png_ptr->read_buffer;
+
+ png_ptr->read_buffer_size = 0;
+ png_ptr->read_buffer = NULL;
+ png_free(png_ptr, buffer);
+ }
+
+ /* Finally claim the zstream for the inflate of the IDAT data, use the bits
+ * value from the stream (note that this will result in a fatal error if the
+ * IDAT stream has a bogus deflate header window_bits value, but this should
+ * not be happening any longer!)
+ */
+ if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ */
diff --git a/PDF/src/pngset.c b/PDF/src/pngset.c
index d598d4d1b..eb1c8c7a3 100644
--- a/PDF/src/pngset.c
+++ b/PDF/src/pngset.c
@@ -1,11 +1,14 @@
/* pngset.c - storage of image information into info struct
*
- * Last changed in libpng 1.2.24 [December 14, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* The functions here are used during reads to store data from the file
* into the info struct, and during writes to store application data
@@ -13,365 +16,279 @@
* info struct and allows us to change the structure in the future.
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-#if defined(PNG_bKGD_SUPPORTED)
+#ifdef PNG_bKGD_SUPPORTED
void PNGAPI
-png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_color_16p background)
{
- png_debug1(1, "in %s storage function\n", "bKGD");
- if (png_ptr == NULL || info_ptr == NULL)
+ png_debug1(1, "in %s storage function", "bKGD");
+
+ if (png_ptr == NULL || info_ptr == NULL || background == NULL)
return;
- png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16));
+ info_ptr->background = *background;
info_ptr->valid |= PNG_INFO_bKGD;
}
#endif
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-void PNGAPI
-png_set_cHRM(png_structp png_ptr, png_infop 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)
+#ifdef PNG_cHRM_SUPPORTED
+void PNGFAPI
+png_set_cHRM_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_debug1(1, "in %s storage function\n", "cHRM");
- if (png_ptr == NULL || info_ptr == NULL)
- return;
- if (!(white_x || white_y || red_x || red_y || green_x || green_y ||
- blue_x || blue_y))
- {
- png_warning(png_ptr,
- "Ignoring attempt to set all-zero chromaticity values");
- return;
- }
- if (white_x < 0.0 || white_y < 0.0 ||
- red_x < 0.0 || red_y < 0.0 ||
- green_x < 0.0 || green_y < 0.0 ||
- blue_x < 0.0 || blue_y < 0.0)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set negative chromaticity value");
- return;
- }
- if (white_x > 21474.83 || white_y > 21474.83 ||
- red_x > 21474.83 || red_y > 21474.83 ||
- green_x > 21474.83 || green_y > 21474.83 ||
- blue_x > 21474.83 || blue_y > 21474.83)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set chromaticity value exceeding 21474.83");
- return;
- }
+ png_xy xy;
+
+ png_debug1(1, "in %s storage function", "cHRM fixed");
- info_ptr->x_white = (float)white_x;
- info_ptr->y_white = (float)white_y;
- info_ptr->x_red = (float)red_x;
- info_ptr->y_red = (float)red_y;
- info_ptr->x_green = (float)green_x;
- info_ptr->y_green = (float)green_y;
- info_ptr->x_blue = (float)blue_x;
- info_ptr->y_blue = (float)blue_y;
-#ifdef PNG_FIXED_POINT_SUPPORTED
- info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5);
- info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5);
- info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5);
- info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5);
- info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5);
- info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5);
- info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5);
- info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5);
-#endif
- info_ptr->valid |= PNG_INFO_cHRM;
-}
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-void PNGAPI
-png_set_cHRM_fixed(png_structp png_ptr, png_infop 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_debug1(1, "in %s storage function\n", "cHRM");
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (!(white_x || white_y || red_x || red_y || green_x || green_y ||
- blue_x || blue_y))
- {
- png_warning(png_ptr,
- "Ignoring attempt to set all-zero chromaticity values");
- return;
- }
- if (white_x < 0 || white_y < 0 ||
- red_x < 0 || red_y < 0 ||
- green_x < 0 || green_y < 0 ||
- blue_x < 0 || blue_y < 0)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set negative chromaticity value");
- return;
- }
- if (white_x > (png_fixed_point) PNG_UINT_31_MAX ||
- white_y > (png_fixed_point) PNG_UINT_31_MAX ||
- red_x > (png_fixed_point) PNG_UINT_31_MAX ||
- red_y > (png_fixed_point) PNG_UINT_31_MAX ||
- green_x > (png_fixed_point) PNG_UINT_31_MAX ||
- green_y > (png_fixed_point) PNG_UINT_31_MAX ||
- blue_x > (png_fixed_point) PNG_UINT_31_MAX ||
- blue_y > (png_fixed_point) PNG_UINT_31_MAX )
- {
- png_warning(png_ptr,
- "Ignoring attempt to set chromaticity value exceeding 21474.83");
- return;
- }
- info_ptr->int_x_white = white_x;
- info_ptr->int_y_white = white_y;
- info_ptr->int_x_red = red_x;
- info_ptr->int_y_red = red_y;
- info_ptr->int_x_green = green_x;
- info_ptr->int_y_green = green_y;
- info_ptr->int_x_blue = blue_x;
- info_ptr->int_y_blue = blue_y;
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- info_ptr->x_white = (float)(white_x/100000.);
- info_ptr->y_white = (float)(white_y/100000.);
- info_ptr->x_red = (float)( red_x/100000.);
- info_ptr->y_red = (float)( red_y/100000.);
- info_ptr->x_green = (float)(green_x/100000.);
- info_ptr->y_green = (float)(green_y/100000.);
- info_ptr->x_blue = (float)( blue_x/100000.);
- info_ptr->y_blue = (float)( blue_y/100000.);
-#endif
- info_ptr->valid |= PNG_INFO_cHRM;
-}
-#endif
-#endif
+ 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;
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-void PNGAPI
-png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+ 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);
+}
+
+void PNGFAPI
+png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_fixed_point int_red_X, png_fixed_point int_red_Y,
+ png_fixed_point int_red_Z, png_fixed_point int_green_X,
+ png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+ png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+ png_fixed_point int_blue_Z)
{
- double gamma;
- png_debug1(1, "in %s storage function\n", "gAMA");
+ png_XYZ XYZ;
+
+ png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- /* Check for overflow */
- if (file_gamma > 21474.83)
- {
- png_warning(png_ptr, "Limiting gamma to 21474.83");
- gamma=21474.83;
- }
- else
- gamma=file_gamma;
- info_ptr->gamma = (float)gamma;
-#ifdef PNG_FIXED_POINT_SUPPORTED
- info_ptr->int_gamma = (int)(gamma*100000.+.5);
-#endif
- info_ptr->valid |= PNG_INFO_gAMA;
- if(gamma == 0.0)
- png_warning(png_ptr, "Setting gamma=0");
-}
-#endif
-void PNGAPI
-png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
- int_gamma)
-{
- png_fixed_point gamma;
+ XYZ.red_X = int_red_X;
+ XYZ.red_Y = int_red_Y;
+ XYZ.red_Z = int_red_Z;
+ XYZ.green_X = int_green_X;
+ XYZ.green_Y = int_green_Y;
+ XYZ.green_Z = int_green_Z;
+ XYZ.blue_X = int_blue_X;
+ 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;
+
+ png_colorspace_sync_info(png_ptr, info_ptr);
+}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_cHRM(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)
+{
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ png_fixed(png_ptr, white_x, "cHRM White X"),
+ png_fixed(png_ptr, white_y, "cHRM White Y"),
+ png_fixed(png_ptr, red_x, "cHRM Red X"),
+ png_fixed(png_ptr, red_y, "cHRM Red Y"),
+ png_fixed(png_ptr, green_x, "cHRM Green X"),
+ png_fixed(png_ptr, green_y, "cHRM Green Y"),
+ png_fixed(png_ptr, blue_x, "cHRM Blue X"),
+ png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
+}
+
+void PNGAPI
+png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
+ double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
+ double blue_X, double blue_Y, double blue_Z)
+{
+ png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
+ png_fixed(png_ptr, red_X, "cHRM Red X"),
+ png_fixed(png_ptr, red_Y, "cHRM Red Y"),
+ png_fixed(png_ptr, red_Z, "cHRM Red Z"),
+ png_fixed(png_ptr, green_X, "cHRM Green X"),
+ png_fixed(png_ptr, green_Y, "cHRM Green Y"),
+ png_fixed(png_ptr, green_Z, "cHRM Green Z"),
+ png_fixed(png_ptr, blue_X, "cHRM Blue X"),
+ png_fixed(png_ptr, blue_Y, "cHRM Blue Y"),
+ png_fixed(png_ptr, blue_Z, "cHRM Blue Z"));
+}
+# endif /* FLOATING_POINT */
+
+#endif /* cHRM */
+
+#ifdef PNG_eXIf_SUPPORTED
+void PNGAPI
+png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_bytep exif)
+{
+ png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(exif)
+}
+
+void PNGAPI
+png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_uint_32 num_exif, png_bytep exif)
+{
+ png_bytep new_exif;
+
+ png_debug1(1, "in %s storage function", "eXIf");
+
+ if (png_ptr == NULL || info_ptr == NULL ||
+ (png_ptr->mode & PNG_WROTE_eXIf) != 0)
+ return;
+
+ new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
+
+ if (new_exif == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
+ return;
+ }
+
+ memcpy(new_exif, exif, (size_t)num_exif);
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
+
+ info_ptr->num_exif = num_exif;
+ info_ptr->exif = new_exif;
+ info_ptr->free_me |= PNG_FREE_EXIF;
+ info_ptr->valid |= PNG_INFO_eXIf;
+}
+#endif /* eXIf */
+
+#ifdef PNG_gAMA_SUPPORTED
+void PNGFAPI
+png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_fixed_point file_gamma)
+{
+ png_debug1(1, "in %s storage function", "gAMA");
- png_debug1(1, "in %s storage function\n", "gAMA");
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (int_gamma > (png_fixed_point) PNG_UINT_31_MAX)
- {
- png_warning(png_ptr, "Limiting gamma to 21474.83");
- gamma=PNG_UINT_31_MAX;
- }
- else
- {
- if (int_gamma < 0)
- {
- png_warning(png_ptr, "Setting negative gamma to zero");
- gamma=0;
- }
- else
- gamma=int_gamma;
- }
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- info_ptr->gamma = (float)(gamma/100000.);
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- info_ptr->int_gamma = gamma;
-#endif
- info_ptr->valid |= PNG_INFO_gAMA;
- if(gamma == 0)
- png_warning(png_ptr, "Setting gamma=0");
+ png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
+ png_colorspace_sync_info(png_ptr, info_ptr);
}
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
+{
+ png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
+ "png_set_gAMA"));
+}
+# endif
#endif
-#if defined(PNG_hIST_SUPPORTED)
+#ifdef PNG_hIST_SUPPORTED
void PNGAPI
-png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_uint_16p hist)
{
int i;
- png_debug1(1, "in %s storage function\n", "hIST");
+ png_debug1(1, "in %s storage function", "hIST");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
+
if (info_ptr->num_palette == 0 || info_ptr->num_palette
> PNG_MAX_PALETTE_LENGTH)
{
- png_warning(png_ptr,
- "Invalid palette size, hIST allocation skipped.");
- return;
+ png_warning(png_ptr,
+ "Invalid palette size, hIST allocation skipped");
+
+ return;
}
-#ifdef PNG_FREE_ME_SUPPORTED
png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
-#endif
- /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in version
- 1.2.1 */
- png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr,
- (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof (png_uint_16)));
- if (png_ptr->hist == NULL)
- {
- png_warning(png_ptr, "Insufficient memory for hIST chunk data.");
- return;
- }
+
+ /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
+ * version 1.2.1
+ */
+ info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
+ PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
+
+ if (info_ptr->hist == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for hIST chunk data");
+ return;
+ }
for (i = 0; i < info_ptr->num_palette; i++)
- png_ptr->hist[i] = hist[i];
- info_ptr->hist = png_ptr->hist;
- info_ptr->valid |= PNG_INFO_hIST;
+ info_ptr->hist[i] = hist[i];
-#ifdef PNG_FREE_ME_SUPPORTED
info_ptr->free_me |= PNG_FREE_HIST;
-#else
- png_ptr->flags |= PNG_FLAG_FREE_HIST;
-#endif
+ info_ptr->valid |= PNG_INFO_hIST;
}
#endif
void PNGAPI
-png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 width, png_uint_32 height, int bit_depth,
- int color_type, int interlace_type, int compression_type,
- int filter_type)
+png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
{
- png_debug1(1, "in %s storage function\n", "IHDR");
+ png_debug1(1, "in %s storage function", "IHDR");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- /* check for width and height valid values */
- if (width == 0 || height == 0)
- png_error(png_ptr, "Image width or height is zero in IHDR");
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- if (width > png_ptr->user_width_max || height > png_ptr->user_height_max)
- png_error(png_ptr, "image size exceeds user limits in IHDR");
-#else
- if (width > PNG_USER_WIDTH_MAX || height > PNG_USER_HEIGHT_MAX)
- png_error(png_ptr, "image size exceeds user limits in IHDR");
-#endif
- if (width > PNG_UINT_31_MAX || height > PNG_UINT_31_MAX)
- png_error(png_ptr, "Invalid image size in IHDR");
- if ( width > (PNG_UINT_32_MAX
- >> 3) /* 8-byte RGBA pixels */
- - 64 /* bigrowbuf hack */
- - 1 /* filter byte */
- - 7*8 /* rounding of width to multiple of 8 pixels */
- - 8) /* extra max_pixel_depth pad */
- png_warning(png_ptr, "Width is too large for libpng to process pixels");
-
- /* check other values */
- if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
- bit_depth != 8 && bit_depth != 16)
- png_error(png_ptr, "Invalid bit depth in IHDR");
-
- if (color_type < 0 || color_type == 1 ||
- color_type == 5 || color_type > 6)
- png_error(png_ptr, "Invalid color type in IHDR");
-
- if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
- ((color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
- color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
- png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
-
- if (interlace_type >= PNG_INTERLACE_LAST)
- png_error(png_ptr, "Unknown interlace method in IHDR");
-
- if (compression_type != PNG_COMPRESSION_TYPE_BASE)
- png_error(png_ptr, "Unknown compression method in IHDR");
-
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- /* Accept filter_method 64 (intrapixel differencing) only if
- * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
- * 2. Libpng did not read a PNG signature (this filter_method is only
- * used in PNG datastreams that are embedded in MNG datastreams) and
- * 3. The application called png_permit_mng_features with a mask that
- * included PNG_FLAG_MNG_FILTER_64 and
- * 4. The filter_method is 64 and
- * 5. The color_type is RGB or RGBA
- */
- if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&png_ptr->mng_features_permitted)
- png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
- if(filter_type != PNG_FILTER_TYPE_BASE)
- {
- if(!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
- (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
- ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
- (color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
- png_error(png_ptr, "Unknown filter method in IHDR");
- if(png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)
- png_warning(png_ptr, "Invalid filter method in IHDR");
- }
-#else
- if(filter_type != PNG_FILTER_TYPE_BASE)
- png_error(png_ptr, "Unknown filter method in IHDR");
-#endif
-
info_ptr->width = width;
info_ptr->height = height;
info_ptr->bit_depth = (png_byte)bit_depth;
- info_ptr->color_type =(png_byte) color_type;
+ info_ptr->color_type = (png_byte)color_type;
info_ptr->compression_type = (png_byte)compression_type;
info_ptr->filter_type = (png_byte)filter_type;
info_ptr->interlace_type = (png_byte)interlace_type;
+
+ png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
+ info_ptr->compression_type, info_ptr->filter_type);
+
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
info_ptr->channels = 1;
- else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+
+ else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
info_ptr->channels = 3;
+
else
info_ptr->channels = 1;
- if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+
+ if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
info_ptr->channels++;
+
info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
- /* check for potential overflow */
- if (width > (PNG_UINT_32_MAX
- >> 3) /* 8-byte RGBA pixels */
- - 64 /* bigrowbuf hack */
- - 1 /* filter byte */
- - 7*8 /* rounding of width to multiple of 8 pixels */
- - 8) /* extra max_pixel_depth pad */
- info_ptr->rowbytes = (png_size_t)0;
- else
- info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width);
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
}
-#if defined(PNG_oFFs_SUPPORTED)
+#ifdef PNG_oFFs_SUPPORTED
void PNGAPI
-png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
- png_int_32 offset_x, png_int_32 offset_y, int unit_type)
+png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_int_32 offset_x, png_int_32 offset_y, int unit_type)
{
- png_debug1(1, "in %s storage function\n", "oFFs");
+ png_debug1(1, "in %s storage function", "oFFs");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
@@ -382,141 +299,254 @@ png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
}
#endif
-#if defined(PNG_pCAL_SUPPORTED)
+#ifdef PNG_pCAL_SUPPORTED
void PNGAPI
-png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
- png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
- png_charp units, png_charpp params)
+png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
+ int nparams, png_const_charp units, png_charpp params)
{
- png_uint_32 length;
+ size_t length;
int i;
- png_debug1(1, "in %s storage function\n", "pCAL");
- if (png_ptr == NULL || info_ptr == NULL)
+ png_debug1(1, "in %s storage function", "pCAL");
+
+ if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
+ || (nparams > 0 && params == NULL))
return;
- length = png_strlen(purpose) + 1;
- png_debug1(3, "allocating purpose for info (%lu bytes)\n", length);
- info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length);
- if (info_ptr->pcal_purpose == NULL)
- {
- png_warning(png_ptr, "Insufficient memory for pCAL purpose.");
- return;
- }
- png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length);
+ length = strlen(purpose) + 1;
+ png_debug1(3, "allocating purpose for info (%lu bytes)",
+ (unsigned long)length);
- png_debug(3, "storing X0, X1, type, and nparams in info\n");
+ /* TODO: validate format of calibration name and unit name */
+
+ /* Check that the type matches the specification. */
+ if (type < 0 || type > 3)
+ {
+ png_chunk_report(png_ptr, "Invalid pCAL equation type",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ if (nparams < 0 || nparams > 255)
+ {
+ png_chunk_report(png_ptr, "Invalid pCAL parameter count",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ /* Validate params[nparams] */
+ for (i=0; ipcal_purpose = png_voidcast(png_charp,
+ png_malloc_warn(png_ptr, length));
+
+ if (info_ptr->pcal_purpose == NULL)
+ {
+ png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ memcpy(info_ptr->pcal_purpose, purpose, length);
+
+ info_ptr->free_me |= PNG_FREE_PCAL;
+
+ png_debug(3, "storing X0, X1, type, and nparams in info");
info_ptr->pcal_X0 = X0;
info_ptr->pcal_X1 = X1;
info_ptr->pcal_type = (png_byte)type;
info_ptr->pcal_nparams = (png_byte)nparams;
- length = png_strlen(units) + 1;
- png_debug1(3, "allocating units for info (%lu bytes)\n", length);
- info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length);
+ length = strlen(units) + 1;
+ png_debug1(3, "allocating units for info (%lu bytes)",
+ (unsigned long)length);
+
+ info_ptr->pcal_units = png_voidcast(png_charp,
+ png_malloc_warn(png_ptr, length));
+
if (info_ptr->pcal_units == NULL)
- {
- png_warning(png_ptr, "Insufficient memory for pCAL units.");
- return;
- }
- png_memcpy(info_ptr->pcal_units, units, (png_size_t)length);
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL units");
+ return;
+ }
+
+ memcpy(info_ptr->pcal_units, units, length);
+
+ info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
+ (size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp)))));
- info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr,
- (png_uint_32)((nparams + 1) * png_sizeof(png_charp)));
if (info_ptr->pcal_params == NULL)
- {
- png_warning(png_ptr, "Insufficient memory for pCAL params.");
- return;
- }
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL params");
+ return;
+ }
- info_ptr->pcal_params[nparams] = NULL;
+ memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) *
+ (sizeof (png_charp)));
for (i = 0; i < nparams; i++)
{
- length = png_strlen(params[i]) + 1;
- png_debug2(3, "allocating parameter %d for info (%lu bytes)\n", i, length);
+ length = strlen(params[i]) + 1;
+ png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
+ (unsigned long)length);
+
info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
+
if (info_ptr->pcal_params[i] == NULL)
- {
- png_warning(png_ptr, "Insufficient memory for pCAL parameter.");
- return;
- }
- png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length);
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL parameter");
+ return;
+ }
+
+ memcpy(info_ptr->pcal_params[i], params[i], length);
}
info_ptr->valid |= PNG_INFO_pCAL;
-#ifdef PNG_FREE_ME_SUPPORTED
- info_ptr->free_me |= PNG_FREE_PCAL;
-#endif
}
#endif
-#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_sCAL_SUPPORTED
void PNGAPI
-png_set_sCAL(png_structp png_ptr, png_infop info_ptr,
- int unit, double width, double height)
+png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
+ int unit, png_const_charp swidth, png_const_charp sheight)
{
- png_debug1(1, "in %s storage function\n", "sCAL");
+ size_t lengthw = 0, lengthh = 0;
+
+ png_debug1(1, "in %s storage function", "sCAL");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- info_ptr->scal_unit = (png_byte)unit;
- info_ptr->scal_pixel_width = width;
- info_ptr->scal_pixel_height = height;
+ /* Double check the unit (should never get here with an invalid
+ * unit unless this is an API call.)
+ */
+ if (unit != 1 && unit != 2)
+ png_error(png_ptr, "Invalid sCAL unit");
- info_ptr->valid |= PNG_INFO_sCAL;
-}
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-void PNGAPI
-png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr,
- int unit, png_charp swidth, png_charp sheight)
-{
- png_uint_32 length;
+ if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
+ swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
+ png_error(png_ptr, "Invalid sCAL width");
- png_debug1(1, "in %s storage function\n", "sCAL");
- if (png_ptr == NULL || info_ptr == NULL)
- return;
+ if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
+ sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
+ png_error(png_ptr, "Invalid sCAL height");
info_ptr->scal_unit = (png_byte)unit;
- length = png_strlen(swidth) + 1;
- png_debug1(3, "allocating unit for info (%d bytes)\n", length);
- info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length);
+ ++lengthw;
+
+ png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
+
+ info_ptr->scal_s_width = png_voidcast(png_charp,
+ png_malloc_warn(png_ptr, lengthw));
+
if (info_ptr->scal_s_width == NULL)
{
- png_warning(png_ptr,
- "Memory allocation failed while processing sCAL.");
- }
- png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length);
+ png_warning(png_ptr, "Memory allocation failed while processing sCAL");
+
+ return;
+ }
+
+ memcpy(info_ptr->scal_s_width, swidth, lengthw);
+
+ ++lengthh;
+
+ png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
+
+ info_ptr->scal_s_height = png_voidcast(png_charp,
+ png_malloc_warn(png_ptr, lengthh));
- length = png_strlen(sheight) + 1;
- png_debug1(3, "allocating unit for info (%d bytes)\n", length);
- info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length);
if (info_ptr->scal_s_height == NULL)
{
- png_free (png_ptr, info_ptr->scal_s_width);
- png_warning(png_ptr,
- "Memory allocation failed while processing sCAL.");
+ png_free(png_ptr, info_ptr->scal_s_width);
+ info_ptr->scal_s_width = NULL;
+
+ png_warning(png_ptr, "Memory allocation failed while processing sCAL");
+ return;
}
- png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length);
- info_ptr->valid |= PNG_INFO_sCAL;
-#ifdef PNG_FREE_ME_SUPPORTED
+ memcpy(info_ptr->scal_s_height, sheight, lengthh);
+
info_ptr->free_me |= PNG_FREE_SCAL;
-#endif
+ info_ptr->valid |= PNG_INFO_sCAL;
}
-#endif
-#endif
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
+ double width, double height)
+{
+ png_debug1(1, "in %s storage function", "sCAL");
+
+ /* Check the arguments. */
+ if (width <= 0)
+ png_warning(png_ptr, "Invalid sCAL width ignored");
+
+ else if (height <= 0)
+ png_warning(png_ptr, "Invalid sCAL height ignored");
+
+ else
+ {
+ /* Convert 'width' and 'height' to ASCII. */
+ char swidth[PNG_sCAL_MAX_DIGITS+1];
+ char sheight[PNG_sCAL_MAX_DIGITS+1];
+
+ png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
+ PNG_sCAL_PRECISION);
+ png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
+ PNG_sCAL_PRECISION);
+
+ png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
+ }
+}
+# endif
+
+# ifdef PNG_FIXED_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
+ png_fixed_point width, png_fixed_point height)
+{
+ png_debug1(1, "in %s storage function", "sCAL");
+
+ /* Check the arguments. */
+ if (width <= 0)
+ png_warning(png_ptr, "Invalid sCAL width ignored");
+
+ else if (height <= 0)
+ png_warning(png_ptr, "Invalid sCAL height ignored");
+
+ else
+ {
+ /* Convert 'width' and 'height' to ASCII. */
+ char swidth[PNG_sCAL_MAX_DIGITS+1];
+ char sheight[PNG_sCAL_MAX_DIGITS+1];
+
+ png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
+ png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
+
+ png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
+ }
+}
+# endif
#endif
-#if defined(PNG_pHYs_SUPPORTED)
+#ifdef PNG_pHYs_SUPPORTED
void PNGAPI
-png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
{
- png_debug1(1, "in %s storage function\n", "pHYs");
+ png_debug1(1, "in %s storage function", "pHYs");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
@@ -528,723 +558,1246 @@ png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
#endif
void PNGAPI
-png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
- png_colorp palette, int num_palette)
+png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
+ png_const_colorp palette, int num_palette)
{
- png_debug1(1, "in %s storage function\n", "PLTE");
+ png_uint_32 max_palette_length;
+
+ png_debug1(1, "in %s storage function", "PLTE");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
- {
- if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- png_error(png_ptr, "Invalid palette length");
- else
- {
- png_warning(png_ptr, "Invalid palette length");
- return;
- }
- }
+ max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+ (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
- /*
- * It may not actually be necessary to set png_ptr->palette here;
+ if (num_palette < 0 || num_palette > (int) max_palette_length)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Invalid palette length");
+
+ else
+ {
+ png_warning(png_ptr, "Invalid palette length");
+
+ return;
+ }
+ }
+
+ if ((num_palette > 0 && palette == NULL) ||
+ (num_palette == 0
+# ifdef PNG_MNG_FEATURES_SUPPORTED
+ && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
+# endif
+ ))
+ {
+ png_error(png_ptr, "Invalid palette");
+ }
+
+ /* It may not actually be necessary to set png_ptr->palette here;
* we do it for backward compatibility with the way the png_handle_tRNS
* function used to do the allocation.
+ *
+ * 1.6.0: the above statement appears to be incorrect; something has to set
+ * the palette inside png_struct on read.
*/
-#ifdef PNG_FREE_ME_SUPPORTED
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
-#endif
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
- of num_palette entries,
- in case of an invalid PNG file that has too-large sample values. */
- png_ptr->palette = (png_colorp)png_malloc(png_ptr,
- PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
- png_memset(png_ptr->palette, 0, PNG_MAX_PALETTE_LENGTH *
- png_sizeof(png_color));
- png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof (png_color));
+ * of num_palette entries, in case of an invalid PNG file or incorrect
+ * call to png_set_PLTE() with too-large sample values.
+ */
+ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+ PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+
+ if (num_palette > 0)
+ memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+ (sizeof (png_color)));
+
info_ptr->palette = png_ptr->palette;
info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
-
-#ifdef PNG_FREE_ME_SUPPORTED
info_ptr->free_me |= PNG_FREE_PLTE;
-#else
- png_ptr->flags |= PNG_FLAG_FREE_PLTE;
-#endif
-
info_ptr->valid |= PNG_INFO_PLTE;
}
-#if defined(PNG_sBIT_SUPPORTED)
+#ifdef PNG_sBIT_SUPPORTED
void PNGAPI
-png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
- png_color_8p sig_bit)
+png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_color_8p sig_bit)
{
- png_debug1(1, "in %s storage function\n", "sBIT");
- if (png_ptr == NULL || info_ptr == NULL)
+ png_debug1(1, "in %s storage function", "sBIT");
+
+ if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
return;
- png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof (png_color_8));
+ info_ptr->sig_bit = *sig_bit;
info_ptr->valid |= PNG_INFO_sBIT;
}
#endif
-#if defined(PNG_sRGB_SUPPORTED)
+#ifdef PNG_sRGB_SUPPORTED
void PNGAPI
-png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent)
+png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
{
- png_debug1(1, "in %s storage function\n", "sRGB");
+ png_debug1(1, "in %s storage function", "sRGB");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- info_ptr->srgb_intent = (png_byte)intent;
- info_ptr->valid |= PNG_INFO_sRGB;
+ (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
+ png_colorspace_sync_info(png_ptr, info_ptr);
}
void PNGAPI
-png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
- int intent)
+png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
+ int srgb_intent)
{
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float file_gamma;
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_fixed_point int_file_gamma;
-#endif
-#endif
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
- int_green_y, int_blue_x, int_blue_y;
-#endif
-#endif
- png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM");
+ png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- png_set_sRGB(png_ptr, info_ptr, intent);
+ 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;
+ }
-#if defined(PNG_gAMA_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- file_gamma = (float).45455;
- png_set_gAMA(png_ptr, info_ptr, file_gamma);
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
- int_file_gamma = 45455L;
- png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma);
-#endif
-#endif
-
-#if defined(PNG_cHRM_SUPPORTED)
-#ifdef PNG_FIXED_POINT_SUPPORTED
- int_white_x = 31270L;
- int_white_y = 32900L;
- int_red_x = 64000L;
- int_red_y = 33000L;
- int_green_x = 30000L;
- int_green_y = 60000L;
- int_blue_x = 15000L;
- int_blue_y = 6000L;
-
- png_set_cHRM_fixed(png_ptr, info_ptr,
- int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y,
- int_blue_x, int_blue_y);
-#endif
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- white_x = (float).3127;
- white_y = (float).3290;
- red_x = (float).64;
- red_y = (float).33;
- green_x = (float).30;
- green_y = (float).60;
- blue_x = (float).15;
- blue_y = (float).06;
-
- png_set_cHRM(png_ptr, info_ptr,
- white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
-#endif
-#endif
+ png_colorspace_sync_info(png_ptr, info_ptr);
}
-#endif
+#endif /* sRGB */
-#if defined(PNG_iCCP_SUPPORTED)
+#ifdef PNG_iCCP_SUPPORTED
void PNGAPI
-png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
- png_charp name, int compression_type,
- png_charp profile, png_uint_32 proflen)
+png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_charp name, int compression_type,
+ png_const_bytep profile, png_uint_32 proflen)
{
png_charp new_iccp_name;
- png_charp new_iccp_profile;
- png_uint_32 length;
+ png_bytep new_iccp_profile;
+ size_t length;
+
+ png_debug1(1, "in %s storage function", "iCCP");
- png_debug1(1, "in %s storage function\n", "iCCP");
if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
return;
- length = png_strlen(name)+1;
- new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length);
+ 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));
+
if (new_iccp_name == NULL)
{
- png_warning(png_ptr, "Insufficient memory to process iCCP chunk.");
+ png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
+
return;
}
- png_memcpy(new_iccp_name, name, length);
- new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen);
+
+ memcpy(new_iccp_name, name, length);
+ new_iccp_profile = png_voidcast(png_bytep,
+ png_malloc_warn(png_ptr, proflen));
+
if (new_iccp_profile == NULL)
{
- png_free (png_ptr, new_iccp_name);
- png_warning(png_ptr, "Insufficient memory to process iCCP profile.");
+ png_free(png_ptr, new_iccp_name);
+ png_benign_error(png_ptr,
+ "Insufficient memory to process iCCP profile");
+
return;
}
- png_memcpy(new_iccp_profile, profile, (png_size_t)proflen);
+
+ memcpy(new_iccp_profile, profile, proflen);
png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
info_ptr->iccp_proflen = proflen;
info_ptr->iccp_name = new_iccp_name;
info_ptr->iccp_profile = new_iccp_profile;
- /* Compression is always zero but is here so the API and info structure
- * does not have to change if we introduce multiple compression types */
- info_ptr->iccp_compression = (png_byte)compression_type;
-#ifdef PNG_FREE_ME_SUPPORTED
info_ptr->free_me |= PNG_FREE_ICCP;
-#endif
info_ptr->valid |= PNG_INFO_iCCP;
}
#endif
-#if defined(PNG_TEXT_SUPPORTED)
+#ifdef PNG_TEXT_SUPPORTED
void PNGAPI
-png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
- int num_text)
+png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_textp text_ptr, int num_text)
{
int ret;
- ret=png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
- if (ret)
- png_error(png_ptr, "Insufficient memory to store text");
+ ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
+
+ if (ret != 0)
+ png_error(png_ptr, "Insufficient memory to store text");
}
int /* PRIVATE */
-png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
- int num_text)
+png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_textp text_ptr, int num_text)
{
int i;
- png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
- "text" : (png_const_charp)png_ptr->chunk_name));
+ png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
+ png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
- if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
- return(0);
+ if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
+ return 0;
/* Make sure we have enough space in the "text" array in info_struct
- * to hold all of the incoming text_ptr objects.
+ * to hold all of the incoming text_ptr objects. This compare can't overflow
+ * because max_text >= num_text (anyway, subtract of two positive integers
+ * can't overflow in any case.)
*/
- if (info_ptr->num_text + num_text > info_ptr->max_text)
+ if (num_text > info_ptr->max_text - info_ptr->num_text)
{
- if (info_ptr->text != NULL)
- {
- png_textp old_text;
- int old_max;
+ int old_num_text = info_ptr->num_text;
+ int max_text;
+ png_textp new_text = NULL;
- old_max = info_ptr->max_text;
- info_ptr->max_text = info_ptr->num_text + num_text + 8;
- old_text = info_ptr->text;
- info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
- (png_uint_32)(info_ptr->max_text * png_sizeof (png_text)));
- if (info_ptr->text == NULL)
- {
- png_free(png_ptr, old_text);
- return(1);
- }
- png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
- png_sizeof(png_text)));
- png_free(png_ptr, old_text);
- }
- else
+ /* Calculate an appropriate max_text, checking for overflow. */
+ max_text = old_num_text;
+ if (num_text <= INT_MAX - max_text)
{
- info_ptr->max_text = num_text + 8;
- info_ptr->num_text = 0;
- info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
- (png_uint_32)(info_ptr->max_text * png_sizeof (png_text)));
- if (info_ptr->text == NULL)
- return(1);
-#ifdef PNG_FREE_ME_SUPPORTED
- info_ptr->free_me |= PNG_FREE_TEXT;
-#endif
+ max_text += num_text;
+
+ /* Round up to a multiple of 8 */
+ if (max_text < INT_MAX-8)
+ max_text = (max_text + 8) & ~0x7;
+
+ else
+ max_text = INT_MAX;
+
+ /* Now allocate a new array and copy the old members in; this does all
+ * the overflow checks.
+ */
+ new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
+ info_ptr->text, old_num_text, max_text-old_num_text,
+ sizeof *new_text));
}
- png_debug1(3, "allocated %d entries for info_ptr->text\n",
- info_ptr->max_text);
+
+ if (new_text == NULL)
+ {
+ png_chunk_report(png_ptr, "too many text chunks",
+ PNG_CHUNK_WRITE_ERROR);
+
+ return 1;
+ }
+
+ png_free(png_ptr, info_ptr->text);
+
+ info_ptr->text = new_text;
+ info_ptr->free_me |= PNG_FREE_TEXT;
+ info_ptr->max_text = max_text;
+ /* num_text is adjusted below as the entries are copied in */
+
+ png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
}
+
for (i = 0; i < num_text; i++)
{
- png_size_t text_length,key_len;
- png_size_t lang_len,lang_key_len;
+ size_t text_length, key_len;
+ size_t lang_len, lang_key_len;
png_textp textp = &(info_ptr->text[info_ptr->num_text]);
if (text_ptr[i].key == NULL)
continue;
- key_len = png_strlen(text_ptr[i].key);
+ if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
+ text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
+ {
+ png_chunk_report(png_ptr, "text compression mode is out of range",
+ PNG_CHUNK_WRITE_ERROR);
+ continue;
+ }
- if(text_ptr[i].compression <= 0)
+ key_len = strlen(text_ptr[i].key);
+
+ if (text_ptr[i].compression <= 0)
{
- lang_len = 0;
- lang_key_len = 0;
+ lang_len = 0;
+ lang_key_len = 0;
}
+
else
-#ifdef PNG_iTXt_SUPPORTED
+# ifdef PNG_iTXt_SUPPORTED
{
- /* set iTXt data */
- if (text_ptr[i].lang != NULL)
- lang_len = png_strlen(text_ptr[i].lang);
- else
- lang_len = 0;
- if (text_ptr[i].lang_key != NULL)
- lang_key_len = png_strlen(text_ptr[i].lang_key);
- else
- lang_key_len = 0;
+ /* Set iTXt data */
+
+ if (text_ptr[i].lang != NULL)
+ lang_len = strlen(text_ptr[i].lang);
+
+ else
+ lang_len = 0;
+
+ if (text_ptr[i].lang_key != NULL)
+ lang_key_len = strlen(text_ptr[i].lang_key);
+
+ else
+ lang_key_len = 0;
}
-#else
+# else /* iTXt */
{
- png_warning(png_ptr, "iTXt chunk not supported.");
- continue;
+ png_chunk_report(png_ptr, "iTXt chunk not supported",
+ PNG_CHUNK_WRITE_ERROR);
+ continue;
}
-#endif
+# endif
if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
{
text_length = 0;
-#ifdef PNG_iTXt_SUPPORTED
- if(text_ptr[i].compression > 0)
+# ifdef PNG_iTXt_SUPPORTED
+ if (text_ptr[i].compression > 0)
textp->compression = PNG_ITXT_COMPRESSION_NONE;
+
else
-#endif
+# endif
textp->compression = PNG_TEXT_COMPRESSION_NONE;
}
+
else
{
- text_length = png_strlen(text_ptr[i].text);
+ text_length = strlen(text_ptr[i].text);
textp->compression = text_ptr[i].compression;
}
- textp->key = (png_charp)png_malloc_warn(png_ptr,
- (png_uint_32)(key_len + text_length + lang_len + lang_key_len + 4));
- if (textp->key == NULL)
- return(1);
- png_debug2(2, "Allocated %lu bytes at %x in png_set_text\n",
- (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4),
- (int)textp->key);
+ textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,
+ key_len + text_length + lang_len + lang_key_len + 4));
+
+ if (textp->key == NULL)
+ {
+ png_chunk_report(png_ptr, "text chunk: out of memory",
+ PNG_CHUNK_WRITE_ERROR);
+
+ return 1;
+ }
+
+ png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
+ (unsigned long)(png_uint_32)
+ (key_len + lang_len + lang_key_len + text_length + 4),
+ textp->key);
+
+ memcpy(textp->key, text_ptr[i].key, key_len);
+ *(textp->key + key_len) = '\0';
- png_memcpy(textp->key, text_ptr[i].key,
- (png_size_t)(key_len));
- *(textp->key+key_len) = '\0';
-#ifdef PNG_iTXt_SUPPORTED
if (text_ptr[i].compression > 0)
{
- textp->lang=textp->key + key_len + 1;
- png_memcpy(textp->lang, text_ptr[i].lang, lang_len);
- *(textp->lang+lang_len) = '\0';
- textp->lang_key=textp->lang + lang_len + 1;
- png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
- *(textp->lang_key+lang_key_len) = '\0';
- textp->text=textp->lang_key + lang_key_len + 1;
+ textp->lang = textp->key + key_len + 1;
+ memcpy(textp->lang, text_ptr[i].lang, lang_len);
+ *(textp->lang + lang_len) = '\0';
+ textp->lang_key = textp->lang + lang_len + 1;
+ memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
+ *(textp->lang_key + lang_key_len) = '\0';
+ textp->text = textp->lang_key + lang_key_len + 1;
}
+
else
-#endif
{
-#ifdef PNG_iTXt_SUPPORTED
textp->lang=NULL;
textp->lang_key=NULL;
-#endif
- textp->text=textp->key + key_len + 1;
+ textp->text = textp->key + key_len + 1;
}
- if(text_length)
- png_memcpy(textp->text, text_ptr[i].text,
- (png_size_t)(text_length));
- *(textp->text+text_length) = '\0';
-#ifdef PNG_iTXt_SUPPORTED
- if(textp->compression > 0)
+ if (text_length != 0)
+ memcpy(textp->text, text_ptr[i].text, text_length);
+
+ *(textp->text + text_length) = '\0';
+
+# ifdef PNG_iTXt_SUPPORTED
+ if (textp->compression > 0)
{
textp->text_length = 0;
textp->itxt_length = text_length;
}
+
else
-#endif
+# endif
{
textp->text_length = text_length;
-#ifdef PNG_iTXt_SUPPORTED
textp->itxt_length = 0;
-#endif
}
+
info_ptr->num_text++;
- png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+ png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
}
- return(0);
+
+ return 0;
}
#endif
-#if defined(PNG_tIME_SUPPORTED)
+#ifdef PNG_tIME_SUPPORTED
void PNGAPI
-png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_const_timep mod_time)
{
- png_debug1(1, "in %s storage function\n", "tIME");
- if (png_ptr == NULL || info_ptr == NULL ||
- (png_ptr->mode & PNG_WROTE_tIME))
+ png_debug1(1, "in %s storage function", "tIME");
+
+ if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
+ (png_ptr->mode & PNG_WROTE_tIME) != 0)
return;
- png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof (png_time));
+ if (mod_time->month == 0 || mod_time->month > 12 ||
+ mod_time->day == 0 || mod_time->day > 31 ||
+ mod_time->hour > 23 || mod_time->minute > 59 ||
+ mod_time->second > 60)
+ {
+ png_warning(png_ptr, "Ignoring invalid time value");
+
+ return;
+ }
+
+ info_ptr->mod_time = *mod_time;
info_ptr->valid |= PNG_INFO_tIME;
}
#endif
-#if defined(PNG_tRNS_SUPPORTED)
+#ifdef PNG_tRNS_SUPPORTED
void PNGAPI
-png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
- png_bytep trans, int num_trans, png_color_16p trans_values)
+png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
+ png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
{
- png_debug1(1, "in %s storage function\n", "tRNS");
+ png_debug1(1, "in %s storage function", "tRNS");
+
if (png_ptr == NULL || info_ptr == NULL)
+
return;
- if (trans != NULL)
+ if (trans_alpha != NULL)
{
- /*
- * It may not actually be necessary to set png_ptr->trans here;
+ /* It may not actually be necessary to set png_ptr->trans_alpha here;
* we do it for backward compatibility with the way the png_handle_tRNS
* function used to do the allocation.
+ *
+ * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
+ * relies on png_set_tRNS storing the information in png_struct
+ * (otherwise it won't be there for the code in pngrtran.c).
*/
-#ifdef PNG_FREE_ME_SUPPORTED
+
png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
-#endif
- /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
- png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)PNG_MAX_PALETTE_LENGTH);
- if (num_trans <= PNG_MAX_PALETTE_LENGTH)
- png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans);
-#ifdef PNG_FREE_ME_SUPPORTED
- info_ptr->free_me |= PNG_FREE_TRNS;
-#else
- png_ptr->flags |= PNG_FLAG_FREE_TRNS;
-#endif
+
+ if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+ {
+ /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
+ info_ptr->trans_alpha = png_voidcast(png_bytep,
+ png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+ memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+
+ info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
+ }
+ png_ptr->trans_alpha = info_ptr->trans_alpha;
}
- if (trans_values != NULL)
+ if (trans_color != NULL)
{
- png_memcpy(&(info_ptr->trans_values), trans_values,
- png_sizeof(png_color_16));
+#ifdef PNG_WARNINGS_SUPPORTED
+ if (info_ptr->bit_depth < 16)
+ {
+ int sample_max = (1 << info_ptr->bit_depth) - 1;
+
+ if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
+ trans_color->gray > sample_max) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+ (trans_color->red > sample_max ||
+ trans_color->green > sample_max ||
+ trans_color->blue > sample_max)))
+ png_warning(png_ptr,
+ "tRNS chunk has out-of-range samples for bit_depth");
+ }
+#endif
+
+ info_ptr->trans_color = *trans_color;
+
if (num_trans == 0)
- num_trans = 1;
+ num_trans = 1;
}
+
info_ptr->num_trans = (png_uint_16)num_trans;
- info_ptr->valid |= PNG_INFO_tRNS;
+
+ if (num_trans != 0)
+ {
+ info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
+ }
}
#endif
-#if defined(PNG_sPLT_SUPPORTED)
+#ifdef PNG_sPLT_SUPPORTED
void PNGAPI
-png_set_sPLT(png_structp png_ptr,
- png_infop info_ptr, png_sPLT_tp entries, int nentries)
+png_set_sPLT(png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
+/*
+ * entries - array of png_sPLT_t structures
+ * to be added to the list of palettes
+ * in the info structure.
+ *
+ * nentries - number of palette structures to be
+ * added.
+ */
{
- png_sPLT_tp np;
- int i;
+ png_sPLT_tp np;
- if (png_ptr == NULL || info_ptr == NULL)
- return;
+ png_debug1(1, "in %s storage function", "sPLT");
- np = (png_sPLT_tp)png_malloc_warn(png_ptr,
- (info_ptr->splt_palettes_num + nentries) * png_sizeof(png_sPLT_t));
- if (np == NULL)
- {
- png_warning(png_ptr, "No memory for sPLT palettes.");
+ if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
return;
- }
- png_memcpy(np, info_ptr->splt_palettes,
- info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t));
- png_free(png_ptr, info_ptr->splt_palettes);
- info_ptr->splt_palettes=NULL;
+ /* Use the internal realloc function, which checks for all the possible
+ * overflows. Notice that the parameters are (int) and (size_t)
+ */
+ np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
+ info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
+ sizeof *np));
- for (i = 0; i < nentries; i++)
- {
- png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
- png_sPLT_tp from = entries + i;
- png_uint_32 length;
-
- length = png_strlen(from->name) + 1;
- to->name = (png_charp)png_malloc_warn(png_ptr, length);
- if (to->name == NULL)
- {
- png_warning(png_ptr,
- "Out of memory while processing sPLT chunk");
- }
- png_memcpy(to->name, from->name, length);
- to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
- from->nentries * png_sizeof(png_sPLT_entry));
- if (to->entries == NULL)
- {
- png_warning(png_ptr,
- "Out of memory while processing sPLT chunk");
- png_free(png_ptr,to->name);
- to->name = NULL;
- }
- png_memcpy(to->entries, from->entries,
- from->nentries * png_sizeof(png_sPLT_entry));
- to->nentries = from->nentries;
- to->depth = from->depth;
- }
-
- info_ptr->splt_palettes = np;
- info_ptr->splt_palettes_num += nentries;
- info_ptr->valid |= PNG_INFO_sPLT;
-#ifdef PNG_FREE_ME_SUPPORTED
- info_ptr->free_me |= PNG_FREE_SPLT;
-#endif
-}
-#endif /* PNG_sPLT_SUPPORTED */
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-void PNGAPI
-png_set_unknown_chunks(png_structp png_ptr,
- png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)
-{
- png_unknown_chunkp np;
- int i;
-
- if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
- return;
-
- np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
- (info_ptr->unknown_chunks_num + num_unknowns) *
- png_sizeof(png_unknown_chunk));
- if (np == NULL)
- {
- png_warning(png_ptr,
- "Out of memory while processing unknown chunk.");
- return;
- }
-
- png_memcpy(np, info_ptr->unknown_chunks,
- info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk));
- png_free(png_ptr, info_ptr->unknown_chunks);
- info_ptr->unknown_chunks=NULL;
-
- for (i = 0; i < num_unknowns; i++)
- {
- png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i;
- png_unknown_chunkp from = unknowns + i;
-
- png_memcpy((png_charp)to->name,
- (png_charp)from->name,
- png_sizeof(from->name));
- to->name[png_sizeof(to->name)-1] = '\0';
-
- to->data = (png_bytep)png_malloc_warn(png_ptr, from->size);
- if (to->data == NULL)
- {
- png_warning(png_ptr,
- "Out of memory while processing unknown chunk.");
- }
- else
- {
- png_memcpy(to->data, from->data, from->size);
- to->size = from->size;
-
- /* note our location in the read or write sequence */
- to->location = (png_byte)(png_ptr->mode & 0xff);
- }
- }
-
- info_ptr->unknown_chunks = np;
- info_ptr->unknown_chunks_num += num_unknowns;
-#ifdef PNG_FREE_ME_SUPPORTED
- info_ptr->free_me |= PNG_FREE_UNKN;
-#endif
-}
-void PNGAPI
-png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr,
- int chunk, int location)
-{
- if(png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk <
- (int)info_ptr->unknown_chunks_num)
- info_ptr->unknown_chunks[chunk].location = (png_byte)location;
-}
-#endif
-
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
- defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
-void PNGAPI
-png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted)
-{
- /* This function is deprecated in favor of png_permit_mng_features()
- and will be removed from libpng-1.3.0 */
- png_debug(1, "in png_permit_empty_plte, DEPRECATED.\n");
- if (png_ptr == NULL)
+ if (np == NULL)
+ {
+ /* Out of memory or too many chunks */
+ png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
return;
- png_ptr->mng_features_permitted = (png_byte)
- ((png_ptr->mng_features_permitted & (~PNG_FLAG_MNG_EMPTY_PLTE)) |
- ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE)));
-}
-#endif
-#endif
+ }
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_free(png_ptr, info_ptr->splt_palettes);
+
+ info_ptr->splt_palettes = np;
+ info_ptr->free_me |= PNG_FREE_SPLT;
+
+ np += info_ptr->splt_palettes_num;
+
+ do
+ {
+ size_t length;
+
+ /* Skip invalid input entries */
+ if (entries->name == NULL || entries->entries == NULL)
+ {
+ /* png_handle_sPLT doesn't do this, so this is an app error */
+ png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
+ /* Just skip the invalid entry */
+ continue;
+ }
+
+ np->depth = entries->depth;
+
+ /* In the event of out-of-memory just return - there's no point keeping
+ * on trying to add sPLT chunks.
+ */
+ length = strlen(entries->name) + 1;
+ np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
+
+ if (np->name == NULL)
+ break;
+
+ memcpy(np->name, entries->name, length);
+
+ /* IMPORTANT: we have memory now that won't get freed if something else
+ * goes wrong; this code must free it. png_malloc_array produces no
+ * warnings; use a png_chunk_report (below) if there is an error.
+ */
+ np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
+ entries->nentries, sizeof (png_sPLT_entry)));
+
+ if (np->entries == NULL)
+ {
+ png_free(png_ptr, np->name);
+ np->name = NULL;
+ break;
+ }
+
+ np->nentries = entries->nentries;
+ /* This multiply can't overflow because png_malloc_array has already
+ * checked it when doing the allocation.
+ */
+ memcpy(np->entries, entries->entries,
+ (unsigned int)entries->nentries * sizeof (png_sPLT_entry));
+
+ /* Note that 'continue' skips the advance of the out pointer and out
+ * count, so an invalid entry is not added.
+ */
+ info_ptr->valid |= PNG_INFO_sPLT;
+ ++(info_ptr->splt_palettes_num);
+ ++np;
+ ++entries;
+ }
+ while (--nentries);
+
+ if (nentries > 0)
+ png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
+}
+#endif /* sPLT */
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+static png_byte
+check_location(png_const_structrp png_ptr, int location)
+{
+ location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
+
+ /* New in 1.6.0; copy the location and check it. This is an API
+ * change; previously the app had to use the
+ * png_set_unknown_chunk_location API below for each chunk.
+ */
+ if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
+ {
+ /* Write struct, so unknown chunks come from the app */
+ png_app_warning(png_ptr,
+ "png_set_unknown_chunks now expects a valid location");
+ /* Use the old behavior */
+ location = (png_byte)(png_ptr->mode &
+ (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
+ }
+
+ /* This need not be an internal error - if the app calls
+ * png_set_unknown_chunks on a read pointer it must get the location right.
+ */
+ if (location == 0)
+ png_error(png_ptr, "invalid location in png_set_unknown_chunks");
+
+ /* Now reduce the location to the top-most set bit by removing each least
+ * significant bit in turn.
+ */
+ while (location != (location & -location))
+ location &= ~(location & -location);
+
+ /* The cast is safe because 'location' is a bit mask and only the low four
+ * bits are significant.
+ */
+ return (png_byte)location;
+}
+
+void PNGAPI
+png_set_unknown_chunks(png_const_structrp png_ptr,
+ png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
+{
+ png_unknown_chunkp np;
+
+ if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
+ unknowns == NULL)
+ return;
+
+ /* Check for the failure cases where support has been disabled at compile
+ * time. This code is hardly ever compiled - it's here because
+ * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
+ * code) but may be meaningless if the read or write handling of unknown
+ * chunks is not compiled in.
+ */
+# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
+ defined(PNG_READ_SUPPORTED)
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
+ {
+ png_app_error(png_ptr, "no unknown chunk support on read");
+
+ return;
+ }
+# endif
+# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
+ defined(PNG_WRITE_SUPPORTED)
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
+ {
+ png_app_error(png_ptr, "no unknown chunk support on write");
+
+ return;
+ }
+# endif
+
+ /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
+ * unknown critical chunks could be lost with just a warning resulting in
+ * undefined behavior. Now png_chunk_report is used to provide behavior
+ * appropriate to read or write.
+ */
+ np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
+ info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
+ sizeof *np));
+
+ if (np == NULL)
+ {
+ png_chunk_report(png_ptr, "too many unknown chunks",
+ PNG_CHUNK_WRITE_ERROR);
+ return;
+ }
+
+ png_free(png_ptr, info_ptr->unknown_chunks);
+
+ info_ptr->unknown_chunks = np; /* safe because it is initialized */
+ info_ptr->free_me |= PNG_FREE_UNKN;
+
+ np += info_ptr->unknown_chunks_num;
+
+ /* Increment unknown_chunks_num each time round the loop to protect the
+ * just-allocated chunk data.
+ */
+ for (; num_unknowns > 0; --num_unknowns, ++unknowns)
+ {
+ memcpy(np->name, unknowns->name, (sizeof np->name));
+ np->name[(sizeof np->name)-1] = '\0';
+ np->location = check_location(png_ptr, unknowns->location);
+
+ if (unknowns->size == 0)
+ {
+ np->data = NULL;
+ np->size = 0;
+ }
+
+ else
+ {
+ np->data = png_voidcast(png_bytep,
+ png_malloc_base(png_ptr, unknowns->size));
+
+ if (np->data == NULL)
+ {
+ png_chunk_report(png_ptr, "unknown chunk: out of memory",
+ PNG_CHUNK_WRITE_ERROR);
+ /* But just skip storing the unknown chunk */
+ continue;
+ }
+
+ memcpy(np->data, unknowns->data, unknowns->size);
+ np->size = unknowns->size;
+ }
+
+ /* These increments are skipped on out-of-memory for the data - the
+ * unknown chunk entry gets overwritten if the png_chunk_report returns.
+ * This is correct in the read case (the chunk is just dropped.)
+ */
+ ++np;
+ ++(info_ptr->unknown_chunks_num);
+ }
+}
+
+void PNGAPI
+png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
+ int chunk, int location)
+{
+ /* This API is pretty pointless in 1.6.0 because the location can be set
+ * before the call to png_set_unknown_chunks.
+ *
+ * TODO: add a png_app_warning in 1.7
+ */
+ if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
+ chunk < info_ptr->unknown_chunks_num)
+ {
+ if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
+ {
+ png_app_error(png_ptr, "invalid unknown chunk location");
+ /* Fake out the pre 1.6.0 behavior: */
+ if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
+ location = PNG_AFTER_IDAT;
+
+ else
+ location = PNG_HAVE_IHDR; /* also undocumented */
+ }
+
+ info_ptr->unknown_chunks[chunk].location =
+ check_location(png_ptr, location);
+ }
+}
+#endif /* STORE_UNKNOWN_CHUNKS */
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
png_uint_32 PNGAPI
-png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features)
+png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features)
{
- png_debug(1, "in png_permit_mng_features\n");
+ png_debug(1, "in png_permit_mng_features");
+
if (png_ptr == NULL)
- return (png_uint_32)0;
- png_ptr->mng_features_permitted =
- (png_byte)(mng_features & PNG_ALL_MNG_FEATURES);
- return (png_uint_32)png_ptr->mng_features_permitted;
+ return 0;
+
+ png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
+
+ return png_ptr->mng_features_permitted;
}
#endif
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-void PNGAPI
-png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep
- chunk_list, int num_chunks)
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+static unsigned int
+add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
{
- png_bytep new_list, p;
- int i, old_num_chunks;
- if (png_ptr == NULL)
- return;
- if (num_chunks == 0)
- {
- if(keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE)
- png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
- else
- png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
+ unsigned int i;
- if(keep == PNG_HANDLE_CHUNK_ALWAYS)
- png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS;
- else
- png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS;
+ /* Utility function: update the 'keep' state of a chunk if it is already in
+ * the list, otherwise add it to the list.
+ */
+ for (i=0; i= PNG_HANDLE_CHUNK_LAST)
+ {
+ png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
+
return;
- old_num_chunks=png_ptr->num_chunk_list;
- new_list=(png_bytep)png_malloc(png_ptr,
- (png_uint_32)(5*(num_chunks+old_num_chunks)));
- if(png_ptr->chunk_list != NULL)
- {
- png_memcpy(new_list, png_ptr->chunk_list,
- (png_size_t)(5*old_num_chunks));
- png_free(png_ptr, png_ptr->chunk_list);
- png_ptr->chunk_list=NULL;
- }
- png_memcpy(new_list+5*old_num_chunks, chunk_list,
- (png_size_t)(5*num_chunks));
- for (p=new_list+5*old_num_chunks+4, i=0; inum_chunk_list=old_num_chunks+num_chunks;
- png_ptr->chunk_list=new_list;
-#ifdef PNG_FREE_ME_SUPPORTED
- png_ptr->free_me |= PNG_FREE_LIST;
-#endif
+ }
+
+ if (num_chunks_in <= 0)
+ {
+ png_ptr->unknown_default = keep;
+
+ /* '0' means just set the flags, so stop here */
+ if (num_chunks_in == 0)
+ return;
+ }
+
+ if (num_chunks_in < 0)
+ {
+ /* Ignore all unknown chunks and all chunks recognized by
+ * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
+ */
+ static const png_byte chunks_to_ignore[] = {
+ 98, 75, 71, 68, '\0', /* bKGD */
+ 99, 72, 82, 77, '\0', /* cHRM */
+ 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 */
+ 111, 70, 70, 115, '\0', /* oFFs */
+ 112, 67, 65, 76, '\0', /* pCAL */
+ 112, 72, 89, 115, '\0', /* pHYs */
+ 115, 66, 73, 84, '\0', /* sBIT */
+ 115, 67, 65, 76, '\0', /* sCAL */
+ 115, 80, 76, 84, '\0', /* sPLT */
+ 115, 84, 69, 82, '\0', /* sTER */
+ 115, 82, 71, 66, '\0', /* sRGB */
+ 116, 69, 88, 116, '\0', /* tEXt */
+ 116, 73, 77, 69, '\0', /* tIME */
+ 122, 84, 88, 116, '\0' /* zTXt */
+ };
+
+ chunk_list = chunks_to_ignore;
+ num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;
+ }
+
+ else /* num_chunks_in > 0 */
+ {
+ if (chunk_list == NULL)
+ {
+ /* Prior to 1.6.0 this was silently ignored, now it is an app_error
+ * which can be switched off.
+ */
+ png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
+
+ return;
+ }
+
+ num_chunks = (unsigned int)num_chunks_in;
+ }
+
+ old_num_chunks = png_ptr->num_chunk_list;
+ if (png_ptr->chunk_list == NULL)
+ old_num_chunks = 0;
+
+ /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
+ */
+ if (num_chunks + old_num_chunks > UINT_MAX/5)
+ {
+ png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
+
+ return;
+ }
+
+ /* If these chunks are being reset to the default then no more memory is
+ * required because add_one_chunk above doesn't extend the list if the 'keep'
+ * parameter is the default.
+ */
+ if (keep != 0)
+ {
+ new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
+ 5 * (num_chunks + old_num_chunks)));
+
+ if (old_num_chunks > 0)
+ memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
+ }
+
+ else if (old_num_chunks > 0)
+ new_list = png_ptr->chunk_list;
+
+ else
+ new_list = NULL;
+
+ /* Add the new chunks together with each one's handling code. If the chunk
+ * already exists the code is updated, otherwise the chunk is added to the
+ * end. (In libpng 1.6.0 order no longer matters because this code enforces
+ * the earlier convention that the last setting is the one that is used.)
+ */
+ if (new_list != NULL)
+ {
+ png_const_bytep inlist;
+ png_bytep outlist;
+ unsigned int i;
+
+ for (i=0; ichunk_list != new_list)
+ png_free(png_ptr, new_list);
+
+ new_list = NULL;
+ }
+ }
+
+ else
+ num_chunks = 0;
+
+ png_ptr->num_chunk_list = num_chunks;
+
+ if (png_ptr->chunk_list != new_list)
+ {
+ if (png_ptr->chunk_list != NULL)
+ png_free(png_ptr, png_ptr->chunk_list);
+
+ png_ptr->chunk_list = new_list;
+ }
}
#endif
-#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
void PNGAPI
-png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr,
- png_user_chunk_ptr read_user_chunk_fn)
+png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
+ png_user_chunk_ptr read_user_chunk_fn)
{
- png_debug(1, "in png_set_read_user_chunk_fn\n");
+ png_debug(1, "in png_set_read_user_chunk_fn");
+
if (png_ptr == NULL)
return;
+
png_ptr->read_user_chunk_fn = read_user_chunk_fn;
png_ptr->user_chunk_ptr = user_chunk_ptr;
}
#endif
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
+#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
-png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
+png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_bytepp row_pointers)
{
- png_debug1(1, "in %s storage function\n", "rows");
+ png_debug(1, "in png_set_rows");
if (png_ptr == NULL || info_ptr == NULL)
return;
- if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
+ if (info_ptr->row_pointers != NULL &&
+ (info_ptr->row_pointers != row_pointers))
png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
+
info_ptr->row_pointers = row_pointers;
- if(row_pointers)
+
+ if (row_pointers != NULL)
info_ptr->valid |= PNG_INFO_IDAT;
}
#endif
-#ifdef PNG_WRITE_SUPPORTED
void PNGAPI
-png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size)
+png_set_compression_buffer_size(png_structrp png_ptr, size_t size)
{
- if (png_ptr == NULL)
- return;
- if(png_ptr->zbuf)
- png_free(png_ptr, png_ptr->zbuf);
- png_ptr->zbuf_size = (png_size_t)size;
- png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_debug(1, "in png_set_compression_buffer_size");
+
+ if (png_ptr == NULL)
+ return;
+
+ if (size == 0 || size > PNG_UINT_31_MAX)
+ png_error(png_ptr, "invalid compression buffer size");
+
+# ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
+ {
+ png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
+ return;
+ }
+# endif
+
+# ifdef PNG_WRITE_SUPPORTED
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
+ {
+ if (png_ptr->zowner != 0)
+ {
+ png_warning(png_ptr,
+ "Compression buffer size cannot be changed because it is in use");
+
+ return;
+ }
+
+#ifndef __COVERITY__
+ /* Some compilers complain that this is always false. However, it
+ * can be true when integer overflow happens.
+ */
+ if (size > ZLIB_IO_MAX)
+ {
+ png_warning(png_ptr,
+ "Compression buffer size limited to system maximum");
+ size = ZLIB_IO_MAX; /* must fit */
+ }
+#endif
+
+ if (size < 6)
+ {
+ /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
+ * if this is permitted.
+ */
+ png_warning(png_ptr,
+ "Compression buffer size cannot be reduced below 6");
+
+ return;
+ }
+
+ if (png_ptr->zbuffer_size != size)
+ {
+ png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
+ png_ptr->zbuffer_size = (uInt)size;
+ }
+ }
+# endif
+}
+
+void PNGAPI
+png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ info_ptr->valid &= (unsigned int)(~mask);
+}
+
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+/* This function was added to libpng 1.2.6 */
+void PNGAPI
+png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
+ png_uint_32 user_height_max)
+{
+ png_debug(1, "in png_set_user_limits");
+
+ /* Images with dimensions larger than these limits will be
+ * rejected by png_set_IHDR(). To accept any PNG datastream
+ * regardless of dimensions, set both limits to 0x7fffffff.
+ */
+ if (png_ptr == NULL)
+ return;
+
+ png_ptr->user_width_max = user_width_max;
+ png_ptr->user_height_max = user_height_max;
+}
+
+/* This function was added to libpng 1.4.0 */
+void PNGAPI
+png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
+{
+ png_debug(1, "in png_set_chunk_cache_max");
+
+ if (png_ptr != NULL)
+ png_ptr->user_chunk_cache_max = user_chunk_cache_max;
+}
+
+/* This function was added to libpng 1.4.1 */
+void PNGAPI
+png_set_chunk_malloc_max(png_structrp png_ptr,
+ png_alloc_size_t user_chunk_malloc_max)
+{
+ png_debug(1, "in png_set_chunk_malloc_max");
+
+ if (png_ptr != NULL)
+ png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
+}
+#endif /* ?SET_USER_LIMITS */
+
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+void PNGAPI
+png_set_benign_errors(png_structrp png_ptr, int allowed)
+{
+ png_debug(1, "in png_set_benign_errors");
+
+ /* If allowed is 1, png_benign_error() is treated as a warning.
+ *
+ * If allowed is 0, png_benign_error() is treated as an error (which
+ * is the default behavior if png_set_benign_errors() is not called).
+ */
+
+ if (allowed != 0)
+ png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
+ PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
+
+ else
+ png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
+ PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
+}
+#endif /* BENIGN_ERRORS */
+
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Whether to report invalid palette index; added at libng-1.5.10.
+ * It is possible for an indexed (color-type==3) PNG file to contain
+ * pixels with invalid (out-of-range) indexes if the PLTE chunk has
+ * fewer entries than the image's bit-depth would allow. We recover
+ * from this gracefully by filling any incomplete palette with zeros
+ * (opaque black). By default, when this occurs libpng will issue
+ * a benign error. This API can be used to override that behavior.
+ */
+void PNGAPI
+png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
+{
+ png_debug(1, "in png_set_check_for_invalid_index");
+
+ if (allowed > 0)
+ png_ptr->num_palette_max = 0;
+
+ else
+ png_ptr->num_palette_max = -1;
}
#endif
-void PNGAPI
-png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask)
+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \
+ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
+ * trailing '\0'). If this routine returns 0 then there was no keyword, or a
+ * valid one could not be generated, and the caller must png_error.
+ */
+png_uint_32 /* PRIVATE */
+png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
{
- if (png_ptr && info_ptr)
- info_ptr->valid &= ~mask;
+#ifdef PNG_WARNINGS_SUPPORTED
+ png_const_charp orig_key = key;
+#endif
+ png_uint_32 key_len = 0;
+ int bad_character = 0;
+ int space = 1;
+
+ png_debug(1, "in png_check_keyword");
+
+ if (key == NULL)
+ {
+ *new_key = 0;
+ return 0;
+ }
+
+ while (*key && key_len < 79)
+ {
+ png_byte ch = (png_byte)*key++;
+
+ if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
+ {
+ *new_key++ = ch; ++key_len; space = 0;
+ }
+
+ else if (space == 0)
+ {
+ /* A space or an invalid character when one wasn't seen immediately
+ * before; output just a space.
+ */
+ *new_key++ = 32; ++key_len; space = 1;
+
+ /* If the character was not a space then it is invalid. */
+ if (ch != 32)
+ bad_character = ch;
+ }
+
+ else if (bad_character == 0)
+ bad_character = ch; /* just skip it, record the first error */
+ }
+
+ if (key_len > 0 && space != 0) /* trailing space */
+ {
+ --key_len; --new_key;
+ if (bad_character == 0)
+ bad_character = 32;
+ }
+
+ /* Terminate the keyword */
+ *new_key = 0;
+
+ if (key_len == 0)
+ return 0;
+
+#ifdef PNG_WARNINGS_SUPPORTED
+ /* Try to only output one warning per keyword: */
+ if (*key != 0) /* keyword too long */
+ png_warning(png_ptr, "keyword truncated");
+
+ else if (bad_character != 0)
+ {
+ PNG_WARNING_PARAMETERS(p)
+
+ png_warning_parameter(p, 1, orig_key);
+ png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
+
+ png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
+ }
+#else /* !WARNINGS */
+ PNG_UNUSED(png_ptr)
+#endif /* !WARNINGS */
+
+ return key_len;
}
-
-
-#ifndef PNG_1_0_X
-#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
-/* function was added to libpng 1.2.0 and should always exist by default */
-void PNGAPI
-png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags)
-{
-/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */
- if (png_ptr != NULL)
- png_ptr->asm_flags = 0;
-}
-
-/* this function was added to libpng 1.2.0 */
-void PNGAPI
-png_set_mmx_thresholds (png_structp png_ptr,
- png_byte mmx_bitdepth_threshold,
- png_uint_32 mmx_rowbytes_threshold)
-{
-/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */
- if (png_ptr == NULL)
- return;
-}
-#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
-
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
-/* this function was added to libpng 1.2.6 */
-void PNGAPI
-png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max,
- png_uint_32 user_height_max)
-{
- /* Images with dimensions larger than these limits will be
- * rejected by png_set_IHDR(). To accept any PNG datastream
- * regardless of dimensions, set both limits to 0x7ffffffL.
- */
- if(png_ptr == NULL) return;
- png_ptr->user_width_max = user_width_max;
- png_ptr->user_height_max = user_height_max;
-}
-#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
-
-#endif /* ?PNG_1_0_X */
-#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+#endif /* TEXT || pCAL || iCCP || sPLT */
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngtest.c b/PDF/src/pngtest.c
index 7abd8a2c5..45ef66a70 100644
--- a/PDF/src/pngtest.c
+++ b/PDF/src/pngtest.c
@@ -1,11 +1,14 @@
-/* pngtest.c - a simple test program to test libpng
+/* pngtest.c - a test program for libpng
*
- * Last changed in libpng 1.2.23 - [November 6, 2007]
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* This program reads in a PNG image, writes it out again, and then
* compares the two files. If the files are identical, this shows that
@@ -28,51 +31,104 @@
* of files at once by typing "pngtest -m file1.png file2.png ..."
*/
+#define _POSIX_SOURCE 1
+
+#include
+#include
+#include
+
+#ifdef PNG_ZLIB_HEADER
+# include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */
+#else
+# include
+#endif
+
#include "png.h"
-#if defined(_WIN32_WCE)
-# if _WIN32_WCE < 211
- __error__ (f|w)printf functions are not supported on old WindowsCE.;
-# endif
-# include
-# include
-# define READFILE(file, data, length, check) \
- if (ReadFile(file, data, length, &check,NULL)) check = 0
-# define WRITEFILE(file, data, length, check)) \
- if (WriteFile(file, data, length, &check, NULL)) check = 0
-# define FCLOSE(file) CloseHandle(file)
+/* Generate a compiler error if there is an old png.h in the search path. */
+typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43;
+
+/* Ensure that all version numbers in png.h are consistent with one another. */
+#if (PNG_LIBPNG_VER != PNG_LIBPNG_VER_MAJOR * 10000 + \
+ PNG_LIBPNG_VER_MINOR * 100 + \
+ PNG_LIBPNG_VER_RELEASE) || \
+ (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_MAJOR * 10 + \
+ PNG_LIBPNG_VER_MINOR) || \
+ (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_SONUM) || \
+ (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_DLLNUM)
+# error "Inconsistent version numbers in png.h"
+#endif
+
+/* In version 1.6.1, we added support for the configure test harness, which
+ * uses 77 to indicate a skipped test. On the other hand, in cmake build tests,
+ * we still need to succeed on a skipped test, so:
+ */
+#if defined(HAVE_CONFIG_H)
+# define SKIP 77
#else
-# include
-# include
-# define READFILE(file, data, length, check) \
- check=(png_size_t)fread(data,(png_size_t)1,length,file)
-# define WRITEFILE(file, data, length, check) \
- check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
-# define FCLOSE(file) fclose(file)
+# define SKIP 0
#endif
-#if defined(PNG_NO_STDIO)
-# if defined(_WIN32_WCE)
- typedef HANDLE png_FILE_p;
-# else
- typedef FILE * png_FILE_p;
-# endif
+/* Known chunks that exist in pngtest.png must be supported, or pngtest will
+ * fail simply as a result of re-ordering them. This may be fixed in the next
+ * generation of libpng.
+ *
+ * pngtest allocates a single row buffer for each row and overwrites it,
+ * therefore if the write side doesn't support the writing of interlaced images
+ * nothing can be done for an interlaced image (and the code below will fail
+ * horribly trying to write extra data after writing garbage).
+ */
+#if defined PNG_READ_SUPPORTED && /* else nothing can be done */ \
+ defined PNG_READ_bKGD_SUPPORTED && \
+ defined PNG_READ_cHRM_SUPPORTED && \
+ defined PNG_READ_gAMA_SUPPORTED && \
+ defined PNG_READ_oFFs_SUPPORTED && \
+ defined PNG_READ_pCAL_SUPPORTED && \
+ defined PNG_READ_pHYs_SUPPORTED && \
+ defined PNG_READ_sBIT_SUPPORTED && \
+ defined PNG_READ_sCAL_SUPPORTED && \
+ defined PNG_READ_sRGB_SUPPORTED && \
+ defined PNG_READ_sPLT_SUPPORTED && \
+ defined PNG_READ_tEXt_SUPPORTED && \
+ defined PNG_READ_tIME_SUPPORTED && \
+ defined PNG_READ_zTXt_SUPPORTED && \
+ (defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700)
+
+/* Copied from pngpriv.h but only used in error messages below. */
+#ifndef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 8192
#endif
-/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_STDIO_SUPPORTED
+typedef FILE * png_FILE_p;
+#endif
+
+/* This hack was introduced for historical reasons, and we are
+ * still keeping it in libpng-1.6.x for compatibility reasons.
+ */
+#define STDERR stdout
+
#ifndef PNG_DEBUG
# define PNG_DEBUG 0
#endif
-#if !PNG_DEBUG
-# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */
+#if PNG_DEBUG > 1
+# define pngtest_debug(m) ((void)fprintf(stderr, m "\n"))
+# define pngtest_debug1(m, p1) ((void)fprintf(stderr, m "\n", p1))
+# define pngtest_debug2(m, p1, p2) ((void)fprintf(stderr, m "\n", p1, p2))
+#elif PNG_DEBUG == 0 || PNG_DEBUG == 1
+# define pngtest_debug(m) ((void)0)
+# define pngtest_debug1(m, p1) ((void)0)
+# define pngtest_debug2(m, p1, p2) ((void)0)
+#else /* PNG_DEBUG < 0 */
+# error "Bad PNG_DEBUG value"
#endif
/* Turn on CPU timing
#define PNGTEST_TIMING
*/
-#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
+#ifndef PNG_FLOATING_POINT_SUPPORTED
#undef PNGTEST_TIMING
#endif
@@ -81,124 +137,110 @@ static float t_start, t_stop, t_decode, t_encode, t_misc;
#include
#endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
-#define PNG_tIME_STRING_LENGTH 30
-static int tIME_chunk_present=0;
-static char tIME_string[PNG_tIME_STRING_LENGTH] = "no tIME chunk present in file";
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+static int tIME_chunk_present = 0;
+static char tIME_string[29] = "tIME chunk is not present";
+/* This use case is deprecated.
+ * See the declaration of png_convert_to_rfc1123_buffer for more details.
+ */
#endif
static int verbose = 0;
+static int strict = 0;
+static int relaxed = 0;
+static int xfail = 0;
+static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
+static int error_count = 0; /* count calls to png_error */
+static int warning_count = 0; /* count calls to png_warning */
-int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
+/* Example of using row callbacks to make a simple progress meter */
+static int status_pass = 1;
+static int status_dots_requested = 0;
+static int status_dots = 1;
-#ifdef __TURBOC__
-#include
-#endif
-
-/* defined so I can write to a file on gui/windowing platforms */
-/* #define STDERR stderr */
-#define STDERR stdout /* for DOS */
-
-/* example of using row callbacks to make a simple progress meter */
-static int status_pass=1;
-static int status_dots_requested=0;
-static int status_dots=1;
-
-/* In case a system header (e.g., on AIX) defined jmpbuf */
-#ifdef jmpbuf
-# undef jmpbuf
-#endif
-
-/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
-#ifndef png_jmpbuf
-# define png_jmpbuf(png_ptr) png_ptr->jmpbuf
-#endif
-
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
-read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
+static void PNGCBAPI
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{
- if(png_ptr == NULL || row_number > PNG_UINT_31_MAX) return;
- if(status_pass != pass)
- {
- fprintf(stdout,"\n Pass %d: ",pass);
- status_pass = pass;
- status_dots = 31;
- }
- status_dots--;
- if(status_dots == 0)
- {
- fprintf(stdout, "\n ");
- status_dots=30;
- }
- fprintf(stdout, "r");
+ /* The callback should always receive correct parameters. */
+ if (png_ptr == NULL)
+ png_error(png_ptr, "read_row_callback: bad png_ptr");
+ if (row_number > PNG_UINT_31_MAX)
+ png_error(png_ptr, "read_row_callback: bad row number");
+ if (pass < 0 || pass > 7)
+ png_error(png_ptr, "read_row_callback: bad pass");
+
+ if (status_pass != pass)
+ {
+ fprintf(stdout, "\n Pass %d: ", pass);
+ status_pass = pass;
+ status_dots = 31;
+ }
+
+ status_dots--;
+
+ if (status_dots == 0)
+ {
+ fprintf(stdout, "\n ");
+ status_dots = 30;
+ }
+
+ fprintf(stdout, "r");
}
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
-write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
+#ifdef PNG_WRITE_SUPPORTED
+static void PNGCBAPI
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{
- if(png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return;
- fprintf(stdout, "w");
+ /* The callback should always receive correct parameters. */
+ if (png_ptr == NULL)
+ png_error(png_ptr, "write_row_callback: bad png_ptr");
+ if (row_number > PNG_UINT_31_MAX)
+ png_error(png_ptr, "write_row_callback: bad row number");
+ if (pass < 0 || pass > 7)
+ png_error(png_ptr, "write_row_callback: bad pass");
+
+ fprintf(stdout, "w");
}
+#endif
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
-/* Example of using user transform callback (we don't transform anything,
- but merely examine the row filters. We set this to 256 rather than
- 5 in case illegal filter values are present.) */
-static png_uint_32 filters_used[256];
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
-count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
-count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+/* Example of using a user transform callback (doesn't do anything at present).
+ */
+static void PNGCBAPI
+read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
- if(png_ptr != NULL && row_info != NULL)
- ++filters_used[*(data-1)];
+ /* The callback should always receive correct parameters. */
+ if (png_ptr == NULL)
+ png_error(png_ptr, "read_user_callback: bad png_ptr");
+ if (row_info == NULL)
+ png_error(png_ptr, "read_user_callback: bad row info");
+ if (data == NULL)
+ png_error(png_ptr, "read_user_callback: bad data");
}
#endif
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
-/* example of using user transform callback (we don't transform anything,
- but merely count the zero samples) */
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+/* Example of using user transform callback (we don't transform anything,
+ * but merely count the zero samples)
+ */
static png_uint_32 zero_samples;
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
-count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
-void
-#ifdef PNG_1_0_X
-PNGAPI
-#endif
+static void PNGCBAPI
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
png_bytep dp = data;
- if(png_ptr == NULL)return;
- /* contents of row_info:
+ /* The callback should always receive correct parameters. */
+ if (png_ptr == NULL)
+ png_error(png_ptr, "count_zero_samples: bad png_ptr");
+ if (row_info == NULL)
+ png_error(png_ptr, "count_zero_samples: bad row info");
+ if (data == NULL)
+ png_error(png_ptr, "count_zero_samples: bad data");
+
+ /* Contents of row_info:
* png_uint_32 width width of row
* png_uint_32 rowbytes number of bytes in row
* png_byte color_type color type of pixels
@@ -207,250 +249,229 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
* png_byte pixel_depth bits per pixel (depth*channels)
*/
+ /* Counts the number of zero samples (or zero pixels if color_type is 3 */
- /* counts the number of zero samples (or zero pixels if color_type is 3 */
+ if (row_info->color_type == 0 || row_info->color_type == 3)
+ {
+ int pos = 0;
+ png_uint_32 n, nstop;
- if(row_info->color_type == 0 || row_info->color_type == 3)
- {
- int pos=0;
- png_uint_32 n, nstop;
- for (n=0, nstop=row_info->width; nbit_depth == 1)
- {
- if(((*dp << pos++ ) & 0x80) == 0) zero_samples++;
- if(pos == 8)
- {
- pos = 0;
- dp++;
- }
- }
- if(row_info->bit_depth == 2)
- {
- if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
- if(pos == 8)
- {
- pos = 0;
- dp++;
- }
- }
- if(row_info->bit_depth == 4)
- {
- if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
- if(pos == 8)
- {
- pos = 0;
- dp++;
- }
- }
- if(row_info->bit_depth == 8)
- if(*dp++ == 0) zero_samples++;
- if(row_info->bit_depth == 16)
- {
- if((*dp | *(dp+1)) == 0) zero_samples++;
- dp+=2;
- }
- }
- }
- else /* other color types */
- {
- png_uint_32 n, nstop;
- int channel;
- int color_channels = row_info->channels;
- if(row_info->color_type > 3)color_channels--;
+ for (n = 0, nstop = row_info->width; n < nstop; n++)
+ {
+ if (row_info->bit_depth == 1)
+ {
+ if (((*dp << pos++ ) & 0x80) == 0)
+ zero_samples++;
- for (n=0, nstop=row_info->width; nbit_depth == 8)
- if(*dp++ == 0) zero_samples++;
- if(row_info->bit_depth == 16)
- {
- if((*dp | *(dp+1)) == 0) zero_samples++;
- dp+=2;
- }
- }
- if(row_info->color_type > 3)
- {
- dp++;
- if(row_info->bit_depth == 16)dp++;
- }
- }
- }
+ if (pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+
+ if (row_info->bit_depth == 2)
+ {
+ if (((*dp << (pos+=2)) & 0xc0) == 0)
+ zero_samples++;
+
+ if (pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+
+ if (row_info->bit_depth == 4)
+ {
+ if (((*dp << (pos+=4)) & 0xf0) == 0)
+ zero_samples++;
+
+ if (pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+
+ if (row_info->bit_depth == 8)
+ if (*dp++ == 0)
+ zero_samples++;
+
+ if (row_info->bit_depth == 16)
+ {
+ if ((*dp | *(dp+1)) == 0)
+ zero_samples++;
+ dp += 2;
+ }
+ }
+ }
+ else /* Other color types */
+ {
+ png_uint_32 n, nstop;
+ int channel;
+ int color_channels = row_info->channels;
+ if (row_info->color_type > 3)
+ color_channels--;
+
+ for (n = 0, nstop = row_info->width; n < nstop; n++)
+ {
+ for (channel = 0; channel < color_channels; channel++)
+ {
+ if (row_info->bit_depth == 8)
+ if (*dp++ == 0)
+ zero_samples++;
+
+ if (row_info->bit_depth == 16)
+ {
+ if ((*dp | *(dp+1)) == 0)
+ zero_samples++;
+
+ dp += 2;
+ }
+ }
+ if (row_info->color_type > 3)
+ {
+ dp++;
+ if (row_info->bit_depth == 16)
+ dp++;
+ }
+ }
+ }
}
-#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
+#endif /* WRITE_USER_TRANSFORM */
-static int wrote_question = 0;
-
-#if defined(PNG_NO_STDIO)
+#ifndef PNG_STDIO_SUPPORTED
/* START of code to validate stdio-free compilation */
-/* These copies of the default read/write functions come from pngrio.c and */
-/* pngwio.c. They allow "don't include stdio" testing of the library. */
-/* This is the function that does the actual reading of data. If you are
- not reading from a standard C stream, you should create a replacement
- read_data function and use it at run time with png_set_read_fn(), rather
- than changing the library. */
+/* These copies of the default read/write functions come from pngrio.c and
+ * pngwio.c. They allow "don't include stdio" testing of the library.
+ * This is the function that does the actual reading of data. If you are
+ * not reading from a standard C stream, you should create a replacement
+ * read_data function and use it at run time with png_set_read_fn(), rather
+ * than changing the library.
+ */
-#ifndef USE_FAR_KEYWORD
-static void
-pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#ifdef PNG_IO_STATE_SUPPORTED
+void
+pngtest_check_io_state(png_structp png_ptr, size_t data_length,
+ png_uint_32 io_op)
{
- png_size_t check;
+ png_uint_32 io_state = png_get_io_state(png_ptr);
+ int err = 0;
- /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ /* Check if the current operation (reading / writing) is as expected. */
+ if ((io_state & PNG_IO_MASK_OP) != io_op)
+ png_error(png_ptr, "Incorrect operation in I/O state");
+
+ /* Check if the buffer size specific to the current location
+ * (file signature / header / data / crc) is as expected.
+ */
+ switch ((io_state & PNG_IO_MASK_LOC) != 0)
+ {
+ case PNG_IO_SIGNATURE:
+ if (data_length > 8)
+ err = 1;
+ break;
+ case PNG_IO_CHUNK_HDR:
+ if (data_length != 8)
+ err = 1;
+ break;
+ case PNG_IO_CHUNK_DATA:
+ break; /* no restrictions here */
+ case PNG_IO_CHUNK_CRC:
+ if (data_length != 4)
+ err = 1;
+ break;
+ default:
+ err = 1; /* uninitialized */
+ }
+ if (err != 0)
+ png_error(png_ptr, "Bad I/O state or buffer size");
+}
+#endif
+
+static void PNGCBAPI
+pngtest_read_data(png_structp png_ptr, png_bytep data, size_t length)
+{
+ size_t check = 0;
+ png_voidp io_ptr;
+
+ if (png_ptr == NULL)
+ png_error(png_ptr, "pngtest_read_data: bad png_ptr");
+
+ /* 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.
*/
- READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
+ io_ptr = png_get_io_ptr(png_ptr);
+ if (io_ptr != NULL)
+ check = fread(data, 1, length, (png_FILE_p)io_ptr);
if (check != length)
- {
- png_error(png_ptr, "Read Error!");
- }
+ png_error(png_ptr, "Read Error");
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
+#endif
}
-#else
-/* this is the model-independent version. Since the standard I/O library
- can't handle far buffers in the medium and small models, we have to copy
- the data.
-*/
-#define NEAR_BUF_SIZE 1024
-#define MIN(a,b) (a <= b ? a : b)
-
-static void
-pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
-{
- int check;
- png_byte *n_data;
- png_FILE_p io_ptr;
-
- /* Check if data really is near. If so, use usual code. */
- n_data = (png_byte *)CVT_PTR_NOCHECK(data);
- io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
- if ((png_bytep)n_data == data)
- {
- READFILE(io_ptr, n_data, length, check);
- }
- else
- {
- png_byte buf[NEAR_BUF_SIZE];
- png_size_t read, remaining, err;
- check = 0;
- remaining = length;
- do
- {
- read = MIN(NEAR_BUF_SIZE, remaining);
- READFILE(io_ptr, buf, 1, err);
- png_memcpy(data, buf, read); /* copy far buffer to near buffer */
- if(err != read)
- break;
- else
- check += err;
- data += read;
- remaining -= read;
- }
- while (remaining != 0);
- }
- if (check != length)
- {
- png_error(png_ptr, "read Error");
- }
-}
-#endif /* USE_FAR_KEYWORD */
-
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
-static void
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+static void PNGCBAPI
pngtest_flush(png_structp png_ptr)
{
-#if !defined(_WIN32_WCE)
- png_FILE_p io_ptr;
- io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
- if (io_ptr != NULL)
- fflush(io_ptr);
-#endif
+ if (png_ptr == NULL)
+ png_error(png_ptr, "pngtest_flush: bad png_ptr");
+
+ /* Do nothing; fflush() is said to be just a waste of energy. */
}
#endif
/* This is the function that does the actual writing of data. If you are
- not writing to a standard C stream, you should create a replacement
- write_data function and use it at run time with png_set_write_fn(), rather
- than changing the library. */
-#ifndef USE_FAR_KEYWORD
-static void
-pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+ * not writing to a standard C stream, you should create a replacement
+ * write_data function and use it at run time with png_set_write_fn(), rather
+ * than changing the library.
+ */
+static void PNGCBAPI
+pngtest_write_data(png_structp png_ptr, png_bytep data, size_t length)
{
- png_uint_32 check;
+ size_t check;
+
+ if (png_ptr == NULL)
+ png_error(png_ptr, "pngtest_write_data: bad png_ptr");
+
+ check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
- WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
if (check != length)
- {
png_error(png_ptr, "Write Error");
- }
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
+#endif
}
-#else
-/* this is the model-independent version. Since the standard I/O library
- can't handle far buffers in the medium and small models, we have to copy
- the data.
-*/
-
-#define NEAR_BUF_SIZE 1024
-#define MIN(a,b) (a <= b ? a : b)
-
-static void
-pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
-{
- png_uint_32 check;
- png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
- png_FILE_p io_ptr;
-
- /* Check if data really is near. If so, use usual code. */
- near_data = (png_byte *)CVT_PTR_NOCHECK(data);
- io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
- if ((png_bytep)near_data == data)
- {
- WRITEFILE(io_ptr, near_data, length, check);
- }
- else
- {
- png_byte buf[NEAR_BUF_SIZE];
- png_size_t written, remaining, err;
- check = 0;
- remaining = length;
- do
- {
- written = MIN(NEAR_BUF_SIZE, remaining);
- png_memcpy(buf, data, written); /* copy far buffer to near buffer */
- WRITEFILE(io_ptr, buf, written, err);
- if (err != written)
- break;
- else
- check += err;
- data += written;
- remaining -= written;
- }
- while (remaining != 0);
- }
- if (check != length)
- {
- png_error(png_ptr, "Write Error");
- }
-}
-#endif /* USE_FAR_KEYWORD */
-#endif /* PNG_NO_STDIO */
-/* END of code to validate stdio-free compilation */
+#endif /* !STDIO */
/* This function is called when there is a warning, but the library thinks
* it can continue anyway. Replacement functions don't have to do anything
* here if you don't want to. In the default configuration, png_ptr is
* not used, but it is passed in case it may be useful.
*/
-static void
+typedef struct
+{
+ const char *file_name;
+} pngtest_error_parameters;
+
+static void PNGCBAPI
pngtest_warning(png_structp png_ptr, png_const_charp message)
{
- PNG_CONST char *name = "UNKNOWN (ERROR!)";
- if (png_ptr != NULL && png_ptr->error_ptr != NULL)
- name = png_ptr->error_ptr;
- fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
+ const char *name = "UNKNOWN (ERROR!)";
+ pngtest_error_parameters *test =
+ (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
+
+ ++warning_count;
+
+ if (test != NULL && test->file_name != NULL)
+ name = test->file_name;
+
+ fprintf(STDERR, "\n%s: libpng warning: %s\n", name, message);
}
/* This is the default error handling function. Note that replacements for
@@ -458,32 +479,38 @@ pngtest_warning(png_structp png_ptr, png_const_charp message)
* function is used by default, or if the program supplies NULL for the
* error function pointer in png_set_error_fn().
*/
-static void
+static void PNGCBAPI
pngtest_error(png_structp png_ptr, png_const_charp message)
{
+ ++error_count;
+
pngtest_warning(png_ptr, message);
/* We can return because png_error calls the default handler, which is
- * actually OK in this case. */
+ * actually OK in this case.
+ */
}
+/* END of code to validate stdio-free compilation */
+
/* START of code to validate memory allocation and deallocation */
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
/* Allocate memory. For reasonable files, size should never exceed
- 64K. However, zlib may allocate more then 64K if you don't tell
- it not to. See zconf.h and png.h for more information. zlib does
- need to allocate exactly 64K, so whatever you call here must
- have the ability to do that.
-
- This piece of code can be compiled to validate max 64K allocations
- by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
+ * 64K. However, zlib may allocate more than 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * This piece of code can be compiled to validate max 64K allocations
+ * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
+ */
typedef struct memory_information
{
- png_uint_32 size;
+ png_alloc_size_t size;
png_voidp pointer;
- struct memory_information FAR *next;
+ struct memory_information *next;
} memory_information;
-typedef memory_information FAR *memory_infop;
+typedef memory_information *memory_infop;
static memory_infop pinformation = NULL;
static int current_allocation = 0;
@@ -491,18 +518,20 @@ static int maximum_allocation = 0;
static int total_allocation = 0;
static int num_allocations = 0;
-png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
-void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
+png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr,
+ png_alloc_size_t size));
+void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
png_voidp
-png_debug_malloc(png_structp png_ptr, png_uint_32 size)
+PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
{
/* png_malloc has already tested for NULL; png_create_struct calls
- png_debug_malloc directly, with png_ptr == NULL which is OK */
+ * png_debug_malloc directly, with png_ptr == NULL which is OK
+ */
if (size == 0)
- return (NULL);
+ return NULL;
/* This calls the library allocator twice, once to get the requested
buffer and once to get a new free list entry. */
@@ -511,41 +540,49 @@ png_debug_malloc(png_structp png_ptr, png_uint_32 size)
memory_infop pinfo;
png_set_mem_fn(png_ptr, NULL, NULL, NULL);
pinfo = (memory_infop)png_malloc(png_ptr,
- (png_uint_32)png_sizeof (*pinfo));
+ (sizeof *pinfo));
pinfo->size = size;
current_allocation += size;
total_allocation += size;
- num_allocations ++;
+ ++num_allocations;
+
if (current_allocation > maximum_allocation)
maximum_allocation = current_allocation;
- pinfo->pointer = (png_voidp)png_malloc(png_ptr, size);
+
+ pinfo->pointer = png_malloc(png_ptr, size);
/* Restore malloc_fn and free_fn */
- png_set_mem_fn(png_ptr, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc,
- (png_free_ptr)png_debug_free);
+
+ png_set_mem_fn(png_ptr,
+ NULL, png_debug_malloc, png_debug_free);
+
if (size != 0 && pinfo->pointer == NULL)
{
current_allocation -= size;
total_allocation -= size;
png_error(png_ptr,
- "out of memory in pngtest->png_debug_malloc.");
+ "out of memory in pngtest->png_debug_malloc");
}
+
pinfo->next = pinformation;
pinformation = pinfo;
/* Make sure the caller isn't assuming zeroed memory. */
- png_memset(pinfo->pointer, 0xdd, pinfo->size);
- if(verbose)
- printf("png_malloc %lu bytes at %x\n",(unsigned long)size,
- pinfo->pointer);
- return (png_voidp)(pinfo->pointer);
+ memset(pinfo->pointer, 0xdd, pinfo->size);
+
+ if (verbose != 0)
+ printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
+ pinfo->pointer);
+
+ return (png_voidp)pinfo->pointer;
}
}
/* Free a pointer. It is removed from the list at the same time. */
-void
+void PNGCBAPI
png_debug_free(png_structp png_ptr, png_voidp ptr)
{
if (png_ptr == NULL)
fprintf(STDERR, "NULL pointer to png_debug_free.\n");
+
if (ptr == 0)
{
#if 0 /* This happens all the time. */
@@ -555,11 +592,14 @@ png_debug_free(png_structp png_ptr, png_voidp ptr)
}
/* Unlink the element from the list. */
+ if (pinformation != NULL)
{
- memory_infop FAR *ppinfo = &pinformation;
+ memory_infop *ppinfo = &pinformation;
+
for (;;)
{
memory_infop pinfo = *ppinfo;
+
if (pinfo->pointer == ptr)
{
*ppinfo = pinfo->next;
@@ -568,111 +608,322 @@ png_debug_free(png_structp png_ptr, png_voidp ptr)
fprintf(STDERR, "Duplicate free of memory\n");
/* We must free the list element too, but first kill
the memory that is to be freed. */
- png_memset(ptr, 0x55, pinfo->size);
- png_free_default(png_ptr, pinfo);
- pinfo=NULL;
+ memset(ptr, 0x55, pinfo->size);
+ free(pinfo);
+ pinfo = NULL;
break;
}
+
if (pinfo->next == NULL)
{
- fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
+ fprintf(STDERR, "Pointer %p not found\n", ptr);
break;
}
+
ppinfo = &pinfo->next;
}
}
/* Finally free the data. */
- if(verbose)
- printf("Freeing %x\n",ptr);
- png_free_default(png_ptr, ptr);
- ptr=NULL;
+ if (verbose != 0)
+ printf("Freeing %p\n", ptr);
+
+ if (ptr != NULL)
+ free(ptr);
+ ptr = NULL;
}
-#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
+#endif /* USER_MEM && DEBUG */
/* END of code to test memory allocation/deallocation */
+
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+/* Demonstration of user chunk support of the sTER and vpAg chunks */
+
+/* (sTER is a public chunk not yet known by libpng. vpAg is a private
+chunk used in ImageMagick to store "virtual page" size). */
+
+typedef struct user_chunk_info_def
+{
+ png_const_infop info_ptr;
+ png_uint_32 vpAg_width, vpAg_height;
+ png_byte vpAg_units;
+ png_byte sTER_mode;
+ int location[2];
+} user_chunk_info;
+
+/* Used for location and order; zero means nothing. */
+#define have_sTER 0x01
+#define have_vpAg 0x02
+#define before_PLTE 0x10
+#define before_IDAT 0x20
+#define after_IDAT 0x40
+
+static void
+init_user_chunk_info(png_const_infop info_ptr, user_chunk_info *chunk_data)
+{
+ memset(chunk_data, 0, sizeof(*chunk_data));
+ chunk_data->info_ptr = info_ptr;
+}
+
+static int
+set_chunk_location(png_structp png_ptr, user_chunk_info *chunk_data, int what)
+{
+ int location;
+
+ if ((chunk_data->location[0] & what) != 0 ||
+ (chunk_data->location[1] & what) != 0)
+ return 0; /* we already have one of these */
+
+ /* Find where we are (the code below zeroes info_ptr to indicate that the
+ * chunks before the first IDAT have been read.)
+ */
+ if (chunk_data->info_ptr == NULL) /* after IDAT */
+ location = what | after_IDAT;
+
+ else if (png_get_valid(png_ptr, chunk_data->info_ptr, PNG_INFO_PLTE) != 0)
+ location = what | before_IDAT;
+
+ else
+ location = what | before_PLTE;
+
+ if (chunk_data->location[0] == 0)
+ chunk_data->location[0] = location;
+
+ else
+ chunk_data->location[1] = location;
+
+ return 1; /* handled */
+}
+
+static int PNGCBAPI
+read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
+{
+ user_chunk_info *my_user_chunk_data =
+ (user_chunk_info*)png_get_user_chunk_ptr(png_ptr);
+
+ if (my_user_chunk_data == NULL)
+ png_error(png_ptr, "lost pointer to user chunk data");
+
+ /* Return one of the following:
+ * return -n; chunk had an error
+ * return 0; did not recognize
+ * return n; success
+ *
+ * The unknown chunk structure contains the chunk data:
+ * png_byte name[5];
+ * png_byte *data;
+ * size_t size;
+ *
+ * Note that libpng has already taken care of the CRC handling.
+ */
+
+ if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */
+ chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */
+ {
+ /* Found sTER chunk */
+ if (chunk->size != 1)
+ return -1; /* Error return */
+
+ if (chunk->data[0] != 0 && chunk->data[0] != 1)
+ return -1; /* Invalid mode */
+
+ if (set_chunk_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
+ {
+ my_user_chunk_data->sTER_mode = chunk->data[0];
+ return 1;
+ }
+
+ else
+ return 0; /* duplicate sTER - give it to libpng */
+ }
+
+ if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */
+ chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */
+ return 0; /* Did not recognize */
+
+ /* Found ImageMagick vpAg chunk */
+
+ if (chunk->size != 9)
+ return -1; /* Error return */
+
+ if (set_chunk_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
+ return 0; /* duplicate vpAg */
+
+ my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data);
+ my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4);
+ my_user_chunk_data->vpAg_units = chunk->data[8];
+
+ return 1;
+}
+
+#ifdef PNG_WRITE_SUPPORTED
+static void
+write_sTER_chunk(png_structp write_ptr, user_chunk_info *data)
+{
+ png_byte sTER[5] = {115, 84, 69, 82, '\0'};
+
+ if (verbose != 0)
+ fprintf(STDERR, "\n stereo mode = %d\n", data->sTER_mode);
+
+ png_write_chunk(write_ptr, sTER, &data->sTER_mode, 1);
+}
+
+static void
+write_vpAg_chunk(png_structp write_ptr, user_chunk_info *data)
+{
+ png_byte vpAg[5] = {118, 112, 65, 103, '\0'};
+
+ png_byte vpag_chunk_data[9];
+
+ if (verbose != 0)
+ fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
+ (unsigned long)data->vpAg_width,
+ (unsigned long)data->vpAg_height,
+ data->vpAg_units);
+
+ png_save_uint_32(vpag_chunk_data, data->vpAg_width);
+ png_save_uint_32(vpag_chunk_data + 4, data->vpAg_height);
+ vpag_chunk_data[8] = data->vpAg_units;
+ png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
+}
+
+static void
+write_chunks(png_structp write_ptr, user_chunk_info *data, int location)
+{
+ int i;
+
+ /* Notice that this preserves the original chunk order, however chunks
+ * intercepted by the callback will be written *after* chunks passed to
+ * libpng. This will actually reverse a pair of sTER chunks or a pair of
+ * vpAg chunks, resulting in an error later. This is not worth worrying
+ * about - the chunks should not be duplicated!
+ */
+ for (i = 0; i < 2; ++i)
+ {
+ if (data->location[i] == (location | have_sTER))
+ write_sTER_chunk(write_ptr, data);
+
+ else if (data->location[i] == (location | have_vpAg))
+ write_vpAg_chunk(write_ptr, data);
+ }
+}
+#endif /* WRITE */
+#else /* !READ_USER_CHUNKS */
+# define write_chunks(pp,loc) ((void)0)
+#endif
+/* END of code to demonstrate user chunk support */
+
+/* START of code to check that libpng has the required text support; this only
+ * checks for the write support because if read support is missing the chunk
+ * will simply not be reported back to pngtest.
+ */
+#ifdef PNG_TEXT_SUPPORTED
+static void
+pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr,
+ int num_text)
+{
+ while (num_text > 0)
+ {
+ switch (text_ptr[--num_text].compression)
+ {
+ case PNG_TEXT_COMPRESSION_NONE:
+ break;
+
+ case PNG_TEXT_COMPRESSION_zTXt:
+# ifndef PNG_WRITE_zTXt_SUPPORTED
+ ++unsupported_chunks;
+ /* In libpng 1.7 this now does an app-error, so stop it: */
+ text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+# endif
+ break;
+
+ case PNG_ITXT_COMPRESSION_NONE:
+ case PNG_ITXT_COMPRESSION_zTXt:
+# ifndef PNG_WRITE_iTXt_SUPPORTED
+ ++unsupported_chunks;
+ text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+# endif
+ break;
+
+ default:
+ /* This is an error */
+ png_error(png_ptr, "invalid text chunk compression field");
+ break;
+ }
+ }
+}
+#endif
+/* END of code to check that libpng has the required text support */
+
/* Test one file */
-int
-test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
+static int
+test_one_file(const char *inname, const char *outname)
{
static png_FILE_p fpin;
static png_FILE_p fpout; /* "static" prevents setjmp corruption */
+ pngtest_error_parameters error_parameters;
png_structp read_ptr;
png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
png_structp write_ptr;
png_infop write_info_ptr;
png_infop write_end_info_ptr;
-#else
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ int interlace_preserved = 1;
+#endif /* WRITE_FILTER */
+#else /* !WRITE */
png_structp write_ptr = NULL;
png_infop write_info_ptr = NULL;
png_infop write_end_info_ptr = NULL;
-#endif
+#endif /* !WRITE */
png_bytep row_buf;
png_uint_32 y;
png_uint_32 width, height;
- int num_pass, pass;
int bit_depth, color_type;
-#ifdef PNG_SETJMP_SUPPORTED
-#ifdef USE_FAR_KEYWORD
- jmp_buf jmpbuf;
-#endif
-#endif
-
-#if defined(_WIN32_WCE)
- TCHAR path[MAX_PATH];
-#endif
- char inbuf[256], outbuf[256];
+ user_chunk_info my_user_chunk_data;
+ int pass, num_passes;
row_buf = NULL;
+ error_parameters.file_name = inname;
-#if defined(_WIN32_WCE)
- MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
- if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
-#else
if ((fpin = fopen(inname, "rb")) == NULL)
-#endif
{
fprintf(STDERR, "Could not find input file %s\n", inname);
- return (1);
+ return 1;
}
-#if defined(_WIN32_WCE)
- MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
- if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
-#else
if ((fpout = fopen(outname, "wb")) == NULL)
-#endif
{
fprintf(STDERR, "Could not open output file %s\n", outname);
- FCLOSE(fpin);
- return (1);
+ fclose(fpin);
+ return 1;
}
- png_debug(0, "Allocating read and write structures\n");
+ pngtest_debug("Allocating read and write structures");
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
- read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
- png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
- (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+ read_ptr =
+ png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
+ NULL, NULL, NULL, png_debug_malloc, png_debug_free);
#else
- read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
- png_error_ptr_NULL, png_error_ptr_NULL);
+ read_ptr =
+ png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
- png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
+ png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
pngtest_warning);
+
#ifdef PNG_WRITE_SUPPORTED
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
- write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
- png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
- (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+ write_ptr =
+ png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
+ NULL, NULL, NULL, png_debug_malloc, png_debug_free);
#else
- write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
- png_error_ptr_NULL, png_error_ptr_NULL);
+ write_ptr =
+ png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
- png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
+ png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
pngtest_warning);
#endif
- png_debug(0, "Allocating read_info, write_info and end_info structures\n");
+ pngtest_debug("Allocating read_info, write_info and end_info structures");
read_info_ptr = png_create_info_struct(read_ptr);
end_info_ptr = png_create_info_struct(read_ptr);
#ifdef PNG_WRITE_SUPPORTED
@@ -680,56 +931,94 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
write_end_info_ptr = png_create_info_struct(write_ptr);
#endif
-#ifdef PNG_SETJMP_SUPPORTED
- png_debug(0, "Setting jmpbuf for read struct\n");
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
-#else
- if (setjmp(png_jmpbuf(read_ptr)))
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ init_user_chunk_info(read_info_ptr, &my_user_chunk_data);
+ png_set_read_user_chunk_fn(read_ptr, &my_user_chunk_data,
+ read_user_chunk_callback);
#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ pngtest_debug("Setting jmpbuf for read struct");
+ if (setjmp(png_jmpbuf(read_ptr)))
{
fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
- if (row_buf)
- png_free(read_ptr, row_buf);
+ png_free(read_ptr, row_buf);
+ row_buf = NULL;
+ if (verbose != 0)
+ fprintf(STDERR, " destroy read structs\n");
png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
+ if (verbose != 0)
+ fprintf(STDERR, " destroy write structs\n");
png_destroy_info_struct(write_ptr, &write_end_info_ptr);
png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
- FCLOSE(fpin);
- FCLOSE(fpout);
- return (1);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
}
-#ifdef USE_FAR_KEYWORD
- png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf));
-#endif
#ifdef PNG_WRITE_SUPPORTED
- png_debug(0, "Setting jmpbuf for write struct\n");
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
-#else
+ pngtest_debug("Setting jmpbuf for write struct");
+
if (setjmp(png_jmpbuf(write_ptr)))
-#endif
{
fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
+ png_free(read_ptr, row_buf);
+ row_buf = NULL;
+ if (verbose != 0)
+ fprintf(STDERR, " destroying read structs\n");
png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ if (verbose != 0)
+ fprintf(STDERR, " destroying write structs\n");
png_destroy_info_struct(write_ptr, &write_end_info_ptr);
-#ifdef PNG_WRITE_SUPPORTED
png_destroy_write_struct(&write_ptr, &write_info_ptr);
-#endif
- FCLOSE(fpin);
- FCLOSE(fpout);
- return (1);
+ fclose(fpin);
+ fclose(fpout);
+ return 1;
}
-#ifdef USE_FAR_KEYWORD
- png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf));
-#endif
#endif
#endif
- png_debug(0, "Initializing input and output streams\n");
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ if (strict != 0)
+ {
+ /* Treat png_benign_error() as errors on read */
+ png_set_benign_errors(read_ptr, 0);
+
+# ifdef PNG_WRITE_SUPPORTED
+ /* Treat them as errors on write */
+ png_set_benign_errors(write_ptr, 0);
+# endif
+
+ /* if strict is not set, then app warnings and errors are treated as
+ * warnings in release builds, but not in unstable builds; this can be
+ * changed with '--relaxed'.
+ */
+ }
+
+ else if (relaxed != 0)
+ {
+ /* Allow application (pngtest) errors and warnings to pass */
+ png_set_benign_errors(read_ptr, 1);
+
+ /* Turn off CRC checking while reading */
+ png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
+
+#ifdef PNG_IGNORE_ADLER32
+ /* Turn off ADLER32 checking while reading */
+ png_set_option(read_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
+#endif
+
+# ifdef PNG_WRITE_SUPPORTED
+ png_set_benign_errors(write_ptr, 1);
+# endif
+
+ }
+#endif /* BENIGN_ERRORS */
+
+ pngtest_debug("Initializing input and output streams");
+#ifdef PNG_STDIO_SUPPORTED
png_init_io(read_ptr, fpin);
# ifdef PNG_WRITE_SUPPORTED
png_init_io(write_ptr, fpout);
@@ -738,189 +1027,220 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
# ifdef PNG_WRITE_SUPPORTED
png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data,
-# if defined(PNG_WRITE_FLUSH_SUPPORTED)
- pngtest_flush);
+# ifdef PNG_WRITE_FLUSH_SUPPORTED
+ pngtest_flush);
# else
- NULL);
+ NULL);
# endif
# endif
#endif
- if(status_dots_requested == 1)
+
+ if (status_dots_requested == 1)
{
#ifdef PNG_WRITE_SUPPORTED
png_set_write_status_fn(write_ptr, write_row_callback);
#endif
png_set_read_status_fn(read_ptr, read_row_callback);
}
+
else
{
#ifdef PNG_WRITE_SUPPORTED
- png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL);
+ png_set_write_status_fn(write_ptr, NULL);
#endif
- png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL);
+ png_set_read_status_fn(read_ptr, NULL);
}
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- {
- int i;
- for(i=0; i<256; i++)
- filters_used[i]=0;
- png_set_read_user_transform_fn(read_ptr, count_filters);
- }
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+ png_set_read_user_transform_fn(read_ptr, read_user_callback);
#endif
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
- zero_samples=0;
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+ zero_samples = 0;
png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
-# ifndef PNG_HANDLE_CHUNK_ALWAYS
-# define PNG_HANDLE_CHUNK_ALWAYS 3
-# endif
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ /* Preserve all the unknown chunks, if possible. If this is disabled, then
+ * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use
+ * libpng to *save* the unknown chunks on read (because we can't switch the
+ * save option on!)
+ *
+ * Notice that if SET_UNKNOWN_CHUNKS is *not* supported, the reader will
+ * discard all unknown chunks, and the writer will write them all.
+ */
+#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
- png_bytep_NULL, 0);
+ NULL, 0);
+#endif
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
+ NULL, 0);
#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
-# ifndef PNG_HANDLE_CHUNK_IF_SAFE
-# define PNG_HANDLE_CHUNK_IF_SAFE 2
-# endif
- png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
- png_bytep_NULL, 0);
#endif
- png_debug(0, "Reading info struct\n");
+ pngtest_debug("Reading info struct");
png_read_info(read_ptr, read_info_ptr);
- png_debug(0, "Transferring info struct\n");
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ /* This is a bit of a hack; there is no obvious way in the callback function
+ * to determine that the chunks before the first IDAT have been read, so
+ * remove the info_ptr (which is only used to determine position relative to
+ * PLTE) here to indicate that we are after the IDAT.
+ */
+ my_user_chunk_data.info_ptr = NULL;
+#endif
+
+ pngtest_debug("Transferring info struct");
{
int interlace_type, compression_type, filter_type;
if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
- &color_type, &interlace_type, &compression_type, &filter_type))
+ &color_type, &interlace_type, &compression_type, &filter_type) != 0)
{
png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
- color_type, interlace_type, compression_type, filter_type);
-#else
- color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
-#endif
+ color_type, interlace_type, compression_type, filter_type);
+ /* num_passes may not be available below if interlace support is not
+ * provided by libpng for both read and write.
+ */
+ switch (interlace_type)
+ {
+ case PNG_INTERLACE_NONE:
+ num_passes = 1;
+ break;
+
+ case PNG_INTERLACE_ADAM7:
+ num_passes = 7;
+ break;
+
+ default:
+ png_error(read_ptr, "invalid interlace type");
+ /*NOT REACHED*/
+ }
}
+
+ else
+ png_error(read_ptr, "png_get_IHDR failed");
}
-#if defined(PNG_FIXED_POINT_SUPPORTED)
-#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FIXED_POINT_SUPPORTED
+#ifdef PNG_cHRM_SUPPORTED
{
png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
- blue_y;
- if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
- &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ blue_y;
+
+ if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
+ &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
{
png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
- red_y, green_x, green_y, blue_x, blue_y);
+ red_y, green_x, green_y, blue_x, blue_y);
}
}
#endif
-#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_gAMA_SUPPORTED
{
png_fixed_point gamma;
- if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
- {
+ if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0)
png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
- }
}
#endif
#else /* Use floating point versions */
-#if defined(PNG_FLOATING_POINT_SUPPORTED)
-#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_cHRM_SUPPORTED
{
double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
- blue_y;
+ blue_y;
+
if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
- &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
{
png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
- red_y, green_x, green_y, blue_x, blue_y);
+ red_y, green_x, green_y, blue_x, blue_y);
}
}
#endif
-#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_gAMA_SUPPORTED
{
double gamma;
- if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
- {
+ if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0)
png_set_gAMA(write_ptr, write_info_ptr, gamma);
- }
}
#endif
-#endif /* floating point */
-#endif /* fixed point */
-#if defined(PNG_iCCP_SUPPORTED)
+#endif /* Floating point */
+#endif /* Fixed point */
+#ifdef PNG_iCCP_SUPPORTED
{
png_charp name;
- png_charp profile;
+ png_bytep profile;
png_uint_32 proflen;
int compression_type;
if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
- &profile, &proflen))
+ &profile, &proflen) != 0)
{
png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
- profile, proflen);
+ profile, proflen);
}
}
#endif
-#if defined(PNG_sRGB_SUPPORTED)
+#ifdef PNG_sRGB_SUPPORTED
{
int intent;
- if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
- {
+ if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
png_set_sRGB(write_ptr, write_info_ptr, intent);
- }
}
#endif
{
png_colorp palette;
int num_palette;
- if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
- {
+ if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
- }
}
-#if defined(PNG_bKGD_SUPPORTED)
+#ifdef PNG_bKGD_SUPPORTED
{
png_color_16p background;
- if (png_get_bKGD(read_ptr, read_info_ptr, &background))
- {
+ if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
png_set_bKGD(write_ptr, write_info_ptr, background);
+ }
+#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+ {
+ png_bytep exif = NULL;
+ png_uint_32 exif_length;
+
+ if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0)
+ {
+ if (exif_length > 1)
+ fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1],
+ (unsigned long)exif_length);
+# ifdef PNG_WRITE_eXIf_SUPPORTED
+ png_set_eXIf_1(write_ptr, write_info_ptr, exif_length, exif);
+# endif
}
}
#endif
-#if defined(PNG_hIST_SUPPORTED)
+#ifdef PNG_hIST_SUPPORTED
{
png_uint_16p hist;
- if (png_get_hIST(read_ptr, read_info_ptr, &hist))
- {
+ if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
png_set_hIST(write_ptr, write_info_ptr, hist);
- }
}
#endif
-#if defined(PNG_oFFs_SUPPORTED)
+#ifdef PNG_oFFs_SUPPORTED
{
png_int_32 offset_x, offset_y;
int unit_type;
- if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
- {
+ if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
+ &unit_type) != 0)
png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
- }
}
#endif
-#if defined(PNG_pCAL_SUPPORTED)
+#ifdef PNG_pCAL_SUPPORTED
{
png_charp purpose, units;
png_charpp params;
@@ -928,45 +1248,39 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
int type, nparams;
if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
- &nparams, &units, ¶ms))
- {
+ &nparams, &units, ¶ms) != 0)
png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
- nparams, units, params);
- }
+ nparams, units, params);
}
#endif
-#if defined(PNG_pHYs_SUPPORTED)
+#ifdef PNG_pHYs_SUPPORTED
{
png_uint_32 res_x, res_y;
int unit_type;
- if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
- {
+ if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
+ &unit_type) != 0)
png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
- }
}
#endif
-#if defined(PNG_sBIT_SUPPORTED)
+#ifdef PNG_sBIT_SUPPORTED
{
png_color_8p sig_bit;
- if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
- {
+ if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
- }
}
#endif
-#if defined(PNG_sCAL_SUPPORTED)
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_sCAL_SUPPORTED
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
+ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
{
int unit;
double scal_width, scal_height;
if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
- &scal_height))
- {
+ &scal_height) != 0)
png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
- }
}
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
@@ -975,125 +1289,188 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
png_charp scal_width, scal_height;
if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
- &scal_height))
+ &scal_height) != 0)
{
- png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
+ png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
+ scal_height);
}
}
#endif
#endif
#endif
-#if defined(PNG_TEXT_SUPPORTED)
+
+#ifdef PNG_sPLT_SUPPORTED
+ {
+ png_sPLT_tp entries;
+
+ int num_entries = png_get_sPLT(read_ptr, read_info_ptr, &entries);
+ if (num_entries != 0)
+ png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries);
+ }
+#endif
+
+#ifdef PNG_TEXT_SUPPORTED
{
png_textp text_ptr;
int num_text;
if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
{
- png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
+ pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
+
+ pngtest_check_text_support(read_ptr, text_ptr, num_text);
+
+ if (verbose != 0)
+ {
+ int i;
+
+ fprintf(STDERR,"\n");
+ for (i = 0; i < num_text; i++)
+ {
+ fprintf(STDERR," Text compression[%d]=%d\n",
+ i, text_ptr[i].compression);
+ }
+ }
+
png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
}
}
#endif
-#if defined(PNG_tIME_SUPPORTED)
+#ifdef PNG_tIME_SUPPORTED
{
png_timep mod_time;
- if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
+ if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
{
png_set_tIME(write_ptr, write_info_ptr, mod_time);
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- /* we have to use png_memcpy instead of "=" because the string
- pointed to by png_convert_to_rfc1123() gets free'ed before
- we use it */
- png_memcpy(tIME_string,
- png_convert_to_rfc1123(read_ptr, mod_time),
- png_sizeof(tIME_string));
- tIME_string[png_sizeof(tIME_string)-1] = '\0';
- tIME_chunk_present++;
-#endif /* PNG_TIME_RFC1123_SUPPORTED */
- }
- }
-#endif
-#if defined(PNG_tRNS_SUPPORTED)
- {
- png_bytep trans;
- int num_trans;
- png_color_16p trans_values;
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+ if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
+ tIME_string[(sizeof tIME_string) - 1] = '\0';
- if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
- &trans_values))
- {
- png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
- trans_values);
+ else
+ {
+ strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
+ tIME_string[(sizeof tIME_string) - 1] = '\0';
+ }
+
+ tIME_chunk_present++;
+#endif /* TIME_RFC1123 */
}
}
#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+#ifdef PNG_tRNS_SUPPORTED
+ {
+ png_bytep trans_alpha;
+ int num_trans;
+ png_color_16p trans_color;
+
+ if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
+ &trans_color) != 0)
+ {
+ int sample_max = (1 << bit_depth);
+ /* libpng doesn't reject a tRNS chunk with out-of-range samples */
+ if (!((color_type == PNG_COLOR_TYPE_GRAY &&
+ (int)trans_color->gray > sample_max) ||
+ (color_type == PNG_COLOR_TYPE_RGB &&
+ ((int)trans_color->red > sample_max ||
+ (int)trans_color->green > sample_max ||
+ (int)trans_color->blue > sample_max))))
+ png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
+ trans_color);
+ }
+ }
+#endif
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
{
png_unknown_chunkp unknowns;
- int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
- &unknowns);
- if (num_unknowns)
- {
- png_size_t i;
+ int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
+ &unknowns);
+
+ if (num_unknowns != 0)
png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
- num_unknowns);
- /* copy the locations from the read_info_ptr. The automatically
- generated locations in write_info_ptr are wrong because we
- haven't written anything yet */
- for (i = 0; i < (png_size_t)num_unknowns; i++)
- png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
- unknowns[i].location);
- }
+ num_unknowns);
}
#endif
#ifdef PNG_WRITE_SUPPORTED
- png_debug(0, "\nWriting info struct\n");
+ pngtest_debug("Writing info struct");
-/* If we wanted, we could write info in two steps:
+ /* Write the info in two steps so that if we write the 'unknown' chunks here
+ * they go to the correct place.
+ */
png_write_info_before_PLTE(write_ptr, write_info_ptr);
- */
+
+ write_chunks(write_ptr, &my_user_chunk_data, before_PLTE); /* before PLTE */
+
png_write_info(write_ptr, write_info_ptr);
+
+ write_chunks(write_ptr, &my_user_chunk_data, before_IDAT); /* after PLTE */
+
+ png_write_info(write_ptr, write_end_info_ptr);
+
+ write_chunks(write_ptr, &my_user_chunk_data, after_IDAT); /* after IDAT */
+
+#ifdef PNG_COMPRESSION_COMPAT
+ /* Test the 'compatibility' setting here, if it is available. */
+ png_set_compression(write_ptr, PNG_COMPRESSION_COMPAT);
+#endif
#endif
-#ifdef SINGLE_ROWBUF_ALLOC
- png_debug(0, "\nAllocating row buffer...");
- row_buf = (png_bytep)png_malloc(read_ptr,
- png_get_rowbytes(read_ptr, read_info_ptr));
- png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
-#endif /* SINGLE_ROWBUF_ALLOC */
- png_debug(0, "Writing row data\n");
+ pngtest_debug("Writing row data");
-#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
- defined(PNG_WRITE_INTERLACING_SUPPORTED)
- num_pass = png_set_interlace_handling(read_ptr);
-# ifdef PNG_WRITE_SUPPORTED
- png_set_interlace_handling(write_ptr);
-# endif
-#else
- num_pass=1;
-#endif
+#if defined(PNG_READ_INTERLACING_SUPPORTED) &&\
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* Both must be defined for libpng to be able to handle the interlace,
+ * otherwise it gets handled below by simply reading and writing the passes
+ * directly.
+ */
+ if (png_set_interlace_handling(read_ptr) != num_passes)
+ png_error(write_ptr,
+ "png_set_interlace_handling(read): wrong pass count ");
+ if (png_set_interlace_handling(write_ptr) != num_passes)
+ png_error(write_ptr,
+ "png_set_interlace_handling(write): wrong pass count ");
+#else /* png_set_interlace_handling not called on either read or write */
+# define calc_pass_height
+#endif /* not using libpng interlace handling */
#ifdef PNGTEST_TIMING
t_stop = (float)clock();
t_misc += (t_stop - t_start);
t_start = t_stop;
#endif
- for (pass = 0; pass < num_pass; pass++)
+ for (pass = 0; pass < num_passes; pass++)
{
- png_debug1(0, "Writing row data for pass %d\n",pass);
- for (y = 0; y < height; y++)
+# ifdef calc_pass_height
+ png_uint_32 pass_height;
+
+ if (num_passes == 7) /* interlaced */
+ {
+ if (PNG_PASS_COLS(width, pass) > 0)
+ pass_height = PNG_PASS_ROWS(height, pass);
+
+ else
+ pass_height = 0;
+ }
+
+ else /* not interlaced */
+ pass_height = height;
+# else
+# define pass_height height
+# endif
+
+ pngtest_debug1("Writing row data for pass %d", pass);
+ for (y = 0; y < pass_height; y++)
{
-#ifndef SINGLE_ROWBUF_ALLOC
- png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y);
+ pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
+
row_buf = (png_bytep)png_malloc(read_ptr,
- png_get_rowbytes(read_ptr, read_info_ptr));
- png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
- png_get_rowbytes(read_ptr, read_info_ptr));
-#endif /* !SINGLE_ROWBUF_ALLOC */
- png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1);
+ png_get_rowbytes(read_ptr, read_info_ptr));
+
+ pngtest_debug2("\t%p (%lu bytes)", row_buf,
+ (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
+
+ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
#ifdef PNG_WRITE_SUPPORTED
#ifdef PNGTEST_TIMING
@@ -1107,200 +1484,291 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
t_encode += (t_stop - t_start);
t_start = t_stop;
#endif
-#endif /* PNG_WRITE_SUPPORTED */
+#endif /* WRITE */
-#ifndef SINGLE_ROWBUF_ALLOC
- png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y);
+ pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
png_free(read_ptr, row_buf);
-#endif /* !SINGLE_ROWBUF_ALLOC */
+ row_buf = NULL;
}
}
-#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
- png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
-#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
- png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+# ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
+# endif
+# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
+# endif
#endif
- png_debug(0, "Reading and writing end_info data\n");
+ pngtest_debug("Reading and writing end_info data");
png_read_end(read_ptr, end_info_ptr);
-#if defined(PNG_TEXT_SUPPORTED)
+#ifdef PNG_TEXT_SUPPORTED
{
png_textp text_ptr;
int num_text;
if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
{
- png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
+ pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
+
+ pngtest_check_text_support(read_ptr, text_ptr, num_text);
+
+ if (verbose != 0)
+ {
+ int i;
+
+ fprintf(STDERR,"\n");
+ for (i = 0; i < num_text; i++)
+ {
+ fprintf(STDERR," Text compression[%d]=%d\n",
+ i, text_ptr[i].compression);
+ }
+ }
+
png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
}
}
#endif
-#if defined(PNG_tIME_SUPPORTED)
+#ifdef PNG_READ_eXIf_SUPPORTED
+ {
+ png_bytep exif = NULL;
+ png_uint_32 exif_length;
+
+ if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0)
+ {
+ if (exif_length > 1)
+ fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1],
+ (unsigned long)exif_length);
+# ifdef PNG_WRITE_eXIf_SUPPORTED
+ png_set_eXIf_1(write_ptr, write_end_info_ptr, exif_length, exif);
+# endif
+ }
+ }
+#endif
+#ifdef PNG_tIME_SUPPORTED
{
png_timep mod_time;
- if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
+ if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
{
png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- /* we have to use png_memcpy instead of "=" because the string
- pointed to by png_convert_to_rfc1123() gets free'ed before
- we use it */
- png_memcpy(tIME_string,
- png_convert_to_rfc1123(read_ptr, mod_time),
- png_sizeof(tIME_string));
- tIME_string[png_sizeof(tIME_string)-1] = '\0';
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+ if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
+ tIME_string[(sizeof tIME_string) - 1] = '\0';
+
+ else
+ {
+ strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
+ tIME_string[(sizeof tIME_string)-1] = '\0';
+ }
+
tIME_chunk_present++;
-#endif /* PNG_TIME_RFC1123_SUPPORTED */
+#endif /* TIME_RFC1123 */
}
}
#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
{
png_unknown_chunkp unknowns;
- int num_unknowns;
- num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
- &unknowns);
- if (num_unknowns)
- {
- png_size_t i;
+ int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
+ &unknowns);
+
+ if (num_unknowns != 0)
png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
- num_unknowns);
- /* copy the locations from the read_info_ptr. The automatically
- generated locations in write_end_info_ptr are wrong because we
- haven't written the end_info yet */
- for (i = 0; i < (png_size_t)num_unknowns; i++)
- png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
- unknowns[i].location);
- }
+ num_unknowns);
}
#endif
+
#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+ /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
+ * This is here just to make pngtest replicate the results from libpng
+ * versions prior to 1.5.4, and to test this new API.
+ */
+ png_set_text_compression_strategy(write_ptr, Z_FILTERED);
+#endif
+
+ /* When the unknown vpAg/sTER chunks are written by pngtest the only way to
+ * do it is to write them *before* calling png_write_end. When unknown
+ * chunks are written by libpng, however, they are written just before IEND.
+ * There seems to be no way round this, however vpAg/sTER are not expected
+ * after IDAT.
+ */
+ write_chunks(write_ptr, &my_user_chunk_data, after_IDAT);
+
png_write_end(write_ptr, write_end_info_ptr);
#endif
#ifdef PNG_EASY_ACCESS_SUPPORTED
- if(verbose)
+ if (verbose != 0)
{
png_uint_32 iwidth, iheight;
iwidth = png_get_image_width(write_ptr, write_info_ptr);
iheight = png_get_image_height(write_ptr, write_info_ptr);
- fprintf(STDERR, "Image width = %lu, height = %lu\n",
- (unsigned long)iwidth, (unsigned long)iheight);
+ fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
+ (unsigned long)iwidth, (unsigned long)iheight);
}
#endif
- png_debug(0, "Destroying data structs\n");
-#ifdef SINGLE_ROWBUF_ALLOC
- png_debug(1, "destroying row_buf for read_ptr\n");
- png_free(read_ptr, row_buf);
- row_buf=NULL;
-#endif /* SINGLE_ROWBUF_ALLOC */
- png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
+ pngtest_debug("Destroying data structs");
+ pngtest_debug("Destroying read_ptr, read_info_ptr, end_info_ptr");
png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
- png_debug(1, "destroying write_end_info_ptr\n");
+ pngtest_debug("Destroying write_end_info_ptr");
png_destroy_info_struct(write_ptr, &write_end_info_ptr);
- png_debug(1, "destroying write_ptr, write_info_ptr\n");
+ pngtest_debug("Destroying write_ptr, write_info_ptr");
png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
- png_debug(0, "Destruction complete.\n");
+ pngtest_debug("Destruction complete.");
- FCLOSE(fpin);
- FCLOSE(fpout);
+ fclose(fpin);
+ fclose(fpout);
- png_debug(0, "Opening files for comparison\n");
-#if defined(_WIN32_WCE)
- MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
- if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
-#else
+ /* Summarize any warnings or errors and in 'strict' mode fail the test.
+ * Unsupported chunks can result in warnings, in that case ignore the strict
+ * setting, otherwise fail the test on warnings as well as errors.
+ */
+ if (error_count > 0)
+ {
+ /* We don't really expect to get here because of the setjmp handling
+ * above, but this is safe.
+ */
+ fprintf(STDERR, "\n %s: %d libpng errors found (%d warnings)",
+ inname, error_count, warning_count);
+
+ if (strict != 0)
+ return 1;
+ }
+
+# ifdef PNG_WRITE_SUPPORTED
+ /* If there is no write support nothing was written! */
+ else if (unsupported_chunks > 0)
+ {
+ fprintf(STDERR, "\n %s: unsupported chunks (%d)%s",
+ inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
+ }
+# endif
+
+ else if (warning_count > 0)
+ {
+ fprintf(STDERR, "\n %s: %d libpng warnings found",
+ inname, warning_count);
+
+ if (strict != 0)
+ return 1;
+ }
+
+ pngtest_debug("Opening files for comparison");
if ((fpin = fopen(inname, "rb")) == NULL)
-#endif
{
fprintf(STDERR, "Could not find file %s\n", inname);
- return (1);
+ return 1;
}
-#if defined(_WIN32_WCE)
- MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
- if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
-#else
if ((fpout = fopen(outname, "rb")) == NULL)
-#endif
{
fprintf(STDERR, "Could not find file %s\n", outname);
- FCLOSE(fpin);
- return (1);
+ fclose(fpin);
+ return 1;
}
- for(;;)
+#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
+ defined (PNG_WRITE_FILTER_SUPPORTED)
+ if (interlace_preserved != 0) /* else the files will be changed */
{
- png_size_t num_in, num_out;
-
- READFILE(fpin, inbuf, 1, num_in);
- READFILE(fpout, outbuf, 1, num_out);
-
- if (num_in != num_out)
+ for (;;)
{
- fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
- inname, outname);
- if(wrote_question == 0)
- {
- fprintf(STDERR,
- " Was %s written with the same maximum IDAT chunk size (%d bytes),",
- inname,PNG_ZBUF_SIZE);
- fprintf(STDERR,
- "\n filtering heuristic (libpng default), compression");
- fprintf(STDERR,
- " level (zlib default),\n and zlib version (%s)?\n\n",
- ZLIB_VERSION);
- wrote_question=1;
- }
- FCLOSE(fpin);
- FCLOSE(fpout);
- return (0);
- }
+ static int wrote_question = 0;
+ size_t num_in, num_out;
+ char inbuf[256], outbuf[256];
- if (!num_in)
- break;
+ num_in = fread(inbuf, 1, sizeof inbuf, fpin);
+ num_out = fread(outbuf, 1, sizeof outbuf, fpout);
- if (png_memcmp(inbuf, outbuf, num_in))
- {
- fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
- if(wrote_question == 0)
+ if (num_in != num_out)
{
- fprintf(STDERR,
- " Was %s written with the same maximum IDAT chunk size (%d bytes),",
- inname,PNG_ZBUF_SIZE);
- fprintf(STDERR,
- "\n filtering heuristic (libpng default), compression");
- fprintf(STDERR,
- " level (zlib default),\n and zlib version (%s)?\n\n",
- ZLIB_VERSION);
- wrote_question=1;
+ fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
+ inname, outname);
+
+ if (wrote_question == 0 && unsupported_chunks == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same maximum IDAT"
+ " chunk size (%d bytes),",
+ inname, PNG_ZBUF_SIZE);
+ fprintf(STDERR,
+ "\n filtering heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default),\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question = 1;
+ }
+
+ fclose(fpin);
+ fclose(fpout);
+
+ if (strict != 0 && unsupported_chunks == 0)
+ return 1;
+
+ else
+ return 0;
+ }
+
+ if (num_in == 0)
+ break;
+
+ if (memcmp(inbuf, outbuf, num_in))
+ {
+ fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
+ outname);
+
+ if (wrote_question == 0 && unsupported_chunks == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same maximum"
+ " IDAT chunk size (%d bytes),",
+ inname, PNG_ZBUF_SIZE);
+ fprintf(STDERR,
+ "\n filtering heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default),\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question = 1;
+ }
+
+ fclose(fpin);
+ fclose(fpout);
+
+ /* NOTE: the unsupported_chunks escape is permitted here because
+ * unsupported text chunk compression will result in the compression
+ * mode being changed (to NONE) yet, in the test case, the result
+ * can be exactly the same size!
+ */
+ if (strict != 0 && unsupported_chunks == 0)
+ return 1;
+
+ else
+ return 0;
}
- FCLOSE(fpin);
- FCLOSE(fpout);
- return (0);
}
}
+#endif /* WRITE && WRITE_FILTER */
- FCLOSE(fpin);
- FCLOSE(fpout);
+ fclose(fpin);
+ fclose(fpout);
- return (0);
+ return 0;
}
-/* input and output filenames */
+/* Input and output filenames */
#ifdef RISCOS
-static PNG_CONST char *inname = "pngtest/png";
-static PNG_CONST char *outname = "pngout/png";
+static const char *inname = "pngtest/png";
+static const char *outname = "pngout/png";
#else
-static PNG_CONST char *inname = "pngtest.png";
-static PNG_CONST char *outname = "pngout.png";
+static const char *inname = "pngtest.png";
+static const char *outname = "pngout.png";
#endif
int
@@ -1309,23 +1777,25 @@ main(int argc, char *argv[])
int multiple = 0;
int ierror = 0;
- fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
+ png_structp dummy_ptr;
+
+ fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
- fprintf(STDERR,"%s",png_get_copyright(NULL));
+ fprintf(STDERR, "%s", png_get_copyright(NULL));
/* Show the version of libpng used in building the library */
- fprintf(STDERR," library (%lu):%s",
- (unsigned long)png_access_version_number(),
- png_get_header_version(NULL));
+ fprintf(STDERR, " library (%lu):%s",
+ (unsigned long)png_access_version_number(),
+ png_get_header_version(NULL));
+
/* Show the version of libpng used in building the application */
- fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
- PNG_HEADER_VERSION_STRING);
- fprintf(STDERR," png_sizeof(png_struct)=%ld, png_sizeof(png_info)=%ld\n",
- (long)png_sizeof(png_struct), (long)png_sizeof(png_info));
+ fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
+ PNG_HEADER_VERSION_STRING);
/* Do some consistency checking on the memory allocation settings, I'm
- not sure this matters, but it is nice to know, the first of these
- tests should be impossible because of the way the macros are set
- in pngconf.h */
+ * not sure this matters, but it is nice to know, the first of these
+ * tests should be impossible because of the way the macros are set
+ * in pngconf.h
+ */
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
#endif
@@ -1334,12 +1804,11 @@ main(int argc, char *argv[])
fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
#endif
- if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
+ if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING) != 0)
{
- fprintf(STDERR,
- "Warning: versions are different between png.h and png.c\n");
- fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
- fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
+ fprintf(STDERR, "Warning: mismatching versions of png.h and png.c\n");
+ fprintf(STDERR, " png.h version string: %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " png.c version string: %s\n\n", png_libpng_ver);
++ierror;
}
@@ -1350,6 +1819,7 @@ main(int argc, char *argv[])
multiple = 1;
status_dots_requested = 0;
}
+
else if (strcmp(argv[1], "-mv") == 0 ||
strcmp(argv[1], "-vm") == 0 )
{
@@ -1357,12 +1827,44 @@ main(int argc, char *argv[])
verbose = 1;
status_dots_requested = 1;
}
+
else if (strcmp(argv[1], "-v") == 0)
{
verbose = 1;
status_dots_requested = 1;
inname = argv[2];
}
+
+ else if (strcmp(argv[1], "--strict") == 0)
+ {
+ status_dots_requested = 0;
+ verbose = 1;
+ inname = argv[2];
+ strict++;
+ relaxed = 0;
+ multiple = 1;
+ }
+
+ else if (strcmp(argv[1], "--relaxed") == 0)
+ {
+ status_dots_requested = 0;
+ verbose = 1;
+ inname = argv[2];
+ strict = 0;
+ relaxed++;
+ multiple = 1;
+ }
+ else if (strcmp(argv[1], "--xfail") == 0)
+ {
+ status_dots_requested = 0;
+ verbose = 1;
+ inname = argv[2];
+ strict = 0;
+ xfail++;
+ relaxed++;
+ multiple = 1;
+ }
+
else
{
inname = argv[1];
@@ -1370,74 +1872,79 @@ main(int argc, char *argv[])
}
}
- if (!multiple && argc == 3+verbose)
- outname = argv[2+verbose];
+ if (multiple == 0 && argc == 3 + verbose)
+ outname = argv[2 + verbose];
- if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
+ if ((multiple == 0 && argc > 3 + verbose) ||
+ (multiple != 0 && argc < 2))
{
- fprintf(STDERR,
- "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
- argv[0], argv[0]);
- fprintf(STDERR,
- " reads/writes one PNG file (without -m) or multiple files (-m)\n");
- fprintf(STDERR,
- " with -m %s is used as a temporary file\n", outname);
- exit(1);
+ fprintf(STDERR,
+ "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
+ argv[0], argv[0]);
+ fprintf(STDERR,
+ " reads/writes one PNG file (without -m) or multiple files (-m)\n");
+ fprintf(STDERR,
+ " with -m %s is used as a temporary file\n", outname);
+ exit(1);
}
- if (multiple)
+ if (multiple != 0)
{
int i;
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
int allocation_now = current_allocation;
#endif
- for (i=2; i 0
+ fprintf(STDERR, "\n");
+#endif
kerror = test_one_file(argv[i], outname);
if (kerror == 0)
{
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
fprintf(STDERR, "\n PASS (%lu zero samples)\n",
- (unsigned long)zero_samples);
+ (unsigned long)zero_samples);
#else
fprintf(STDERR, " PASS\n");
#endif
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- for (k=0; k<256; k++)
- if(filters_used[k])
- fprintf(STDERR, " Filter %d was used %lu times\n",
- k,(unsigned long)filters_used[k]);
-#endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- if(tIME_chunk_present != 0)
- fprintf(STDERR, " tIME = %s\n",tIME_string);
- tIME_chunk_present = 0;
-#endif /* PNG_TIME_RFC1123_SUPPORTED */
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+ if (tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n", tIME_string);
+
+ tIME_chunk_present = 0;
+#endif /* TIME_RFC1123 */
}
+
else
{
- fprintf(STDERR, " FAIL\n");
- ierror += kerror;
+ if (xfail)
+ fprintf(STDERR, " XFAIL\n");
+ else
+ {
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
}
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
if (allocation_now != current_allocation)
fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
- current_allocation-allocation_now);
+ current_allocation - allocation_now);
+
if (current_allocation != 0)
{
memory_infop pinfo = pinformation;
fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
- current_allocation);
+ current_allocation);
+
while (pinfo != NULL)
{
- fprintf(STDERR, " %lu bytes at %x\n", (unsigned long)pinfo->size,
- (unsigned int) pinfo->pointer);
+ fprintf(STDERR, " %lu bytes at %p\n",
+ (unsigned long)pinfo->size,
+ pinfo->pointer);
pinfo = pinfo->next;
}
}
@@ -1445,75 +1952,92 @@ main(int argc, char *argv[])
}
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
fprintf(STDERR, " Current memory allocation: %10d bytes\n",
- current_allocation);
+ current_allocation);
fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
- maximum_allocation);
+ maximum_allocation);
fprintf(STDERR, " Total memory allocation: %10d bytes\n",
- total_allocation);
+ total_allocation);
fprintf(STDERR, " Number of allocations: %10d\n",
- num_allocations);
+ num_allocations);
#endif
}
+
else
{
int i;
- for (i=0; i<3; ++i)
+ for (i = 0; i < 3; ++i)
{
int kerror;
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
int allocation_now = current_allocation;
#endif
- if (i == 1) status_dots_requested = 1;
- else if(verbose == 0)status_dots_requested = 0;
+ if (i == 1)
+ status_dots_requested = 1;
+
+ else if (verbose == 0)
+ status_dots_requested = 0;
+
if (i == 0 || verbose == 1 || ierror != 0)
- fprintf(STDERR, "Testing %s:",inname);
- kerror = test_one_file(inname, outname);
- if(kerror == 0)
{
- if(verbose == 1 || i == 2)
- {
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- int k;
+ fprintf(STDERR, "\n Testing %s:", inname);
+#if PNG_DEBUG > 0
+ fprintf(STDERR, "\n");
#endif
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ }
+
+ kerror = test_one_file(inname, outname);
+
+ if (kerror == 0)
+ {
+ if (verbose == 1 || i == 2)
+ {
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
fprintf(STDERR, "\n PASS (%lu zero samples)\n",
- (unsigned long)zero_samples);
+ (unsigned long)zero_samples);
#else
fprintf(STDERR, " PASS\n");
#endif
-#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
- for (k=0; k<256; k++)
- if(filters_used[k])
- fprintf(STDERR, " Filter %d was used %lu times\n",
- k,(unsigned long)filters_used[k]);
-#endif
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- if(tIME_chunk_present != 0)
- fprintf(STDERR, " tIME = %s\n",tIME_string);
-#endif /* PNG_TIME_RFC1123_SUPPORTED */
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+ if (tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n", tIME_string);
+#endif /* TIME_RFC1123 */
}
}
+
else
{
- if(verbose == 0 && i != 2)
- fprintf(STDERR, "Testing %s:",inname);
- fprintf(STDERR, " FAIL\n");
- ierror += kerror;
+ if (verbose == 0 && i != 2)
+ {
+ fprintf(STDERR, "\n Testing %s:", inname);
+#if PNG_DEBUG > 0
+ fprintf(STDERR, "\n");
+#endif
+ }
+
+ if (xfail)
+ fprintf(STDERR, " XFAIL\n");
+ else
+ {
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
}
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
if (allocation_now != current_allocation)
fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
- current_allocation-allocation_now);
+ current_allocation - allocation_now);
+
if (current_allocation != 0)
{
memory_infop pinfo = pinformation;
fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
- current_allocation);
+ current_allocation);
+
while (pinfo != NULL)
{
- fprintf(STDERR," %lu bytes at %x\n",
- (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
+ fprintf(STDERR, " %lu bytes at %p\n",
+ (unsigned long)pinfo->size, pinfo->pointer);
pinfo = pinfo->next;
}
}
@@ -1521,13 +2045,13 @@ main(int argc, char *argv[])
}
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
fprintf(STDERR, " Current memory allocation: %10d bytes\n",
- current_allocation);
+ current_allocation);
fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
- maximum_allocation);
+ maximum_allocation);
fprintf(STDERR, " Total memory allocation: %10d bytes\n",
- total_allocation);
+ total_allocation);
fprintf(STDERR, " Number of allocations: %10d\n",
- num_allocations);
+ num_allocations);
#endif
}
@@ -1535,22 +2059,49 @@ main(int argc, char *argv[])
t_stop = (float)clock();
t_misc += (t_stop - t_start);
t_start = t_stop;
- fprintf(STDERR," CPU time used = %.3f seconds",
- (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
- fprintf(STDERR," (decoding %.3f,\n",
- t_decode/(float)CLOCKS_PER_SEC);
- fprintf(STDERR," encoding %.3f ,",
- t_encode/(float)CLOCKS_PER_SEC);
- fprintf(STDERR," other %.3f seconds)\n\n",
- t_misc/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR, " CPU time used = %.3f seconds",
+ (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR, " (decoding %.3f,\n",
+ t_decode/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR, " encoding %.3f ,",
+ t_encode/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR, " other %.3f seconds)\n\n",
+ t_misc/(float)CLOCKS_PER_SEC);
#endif
if (ierror == 0)
- fprintf(STDERR, "libpng passes test\n");
- else
- fprintf(STDERR, "libpng FAILS test\n");
- return (int)(ierror != 0);
-}
+ fprintf(STDERR, " libpng passes test\n");
-/* Generate a compiler error if there is an old png.h in the search path. */
-typedef version_1_2_24 your_png_h_is_not_version_1_2_24;
+ else
+ fprintf(STDERR, " libpng FAILS test\n");
+
+ dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ fprintf(STDERR, " Default limits:\n");
+ fprintf(STDERR, " width_max = %lu\n",
+ (unsigned long) png_get_user_width_max(dummy_ptr));
+ fprintf(STDERR, " height_max = %lu\n",
+ (unsigned long) png_get_user_height_max(dummy_ptr));
+ if (png_get_chunk_cache_max(dummy_ptr) == 0)
+ fprintf(STDERR, " cache_max = unlimited\n");
+ else
+ fprintf(STDERR, " cache_max = %lu\n",
+ (unsigned long) png_get_chunk_cache_max(dummy_ptr));
+ if (png_get_chunk_malloc_max(dummy_ptr) == 0)
+ fprintf(STDERR, " malloc_max = unlimited\n");
+ else
+ fprintf(STDERR, " malloc_max = %lu\n",
+ (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
+ png_destroy_read_struct(&dummy_ptr, NULL, NULL);
+
+ return (ierror != 0);
+}
+#else
+int
+main(void)
+{
+ fprintf(STDERR,
+ " test ignored because libpng was not built with read support\n");
+ /* And skip this test */
+ return SKIP;
+}
+#endif
diff --git a/PDF/src/pngtrans.c b/PDF/src/pngtrans.c
index 164009502..62cb21edf 100644
--- a/PDF/src/pngtrans.c
+++ b/PDF/src/pngtrans.c
@@ -1,62 +1,79 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Last changed in libpng 1.2.17 May 15, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-/* turn on BGR-to-RGB mapping */
+/* Turn on BGR-to-RGB mapping */
void PNGAPI
-png_set_bgr(png_structp png_ptr)
+png_set_bgr(png_structrp png_ptr)
{
- png_debug(1, "in png_set_bgr\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_bgr");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->transformations |= PNG_BGR;
}
#endif
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
-/* turn on 16 bit byte swapping */
+/* Turn on 16-bit byte swapping */
void PNGAPI
-png_set_swap(png_structp png_ptr)
+png_set_swap(png_structrp png_ptr)
{
- png_debug(1, "in png_set_swap\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_swap");
+
+ if (png_ptr == NULL)
+ return;
+
if (png_ptr->bit_depth == 16)
png_ptr->transformations |= PNG_SWAP_BYTES;
}
#endif
#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
-/* turn on pixel packing */
+/* Turn on pixel packing */
void PNGAPI
-png_set_packing(png_structp png_ptr)
+png_set_packing(png_structrp png_ptr)
{
- png_debug(1, "in png_set_packing\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_packing");
+
+ if (png_ptr == NULL)
+ return;
+
if (png_ptr->bit_depth < 8)
{
png_ptr->transformations |= PNG_PACK;
- png_ptr->usr_bit_depth = 8;
+# ifdef PNG_WRITE_SUPPORTED
+ png_ptr->usr_bit_depth = 8;
+# endif
}
}
#endif
#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
-/* turn on packed pixel swapping */
+/* Turn on packed pixel swapping */
void PNGAPI
-png_set_packswap(png_structp png_ptr)
+png_set_packswap(png_structrp png_ptr)
{
- png_debug(1, "in png_set_packswap\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_packswap");
+
+ if (png_ptr == NULL)
+ return;
+
if (png_ptr->bit_depth < 8)
png_ptr->transformations |= PNG_PACKSWAP;
}
@@ -64,10 +81,13 @@ png_set_packswap(png_structp png_ptr)
#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
void PNGAPI
-png_set_shift(png_structp png_ptr, png_color_8p true_bits)
+png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)
{
- png_debug(1, "in png_set_shift\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_shift");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->transformations |= PNG_SHIFT;
png_ptr->shift = *true_bits;
}
@@ -76,16 +96,17 @@ png_set_shift(png_structp png_ptr, png_color_8p true_bits)
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
defined(PNG_WRITE_INTERLACING_SUPPORTED)
int PNGAPI
-png_set_interlace_handling(png_structp png_ptr)
+png_set_interlace_handling(png_structrp png_ptr)
{
- png_debug(1, "in png_set_interlace handling\n");
- if (png_ptr && png_ptr->interlaced)
+ png_debug(1, "in png_set_interlace handling");
+
+ if (png_ptr != 0 && png_ptr->interlaced != 0)
{
png_ptr->transformations |= PNG_INTERLACE;
- return (7);
+ return 7;
}
- return (1);
+ return 1;
}
#endif
@@ -96,57 +117,116 @@ png_set_interlace_handling(png_structp png_ptr)
* that don't like bytes as parameters.
*/
void PNGAPI
-png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc)
{
- png_debug(1, "in png_set_filler\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_filler");
+
+ if (png_ptr == NULL)
+ return;
+
+ /* In libpng 1.6 it is possible to determine whether this is a read or write
+ * operation and therefore to do more checking here for a valid call.
+ */
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
+ {
+# ifdef PNG_READ_FILLER_SUPPORTED
+ /* On read png_set_filler is always valid, regardless of the base PNG
+ * format, because other transformations can give a format where the
+ * filler code can execute (basically an 8 or 16-bit component RGB or G
+ * format.)
+ *
+ * NOTE: usr_channels is not used by the read code! (This has led to
+ * confusion in the past.) The filler is only used in the read code.
+ */
+ png_ptr->filler = (png_uint_16)filler;
+# else
+ png_app_error(png_ptr, "png_set_filler not supported on read");
+ PNG_UNUSED(filler) /* not used in the write case */
+ return;
+# endif
+ }
+
+ else /* write */
+ {
+# ifdef PNG_WRITE_FILLER_SUPPORTED
+ /* On write the usr_channels parameter must be set correctly at the
+ * start to record the number of channels in the app-supplied data.
+ */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ png_ptr->usr_channels = 4;
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ if (png_ptr->bit_depth >= 8)
+ {
+ png_ptr->usr_channels = 2;
+ break;
+ }
+
+ else
+ {
+ /* There simply isn't any code in libpng to strip out bits
+ * from bytes when the components are less than a byte in
+ * size!
+ */
+ png_app_error(png_ptr,
+ "png_set_filler is invalid for"
+ " low bit depth gray output");
+ return;
+ }
+
+ default:
+ png_app_error(png_ptr,
+ "png_set_filler: inappropriate color type");
+ return;
+ }
+# else
+ png_app_error(png_ptr, "png_set_filler not supported on write");
+ return;
+# endif
+ }
+
+ /* Here on success - libpng supports the operation, set the transformation
+ * and the flag to say where the filler channel is.
+ */
png_ptr->transformations |= PNG_FILLER;
- png_ptr->filler = (png_byte)filler;
+
if (filler_loc == PNG_FILLER_AFTER)
png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
+
else
png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
-
- /* This should probably go in the "do_read_filler" routine.
- * I attempted to do that in libpng-1.0.1a but that caused problems
- * so I restored it in libpng-1.0.2a
- */
-
- if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
- {
- png_ptr->usr_channels = 4;
- }
-
- /* Also I added this in libpng-1.0.2a (what happens when we expand
- * a less-than-8-bit grayscale to GA? */
-
- if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
- {
- png_ptr->usr_channels = 2;
- }
}
-#if !defined(PNG_1_0_X)
/* Added to libpng-1.2.7 */
void PNGAPI
-png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc)
{
- png_debug(1, "in png_set_add_alpha\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_add_alpha");
+
+ if (png_ptr == NULL)
+ return;
+
png_set_filler(png_ptr, filler, filler_loc);
- png_ptr->transformations |= PNG_ADD_ALPHA;
+ /* The above may fail to do anything. */
+ if ((png_ptr->transformations & PNG_FILLER) != 0)
+ png_ptr->transformations |= PNG_ADD_ALPHA;
}
-#endif
#endif
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
void PNGAPI
-png_set_swap_alpha(png_structp png_ptr)
+png_set_swap_alpha(png_structrp png_ptr)
{
- png_debug(1, "in png_set_swap_alpha\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_swap_alpha");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->transformations |= PNG_SWAP_ALPHA;
}
#endif
@@ -154,40 +234,43 @@ png_set_swap_alpha(png_structp png_ptr)
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
void PNGAPI
-png_set_invert_alpha(png_structp png_ptr)
+png_set_invert_alpha(png_structrp png_ptr)
{
- png_debug(1, "in png_set_invert_alpha\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_invert_alpha");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->transformations |= PNG_INVERT_ALPHA;
}
#endif
#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
void PNGAPI
-png_set_invert_mono(png_structp png_ptr)
+png_set_invert_mono(png_structrp png_ptr)
{
- png_debug(1, "in png_set_invert_mono\n");
- if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_invert_mono");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->transformations |= PNG_INVERT_MONO;
}
-/* invert monochrome grayscale data */
+/* Invert monochrome grayscale data */
void /* PRIVATE */
png_do_invert(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_invert\n");
+ png_debug(1, "in png_do_invert");
+
/* This test removed from libpng version 1.0.13 and 1.2.0:
* if (row_info->bit_depth == 1 &&
*/
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row == NULL || row_info == NULL)
- return;
-#endif
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
png_bytep rp = row;
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
+ size_t i;
+ size_t istop = row_info->rowbytes;
for (i = 0; i < istop; i++)
{
@@ -195,47 +278,49 @@ png_do_invert(png_row_infop row_info, png_bytep row)
rp++;
}
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 8)
{
png_bytep rp = row;
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
+ size_t i;
+ size_t istop = row_info->rowbytes;
- for (i = 0; i < istop; i+=2)
+ for (i = 0; i < istop; i += 2)
{
*rp = (png_byte)(~(*rp));
- rp+=2;
+ rp += 2;
}
}
+
+#ifdef PNG_16BIT_SUPPORTED
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 16)
{
png_bytep rp = row;
- png_uint_32 i;
- png_uint_32 istop = row_info->rowbytes;
+ size_t i;
+ size_t istop = row_info->rowbytes;
- for (i = 0; i < istop; i+=4)
+ for (i = 0; i < istop; i += 4)
{
*rp = (png_byte)(~(*rp));
- *(rp+1) = (png_byte)(~(*(rp+1)));
- rp+=4;
+ *(rp + 1) = (png_byte)(~(*(rp + 1)));
+ rp += 4;
}
}
+#endif
}
#endif
+#ifdef PNG_16BIT_SUPPORTED
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
-/* swaps byte order on 16 bit depth images */
+/* Swaps byte order on 16-bit depth images */
void /* PRIVATE */
png_do_swap(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_swap\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- row_info->bit_depth == 16)
+ png_debug(1, "in png_do_swap");
+
+ if (row_info->bit_depth == 16)
{
png_bytep rp = row;
png_uint_32 i;
@@ -243,16 +328,24 @@ png_do_swap(png_row_infop row_info, png_bytep row)
for (i = 0; i < istop; i++, rp += 2)
{
+#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED
+ /* Feature added to libpng-1.6.11 for testing purposes, not
+ * enabled by default.
+ */
+ *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp);
+#else
png_byte t = *rp;
*rp = *(rp + 1);
*(rp + 1) = t;
+#endif
}
}
}
#endif
+#endif
#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
-static PNG_CONST png_byte onebppswaptable[256] = {
+static const png_byte onebppswaptable[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
@@ -287,7 +380,7 @@ static PNG_CONST png_byte onebppswaptable[256] = {
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
-static PNG_CONST png_byte twobppswaptable[256] = {
+static const png_byte twobppswaptable[256] = {
0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
@@ -322,7 +415,7 @@ static PNG_CONST png_byte twobppswaptable[256] = {
0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
};
-static PNG_CONST png_byte fourbppswaptable[256] = {
+static const png_byte fourbppswaptable[256] = {
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
@@ -357,27 +450,28 @@ static PNG_CONST png_byte fourbppswaptable[256] = {
0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
};
-/* swaps pixel packing order within bytes */
+/* Swaps pixel packing order within bytes */
void /* PRIVATE */
png_do_packswap(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_packswap\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- row_info->bit_depth < 8)
+ png_debug(1, "in png_do_packswap");
+
+ if (row_info->bit_depth < 8)
{
- png_bytep rp, end, table;
+ png_bytep rp;
+ png_const_bytep end, table;
end = row + row_info->rowbytes;
if (row_info->bit_depth == 1)
- table = (png_bytep)onebppswaptable;
+ table = onebppswaptable;
+
else if (row_info->bit_depth == 2)
- table = (png_bytep)twobppswaptable;
+ table = twobppswaptable;
+
else if (row_info->bit_depth == 4)
- table = (png_bytep)fourbppswaptable;
+ table = fourbppswaptable;
+
else
return;
@@ -385,178 +479,150 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
*rp = table[*rp];
}
}
-#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+#endif /* PACKSWAP || WRITE_PACKSWAP */
#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
-/* remove filler or alpha byte(s) */
+/* Remove a channel - this used to be 'png_do_strip_filler' but it used a
+ * somewhat weird combination of flags to determine what to do. All the calls
+ * to png_do_strip_filler are changed in 1.5.2 to call this instead with the
+ * correct arguments.
+ *
+ * The routine isn't general - the channel must be the channel at the start or
+ * end (not in the middle) of each pixel.
+ */
void /* PRIVATE */
-png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
{
- png_debug(1, "in png_do_strip_filler\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_bytep sp = row; /* source pointer */
+ png_bytep dp = row; /* destination pointer */
+ png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */
+
+ png_debug(1, "in png_do_strip_channel");
+
+ /* At the start sp will point to the first byte to copy and dp to where
+ * it is copied to. ep always points just beyond the end of the row, so
+ * the loop simply copies (channels-1) channels until sp reaches ep.
+ *
+ * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc.
+ * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc.
+ */
+
+ /* GA, GX, XG cases */
+ if (row_info->channels == 2)
{
- png_bytep sp=row;
- png_bytep dp=row;
- png_uint_32 row_width=row_info->width;
- png_uint_32 i;
-
- if ((row_info->color_type == PNG_COLOR_TYPE_RGB ||
- (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
- (flags & PNG_FLAG_STRIP_ALPHA))) &&
- row_info->channels == 4)
+ if (row_info->bit_depth == 8)
{
- if (row_info->bit_depth == 8)
+ if (at_start != 0) /* Skip initial filler */
+ ++sp;
+ else /* Skip initial channel and, for sp, the filler */
{
- /* This converts from RGBX or RGBA to RGB */
- if (flags & PNG_FLAG_FILLER_AFTER)
- {
- dp+=3; sp+=4;
- for (i = 1; i < row_width; i++)
- {
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- sp++;
- }
- }
- /* This converts from XRGB or ARGB to RGB */
- else
- {
- for (i = 0; i < row_width; i++)
- {
- sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- }
- }
- row_info->pixel_depth = 24;
- row_info->rowbytes = row_width * 3;
+ sp += 2; ++dp;
}
- else /* if (row_info->bit_depth == 16) */
+
+ /* For a 1 pixel wide image there is nothing to do */
+ while (sp < ep)
{
- if (flags & PNG_FLAG_FILLER_AFTER)
- {
- /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
- sp += 8; dp += 6;
- for (i = 1; i < row_width; i++)
- {
- /* This could be (although png_memcpy is probably slower):
- png_memcpy(dp, sp, 6);
- sp += 8;
- dp += 6;
- */
-
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- sp += 2;
- }
- }
- else
- {
- /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
- for (i = 0; i < row_width; i++)
- {
- /* This could be (although png_memcpy is probably slower):
- png_memcpy(dp, sp, 6);
- sp += 8;
- dp += 6;
- */
-
- sp+=2;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- *dp++ = *sp++;
- }
- }
- row_info->pixel_depth = 48;
- row_info->rowbytes = row_width * 6;
+ *dp++ = *sp; sp += 2;
}
- row_info->channels = 3;
+
+ row_info->pixel_depth = 8;
}
- else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY ||
- (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
- (flags & PNG_FLAG_STRIP_ALPHA))) &&
- row_info->channels == 2)
+
+ else if (row_info->bit_depth == 16)
{
- if (row_info->bit_depth == 8)
+ if (at_start != 0) /* Skip initial filler */
+ sp += 2;
+ else /* Skip initial channel and, for sp, the filler */
{
- /* This converts from GX or GA to G */
- if (flags & PNG_FLAG_FILLER_AFTER)
- {
- for (i = 0; i < row_width; i++)
- {
- *dp++ = *sp++;
- sp++;
- }
- }
- /* This converts from XG or AG to G */
- else
- {
- for (i = 0; i < row_width; i++)
- {
- sp++;
- *dp++ = *sp++;
- }
- }
- row_info->pixel_depth = 8;
- row_info->rowbytes = row_width;
+ sp += 4; dp += 2;
}
- else /* if (row_info->bit_depth == 16) */
+
+ while (sp < ep)
{
- if (flags & PNG_FLAG_FILLER_AFTER)
- {
- /* This converts from GGXX or GGAA to GG */
- sp += 4; dp += 2;
- for (i = 1; i < row_width; i++)
- {
- *dp++ = *sp++;
- *dp++ = *sp++;
- sp += 2;
- }
- }
- else
- {
- /* This converts from XXGG or AAGG to GG */
- for (i = 0; i < row_width; i++)
- {
- sp += 2;
- *dp++ = *sp++;
- *dp++ = *sp++;
- }
- }
- row_info->pixel_depth = 16;
- row_info->rowbytes = row_width * 2;
+ *dp++ = *sp++; *dp++ = *sp; sp += 3;
}
- row_info->channels = 1;
+
+ row_info->pixel_depth = 16;
}
- if (flags & PNG_FLAG_STRIP_ALPHA)
- row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+
+ else
+ return; /* bad bit depth */
+
+ row_info->channels = 1;
+
+ /* Finally fix the color type if it records an alpha channel */
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ row_info->color_type = PNG_COLOR_TYPE_GRAY;
}
+
+ /* RGBA, RGBX, XRGB cases */
+ else if (row_info->channels == 4)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ if (at_start != 0) /* Skip initial filler */
+ ++sp;
+ else /* Skip initial channels and, for sp, the filler */
+ {
+ sp += 4; dp += 3;
+ }
+
+ /* Note that the loop adds 3 to dp and 4 to sp each time. */
+ while (sp < ep)
+ {
+ *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 2;
+ }
+
+ row_info->pixel_depth = 24;
+ }
+
+ else if (row_info->bit_depth == 16)
+ {
+ if (at_start != 0) /* Skip initial filler */
+ sp += 2;
+ else /* Skip initial channels and, for sp, the filler */
+ {
+ sp += 8; dp += 6;
+ }
+
+ while (sp < ep)
+ {
+ /* Copy 6 bytes, skip 2 */
+ *dp++ = *sp++; *dp++ = *sp++;
+ *dp++ = *sp++; *dp++ = *sp++;
+ *dp++ = *sp++; *dp++ = *sp; sp += 3;
+ }
+
+ row_info->pixel_depth = 48;
+ }
+
+ else
+ return; /* bad bit depth */
+
+ row_info->channels = 3;
+
+ /* Finally fix the color type if it records an alpha channel */
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ row_info->color_type = PNG_COLOR_TYPE_RGB;
+ }
+
+ else
+ return; /* The filler channel has gone already */
+
+ /* Fix the rowbytes value. */
+ row_info->rowbytes = (size_t)(dp-row);
}
#endif
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-/* swaps red and blue bytes within a pixel */
+/* Swaps red and blue bytes within a pixel */
void /* PRIVATE */
png_do_bgr(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_bgr\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
- (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ png_debug(1, "in png_do_bgr");
+
+ if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_uint_32 row_width = row_info->width;
if (row_info->bit_depth == 8)
@@ -573,6 +639,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
*(rp + 2) = save;
}
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
@@ -586,6 +653,8 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
}
}
}
+
+#ifdef PNG_16BIT_SUPPORTED
else if (row_info->bit_depth == 16)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
@@ -603,6 +672,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
*(rp + 5) = save;
}
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
@@ -619,28 +689,141 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
}
}
}
+#endif
}
}
-#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+#endif /* READ_BGR || WRITE_BGR */
+
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+/* Added at libpng-1.5.10 */
+void /* PRIVATE */
+png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
+{
+ png_debug(1, "in png_do_check_palette_indexes");
+
+ if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
+ png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
+ {
+ /* Calculations moved outside switch in an attempt to stop different
+ * compiler warnings. 'padding' is in *bits* within the last byte, it is
+ * an 'int' because pixel_depth becomes an 'int' in the expression below,
+ * and this calculation is used because it avoids warnings that other
+ * forms produced on either GCC or MSVC.
+ */
+ int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
+ png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ /* in this case, all bytes must be 0 so we don't need
+ * to unpack the pixels except for the rightmost one.
+ */
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ if ((*rp >> padding) != 0)
+ png_ptr->num_palette_max = 1;
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ int i = ((*rp >> padding) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 2) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 4) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 6) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 4:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ int i = ((*rp >> padding) & 0x0f);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 4) & 0x0f);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 8:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ if (*rp > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = (int) *rp;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+#endif /* CHECK_FOR_INVALID_INDEX */
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
- defined(PNG_LEGACY_SUPPORTED)
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
void PNGAPI
-png_set_user_transform_info(png_structp png_ptr, png_voidp
+png_set_user_transform_info(png_structrp png_ptr, png_voidp
user_transform_ptr, int user_transform_depth, int user_transform_channels)
{
- png_debug(1, "in png_set_user_transform_info\n");
- if(png_ptr == NULL) return;
-#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ png_debug(1, "in png_set_user_transform_info");
+
+ if (png_ptr == NULL)
+ return;
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
+ (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)
+ {
+ png_app_error(png_ptr,
+ "info change after png_start_read_image or png_read_update_info");
+ return;
+ }
+#endif
+
png_ptr->user_transform_ptr = user_transform_ptr;
png_ptr->user_transform_depth = (png_byte)user_transform_depth;
png_ptr->user_transform_channels = (png_byte)user_transform_channels;
-#else
- if(user_transform_ptr || user_transform_depth || user_transform_channels)
- png_warning(png_ptr,
- "This version of libpng does not support user transform info");
-#endif
}
#endif
@@ -649,14 +832,37 @@ png_set_user_transform_info(png_structp png_ptr, png_voidp
* associated with this pointer before png_write_destroy and png_read_destroy
* are called.
*/
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
png_voidp PNGAPI
-png_get_user_transform_ptr(png_structp png_ptr)
+png_get_user_transform_ptr(png_const_structrp png_ptr)
{
-#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
- if (png_ptr == NULL) return (NULL);
- return ((png_voidp)png_ptr->user_transform_ptr);
-#else
- return (NULL);
-#endif
+ if (png_ptr == NULL)
+ return NULL;
+
+ return png_ptr->user_transform_ptr;
}
-#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+#endif
+
+#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
+png_uint_32 PNGAPI
+png_get_current_row_number(png_const_structrp png_ptr)
+{
+ /* See the comments in png.h - this is the sub-image row when reading an
+ * interlaced image.
+ */
+ if (png_ptr != NULL)
+ return png_ptr->row_number;
+
+ return PNG_UINT_32_MAX; /* help the app not to fail silently */
+}
+
+png_byte PNGAPI
+png_get_current_pass_number(png_const_structrp png_ptr)
+{
+ if (png_ptr != NULL)
+ return png_ptr->pass;
+ return 8; /* invalid */
+}
+#endif /* USER_TRANSFORM_INFO */
+#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */
+#endif /* READ || WRITE */
diff --git a/PDF/src/pngwio.c b/PDF/src/pngwio.c
index 371a4fad6..10e919dd0 100644
--- a/PDF/src/pngwio.c
+++ b/PDF/src/pngwio.c
@@ -1,11 +1,14 @@
/* pngwio.c - functions for data output
*
- * Last changed in libpng 1.2.13 November 13, 2006
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2006 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*
* This file provides a location for all output. Users who need
* special handling are expected to write functions that have the same
@@ -15,220 +18,151 @@
* them at run time with png_set_write_fn(...).
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
+
#ifdef PNG_WRITE_SUPPORTED
/* Write the data to whatever output you are using. The default routine
- writes to a file pointer. Note that this routine sometimes gets called
- with very small lengths, so you should implement some kind of simple
- buffering if you are using unbuffered writes. This should never be asked
- to write more than 64K on a 16 bit machine. */
+ * writes to a file pointer. Note that this routine sometimes gets called
+ * with very small lengths, so you should implement some kind of simple
+ * buffering if you are using unbuffered writes. This should never be asked
+ * to write more than 64K on a 16-bit machine.
+ */
void /* PRIVATE */
-png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+png_write_data(png_structrp png_ptr, png_const_bytep data, size_t length)
{
+ /* NOTE: write_data_fn must not change the buffer! */
if (png_ptr->write_data_fn != NULL )
- (*(png_ptr->write_data_fn))(png_ptr, data, length);
+ (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data),
+ length);
+
else
png_error(png_ptr, "Call to NULL write function");
}
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_STDIO_SUPPORTED
/* This is the function that does the actual writing of data. If you are
- not writing to a standard C stream, you should create a replacement
- write_data function and use it at run time with png_set_write_fn(), rather
- than changing the library. */
-#ifndef USE_FAR_KEYWORD
-void PNGAPI
-png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+ * not writing to a standard C stream, you should create a replacement
+ * write_data function and use it at run time with png_set_write_fn(), rather
+ * than changing the library.
+ */
+void PNGCBAPI
+png_default_write_data(png_structp png_ptr, png_bytep data, size_t length)
{
- png_uint_32 check;
+ size_t check;
+
+ if (png_ptr == NULL)
+ return;
- if(png_ptr == NULL) return;
-#if defined(_WIN32_WCE)
- if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
- check = 0;
-#else
check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
-#endif
+
if (check != length)
png_error(png_ptr, "Write Error");
}
-#else
-/* this is the model-independent version. Since the standard I/O library
- can't handle far buffers in the medium and small models, we have to copy
- the data.
-*/
-
-#define NEAR_BUF_SIZE 1024
-#define MIN(a,b) (a <= b ? a : b)
-
-void PNGAPI
-png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
-{
- png_uint_32 check;
- png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
- png_FILE_p io_ptr;
-
- if(png_ptr == NULL) return;
- /* Check if data really is near. If so, use usual code. */
- near_data = (png_byte *)CVT_PTR_NOCHECK(data);
- io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
- if ((png_bytep)near_data == data)
- {
-#if defined(_WIN32_WCE)
- if ( !WriteFile(io_ptr, near_data, length, &check, NULL) )
- check = 0;
-#else
- check = fwrite(near_data, 1, length, io_ptr);
-#endif
- }
- else
- {
- png_byte buf[NEAR_BUF_SIZE];
- png_size_t written, remaining, err;
- check = 0;
- remaining = length;
- do
- {
- written = MIN(NEAR_BUF_SIZE, remaining);
- png_memcpy(buf, data, written); /* copy far buffer to near buffer */
-#if defined(_WIN32_WCE)
- if ( !WriteFile(io_ptr, buf, written, &err, NULL) )
- err = 0;
-#else
- err = fwrite(buf, 1, written, io_ptr);
-#endif
- if (err != written)
- break;
- else
- check += err;
- data += written;
- remaining -= written;
- }
- while (remaining != 0);
- }
- if (check != length)
- png_error(png_ptr, "Write Error");
-}
-
-#endif
#endif
/* This function is called to output any data pending writing (normally
- to disk). After png_flush is called, there should be no data pending
- writing in any buffers. */
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ * to disk). After png_flush is called, there should be no data pending
+ * writing in any buffers.
+ */
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
void /* PRIVATE */
-png_flush(png_structp png_ptr)
+png_flush(png_structrp png_ptr)
{
if (png_ptr->output_flush_fn != NULL)
(*(png_ptr->output_flush_fn))(png_ptr);
}
-#if !defined(PNG_NO_STDIO)
-void PNGAPI
+# ifdef PNG_STDIO_SUPPORTED
+void PNGCBAPI
png_default_flush(png_structp png_ptr)
{
-#if !defined(_WIN32_WCE)
png_FILE_p io_ptr;
-#endif
- if(png_ptr == NULL) return;
-#if !defined(_WIN32_WCE)
- io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
- if (io_ptr != NULL)
- fflush(io_ptr);
-#endif
+
+ if (png_ptr == NULL)
+ return;
+
+ io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));
+ fflush(io_ptr);
}
-#endif
+# endif
#endif
/* This function allows the application to supply new output functions for
- libpng if standard C streams aren't being used.
-
- This function takes as its arguments:
- png_ptr - pointer to a png output data structure
- io_ptr - pointer to user supplied structure containing info about
- the output functions. May be NULL.
- write_data_fn - pointer to a new output function that takes as its
- arguments a pointer to a png_struct, a pointer to
- data to be written, and a 32-bit unsigned int that is
- the number of bytes to be written. The new write
- function should call png_error(png_ptr, "Error msg")
- to exit and output any fatal error messages.
- flush_data_fn - pointer to a new flush function that takes as its
- arguments a pointer to a png_struct. After a call to
- the flush function, there should be no data in any buffers
- or pending transmission. If the output method doesn't do
- any buffering of ouput, a function prototype must still be
- supplied although it doesn't have to do anything. If
- PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
- time, output_flush_fn will be ignored, although it must be
- supplied for compatibility. */
+ * libpng if standard C streams aren't being used.
+ *
+ * This function takes as its arguments:
+ * png_ptr - pointer to a png output data structure
+ * io_ptr - pointer to user supplied structure containing info about
+ * the output functions. May be NULL.
+ * write_data_fn - pointer to a new output function that takes as its
+ * arguments a pointer to a png_struct, a pointer to
+ * data to be written, and a 32-bit unsigned int that is
+ * the number of bytes to be written. The new write
+ * function should call png_error(png_ptr, "Error msg")
+ * to exit and output any fatal error messages. May be
+ * NULL, in which case libpng's default function will
+ * be used.
+ * flush_data_fn - pointer to a new flush function that takes as its
+ * arguments a pointer to a png_struct. After a call to
+ * the flush function, there should be no data in any buffers
+ * or pending transmission. If the output method doesn't do
+ * any buffering of output, a function prototype must still be
+ * supplied although it doesn't have to do anything. If
+ * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
+ * time, output_flush_fn will be ignored, although it must be
+ * supplied for compatibility. May be NULL, in which case
+ * libpng's default function will be used, if
+ * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not
+ * a good idea if io_ptr does not point to a standard
+ * *FILE structure.
+ */
void PNGAPI
-png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
- png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
+png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
{
- if(png_ptr == NULL) return;
+ if (png_ptr == NULL)
+ return;
+
png_ptr->io_ptr = io_ptr;
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_STDIO_SUPPORTED
if (write_data_fn != NULL)
png_ptr->write_data_fn = write_data_fn;
+
else
png_ptr->write_data_fn = png_default_write_data;
#else
png_ptr->write_data_fn = write_data_fn;
#endif
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
-#if !defined(PNG_NO_STDIO)
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+# ifdef PNG_STDIO_SUPPORTED
+
if (output_flush_fn != NULL)
png_ptr->output_flush_fn = output_flush_fn;
+
else
png_ptr->output_flush_fn = png_default_flush;
-#else
- png_ptr->output_flush_fn = output_flush_fn;
-#endif
-#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+# else
+ png_ptr->output_flush_fn = output_flush_fn;
+# endif
+#else
+ PNG_UNUSED(output_flush_fn)
+#endif /* WRITE_FLUSH */
+
+#ifdef PNG_READ_SUPPORTED
/* It is an error to read while writing a png file */
if (png_ptr->read_data_fn != NULL)
{
png_ptr->read_data_fn = NULL;
- png_warning(png_ptr,
- "Attempted to set both read_data_fn and write_data_fn in");
- png_warning(png_ptr,
- "the same structure. Resetting read_data_fn to NULL.");
- }
-}
-#if defined(USE_FAR_KEYWORD)
-#if defined(_MSC_VER)
-void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
-{
- void *near_ptr;
- void FAR *far_ptr;
- FP_OFF(near_ptr) = FP_OFF(ptr);
- far_ptr = (void FAR *)near_ptr;
- if(check != 0)
- if(FP_SEG(ptr) != FP_SEG(far_ptr))
- png_error(png_ptr,"segment lost in conversion");
- return(near_ptr);
+ png_warning(png_ptr,
+ "Can't set both read_data_fn and write_data_fn in the"
+ " same structure");
+ }
+#endif
}
-# else
-void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
-{
- void *near_ptr;
- void FAR *far_ptr;
- near_ptr = (void FAR *)ptr;
- far_ptr = (void FAR *)near_ptr;
- if(check != 0)
- if(far_ptr != ptr)
- png_error(png_ptr,"segment lost in conversion");
- return(near_ptr);
-}
-# endif
-# endif
-#endif /* PNG_WRITE_SUPPORTED */
+#endif /* WRITE */
diff --git a/PDF/src/pngwrite.c b/PDF/src/pngwrite.c
index b1f6a593a..77e412f43 100644
--- a/PDF/src/pngwrite.c
+++ b/PDF/src/pngwrite.c
@@ -1,288 +1,354 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Last changed in libpng 1.2.24 December 14, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-/* get internal access to png.h */
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
+#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
+# include
+#endif /* SIMPLIFIED_WRITE_STDIO */
+
#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+/* Write out all the unknown chunks for the current given location */
+static void
+write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
+ unsigned int where)
+{
+ if (info_ptr->unknown_chunks_num != 0)
+ {
+ png_const_unknown_chunkp up;
+
+ png_debug(5, "writing extra chunks");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ ++up)
+ if ((up->location & where) != 0)
+ {
+ /* If per-chunk unknown chunk handling is enabled use it, otherwise
+ * just write the chunks the application has set.
+ */
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ int keep = png_handle_as_unknown(png_ptr, up->name);
+
+ /* NOTE: this code is radically different from the read side in the
+ * matter of handling an ancillary unknown chunk. In the read side
+ * the default behavior is to discard it, in the code below the default
+ * behavior is to write it. Critical chunks are, however, only
+ * written if explicitly listed or if the default is set to write all
+ * unknown chunks.
+ *
+ * The default handling is also slightly weird - it is not possible to
+ * stop the writing of all unsafe-to-copy chunks!
+ *
+ * TODO: REVIEW: this would seem to be a bug.
+ */
+ if (keep != PNG_HANDLE_CHUNK_NEVER &&
+ ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||
+ keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&
+ png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))
+#endif
+ {
+ /* TODO: review, what is wrong with a zero length unknown chunk? */
+ if (up->size == 0)
+ png_warning(png_ptr, "Writing zero-length unknown chunk");
+
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+}
+#endif /* WRITE_UNKNOWN_CHUNKS */
+
/* Writes all the PNG information. This is the suggested way to use the
* library. If you have a new chunk to add, make a function to write it,
* and put it in the correct location here. If you want the chunk written
* after the image data, put it in png_write_end(). I strongly encourage
- * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
- * the chunk, as that will keep the code from breaking if you want to just
- * write a plain PNG file. If you have long comments, I suggest writing
- * them in png_write_end(), and compressing them.
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before
+ * writing the chunk, as that will keep the code from breaking if you want
+ * to just write a plain PNG file. If you have long comments, I suggest
+ * writing them in png_write_end(), and compressing them.
*/
void PNGAPI
-png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
+png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
{
- png_debug(1, "in png_write_info_before_PLTE\n");
+ png_debug(1, "in png_write_info_before_PLTE");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
+
+ if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
{
- png_write_sig(png_ptr); /* write PNG signature */
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
- {
- png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
- png_ptr->mng_features_permitted=0;
- }
+ /* Write PNG signature */
+ png_write_sig(png_ptr);
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \
+ png_ptr->mng_features_permitted != 0)
+ {
+ png_warning(png_ptr,
+ "MNG features are not allowed in a PNG datastream");
+ png_ptr->mng_features_permitted = 0;
+ }
#endif
- /* write IHDR information. */
- png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
- info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
- info_ptr->filter_type,
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
- info_ptr->interlace_type);
+
+ /* Write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
+ info_ptr->filter_type,
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ info_ptr->interlace_type
#else
- 0);
+ 0
#endif
- /* the rest of these check to see if the valid field has the appropriate
- flag set, and if it does, writes the chunk. */
-#if defined(PNG_WRITE_gAMA_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_gAMA)
- {
-# ifdef PNG_FLOATING_POINT_SUPPORTED
- png_write_gAMA(png_ptr, info_ptr->gamma);
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
- png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
+ );
+
+ /* The rest of these check to see if the valid field has the appropriate
+ * flag set, and if it does, writes the chunk.
+ *
+ * 1.6.0: COLORSPACE support controls the writing of these chunks too, and
+ * the chunks will be written if the WRITE routine is there and
+ * information * is available in the COLORSPACE. (See
+ * png_colorspace_sync_info in png.c for where the valid flags get set.)
+ *
+ * Under certain circumstances the colorspace can be invalidated without
+ * syncing the info_struct 'valid' flags; this happens if libpng detects
+ * an error and calls png_error while the color space is being set, yet
+ * 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
#endif
- }
-#endif
-#if defined(PNG_WRITE_sRGB_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_sRGB)
- png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
-#endif
-#if defined(PNG_WRITE_iCCP_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_iCCP)
- png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
- info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
-#endif
-#if defined(PNG_WRITE_sBIT_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_sBIT)
- png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
-#endif
-#if defined(PNG_WRITE_cHRM_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_cHRM)
- {
-#ifdef PNG_FLOATING_POINT_SUPPORTED
- png_write_cHRM(png_ptr,
- info_ptr->x_white, info_ptr->y_white,
- info_ptr->x_red, info_ptr->y_red,
- info_ptr->x_green, info_ptr->y_green,
- info_ptr->x_blue, info_ptr->y_blue);
-#else
-# ifdef PNG_FIXED_POINT_SUPPORTED
- png_write_cHRM_fixed(png_ptr,
- info_ptr->int_x_white, info_ptr->int_y_white,
- info_ptr->int_x_red, info_ptr->int_y_red,
- info_ptr->int_x_green, info_ptr->int_y_green,
- info_ptr->int_x_blue, info_ptr->int_y_blue);
-# endif
-#endif
- }
-#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
- if (info_ptr->unknown_chunks_num)
- {
- png_unknown_chunk *up;
- png_debug(5, "writing extra chunks\n");
-
- for (up = info_ptr->unknown_chunks;
- up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
- up++)
- {
- int keep=png_handle_as_unknown(png_ptr, up->name);
- if (keep != PNG_HANDLE_CHUNK_NEVER &&
- up->location && !(up->location & PNG_HAVE_PLTE) &&
- !(up->location & PNG_HAVE_IDAT) &&
- ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
- (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+#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)
{
- png_write_chunk(png_ptr, up->name, up->data, up->size);
+# 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
+
+ png_write_iCCP(png_ptr, info_ptr->iccp_name,
+ info_ptr->iccp_profile);
}
- }
- }
+# 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);
+# 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);
+# endif
+#endif
+
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
+#endif
+
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
}
}
void PNGAPI
-png_write_info(png_structp png_ptr, png_infop info_ptr)
+png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
{
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
int i;
#endif
- png_debug(1, "in png_write_info\n");
+ png_debug(1, "in png_write_info");
if (png_ptr == NULL || info_ptr == NULL)
return;
png_write_info_before_PLTE(png_ptr, info_ptr);
- if (info_ptr->valid & PNG_INFO_PLTE)
+ if ((info_ptr->valid & PNG_INFO_PLTE) != 0)
png_write_PLTE(png_ptr, info_ptr->palette,
- (png_uint_32)info_ptr->num_palette);
+ (png_uint_32)info_ptr->num_palette);
+
else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
png_error(png_ptr, "Valid palette required for paletted images");
-#if defined(PNG_WRITE_tRNS_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_tRNS)
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_tRNS) !=0)
+ {
+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
+ /* Invert the alpha channel (in tRNS) */
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&
+ info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
-#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
- /* invert the alpha channel (in tRNS) */
- if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
- info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- {
- int j;
- for (j=0; j<(int)info_ptr->num_trans; j++)
- info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
- }
-#endif
- png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
- info_ptr->num_trans, info_ptr->color_type);
+ int j, jend;
+
+ jend = info_ptr->num_trans;
+ if (jend > PNG_MAX_PALETTE_LENGTH)
+ jend = PNG_MAX_PALETTE_LENGTH;
+
+ for (j = 0; jtrans_alpha[j] =
+ (png_byte)(255 - info_ptr->trans_alpha[j]);
}
#endif
-#if defined(PNG_WRITE_bKGD_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_bKGD)
+ png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),
+ info_ptr->num_trans, info_ptr->color_type);
+ }
+#endif
+#ifdef PNG_WRITE_bKGD_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_bKGD) != 0)
png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
#endif
-#if defined(PNG_WRITE_hIST_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_hIST)
+
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+ {
+ png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+ png_ptr->mode |= PNG_WROTE_eXIf;
+ }
+#endif
+
+#ifdef PNG_WRITE_hIST_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_hIST) != 0)
png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
#endif
-#if defined(PNG_WRITE_oFFs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_oFFs)
+
+#ifdef PNG_WRITE_oFFs_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_oFFs) != 0)
png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
- info_ptr->offset_unit_type);
+ info_ptr->offset_unit_type);
#endif
-#if defined(PNG_WRITE_pCAL_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pCAL)
+
+#ifdef PNG_WRITE_pCAL_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_pCAL) != 0)
png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
- info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
- info_ptr->pcal_units, info_ptr->pcal_params);
+ info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+ info_ptr->pcal_units, info_ptr->pcal_params);
#endif
-#if defined(PNG_WRITE_sCAL_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_sCAL)
-#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
- png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
- info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
+
+#ifdef PNG_WRITE_sCAL_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_sCAL) != 0)
png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
info_ptr->scal_s_width, info_ptr->scal_s_height);
-#else
- png_warning(png_ptr,
- "png_write_sCAL not supported; sCAL chunk not written.");
-#endif
-#endif
-#endif
-#if defined(PNG_WRITE_pHYs_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_pHYs)
+#endif /* sCAL */
+
+#ifdef PNG_WRITE_pHYs_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_pHYs) != 0)
png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
- info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
-#endif
-#if defined(PNG_WRITE_tIME_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_tIME)
+ info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif /* pHYs */
+
+#ifdef PNG_WRITE_tIME_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_tIME) != 0)
{
png_write_tIME(png_ptr, &(info_ptr->mod_time));
png_ptr->mode |= PNG_WROTE_tIME;
}
-#endif
-#if defined(PNG_WRITE_sPLT_SUPPORTED)
- if (info_ptr->valid & PNG_INFO_sPLT)
- for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
- png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
-#endif
-#if defined(PNG_WRITE_TEXT_SUPPORTED)
+#endif /* tIME */
+
+#ifdef PNG_WRITE_sPLT_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_sPLT) != 0)
+ for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
+ png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
+#endif /* sPLT */
+
+#ifdef PNG_WRITE_TEXT_SUPPORTED
/* Check to see if we need to write text chunks */
for (i = 0; i < info_ptr->num_text; i++)
{
- png_debug2(2, "Writing header text chunk %d, type %d\n", i,
- info_ptr->text[i].compression);
- /* an internationalized chunk? */
+ png_debug2(2, "Writing header text chunk %d, type %d", i,
+ info_ptr->text[i].compression);
+ /* An internationalized chunk? */
if (info_ptr->text[i].compression > 0)
{
-#if defined(PNG_WRITE_iTXt_SUPPORTED)
- /* write international chunk */
- png_write_iTXt(png_ptr,
- info_ptr->text[i].compression,
- info_ptr->text[i].key,
- info_ptr->text[i].lang,
- info_ptr->text[i].lang_key,
- info_ptr->text[i].text);
+#ifdef PNG_WRITE_iTXt_SUPPORTED
+ /* Write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+ /* Mark this chunk as written */
+ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ else
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
- png_warning(png_ptr, "Unable to write international text");
+ png_warning(png_ptr, "Unable to write international text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
+
/* If we want a compressed text chunk */
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
{
-#if defined(PNG_WRITE_zTXt_SUPPORTED)
- /* write compressed chunk */
+#ifdef PNG_WRITE_zTXt_SUPPORTED
+ /* Write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key,
- info_ptr->text[i].text, 0,
- info_ptr->text[i].compression);
+ info_ptr->text[i].text, info_ptr->text[i].compression);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
png_warning(png_ptr, "Unable to write compressed text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
+
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
{
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
- /* write uncompressed chunk */
+#ifdef PNG_WRITE_tEXt_SUPPORTED
+ /* Write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key,
- info_ptr->text[i].text,
- 0);
-#else
- png_warning(png_ptr, "Unable to write uncompressed text");
-#endif
+ info_ptr->text[i].text,
+ 0);
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+#else
+ /* Can't get here */
+ png_warning(png_ptr, "Unable to write uncompressed text");
+#endif
}
}
-#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
- if (info_ptr->unknown_chunks_num)
- {
- png_unknown_chunk *up;
+#endif /* tEXt */
- png_debug(5, "writing extra chunks\n");
-
- for (up = info_ptr->unknown_chunks;
- up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
- up++)
- {
- int keep=png_handle_as_unknown(png_ptr, up->name);
- if (keep != PNG_HANDLE_CHUNK_NEVER &&
- up->location && (up->location & PNG_HAVE_PLTE) &&
- !(up->location & PNG_HAVE_IDAT) &&
- ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
- (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
- {
- png_write_chunk(png_ptr, up->name, up->data, up->size);
- }
- }
- }
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);
#endif
}
@@ -292,114 +358,126 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
* comments, I suggest writing them here, and compressing them.
*/
void PNGAPI
-png_write_end(png_structp png_ptr, png_infop info_ptr)
+png_write_end(png_structrp png_ptr, png_inforp info_ptr)
{
- png_debug(1, "in png_write_end\n");
+ png_debug(1, "in png_write_end");
+
if (png_ptr == NULL)
return;
- if (!(png_ptr->mode & PNG_HAVE_IDAT))
+
+ if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
png_error(png_ptr, "No IDATs written into file");
- /* see if user wants us to write information chunks */
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= png_ptr->num_palette)
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+#endif
+
+ /* See if user wants us to write information chunks */
if (info_ptr != NULL)
{
-#if defined(PNG_WRITE_TEXT_SUPPORTED)
+#ifdef PNG_WRITE_TEXT_SUPPORTED
int i; /* local index variable */
#endif
-#if defined(PNG_WRITE_tIME_SUPPORTED)
- /* check to see if user has supplied a time chunk */
- if ((info_ptr->valid & PNG_INFO_tIME) &&
- !(png_ptr->mode & PNG_WROTE_tIME))
+#ifdef PNG_WRITE_tIME_SUPPORTED
+ /* Check to see if user has supplied a time chunk */
+ if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&
+ (png_ptr->mode & PNG_WROTE_tIME) == 0)
png_write_tIME(png_ptr, &(info_ptr->mod_time));
+
#endif
-#if defined(PNG_WRITE_TEXT_SUPPORTED)
- /* loop through comment chunks */
+#ifdef PNG_WRITE_TEXT_SUPPORTED
+ /* Loop through comment chunks */
for (i = 0; i < info_ptr->num_text; i++)
{
- png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
- info_ptr->text[i].compression);
- /* an internationalized chunk? */
+ png_debug2(2, "Writing trailer text chunk %d, type %d", i,
+ info_ptr->text[i].compression);
+ /* An internationalized chunk? */
if (info_ptr->text[i].compression > 0)
{
-#if defined(PNG_WRITE_iTXt_SUPPORTED)
- /* write international chunk */
- png_write_iTXt(png_ptr,
- info_ptr->text[i].compression,
- info_ptr->text[i].key,
- info_ptr->text[i].lang,
- info_ptr->text[i].lang_key,
- info_ptr->text[i].text);
+#ifdef PNG_WRITE_iTXt_SUPPORTED
+ /* Write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+ /* Mark this chunk as written */
+ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ else
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
- png_warning(png_ptr, "Unable to write international text");
+ png_warning(png_ptr, "Unable to write international text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
+
else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
{
-#if defined(PNG_WRITE_zTXt_SUPPORTED)
- /* write compressed chunk */
+#ifdef PNG_WRITE_zTXt_SUPPORTED
+ /* Write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key,
- info_ptr->text[i].text, 0,
- info_ptr->text[i].compression);
+ info_ptr->text[i].text, info_ptr->text[i].compression);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
png_warning(png_ptr, "Unable to write compressed text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
+
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
{
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
- /* write uncompressed chunk */
+#ifdef PNG_WRITE_tEXt_SUPPORTED
+ /* Write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key,
- info_ptr->text[i].text, 0);
+ info_ptr->text[i].text, 0);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
#else
png_warning(png_ptr, "Unable to write uncompressed text");
#endif
-
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
}
#endif
-#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
- if (info_ptr->unknown_chunks_num)
- {
- png_unknown_chunk *up;
- png_debug(5, "writing extra chunks\n");
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
+ (png_ptr->mode & PNG_WROTE_eXIf) == 0)
+ png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+#endif
- for (up = info_ptr->unknown_chunks;
- up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
- up++)
- {
- int keep=png_handle_as_unknown(png_ptr, up->name);
- if (keep != PNG_HANDLE_CHUNK_NEVER &&
- up->location && (up->location & PNG_AFTER_IDAT) &&
- ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
- (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
- {
- png_write_chunk(png_ptr, up->name, up->data, up->size);
- }
- }
- }
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
#endif
}
png_ptr->mode |= PNG_AFTER_IDAT;
- /* write end of PNG file */
+ /* Write end of PNG file */
png_write_IEND(png_ptr);
+
+ /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
+ * and restored again in libpng-1.2.30, may cause some applications that
+ * do not set png_ptr->output_flush_fn to crash. If your application
+ * experiences a problem, please try building libpng with
+ * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
+ * png-mng-implement at lists.sf.net .
+ */
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
+ png_flush(png_ptr);
+# endif
+#endif
}
-#if defined(PNG_WRITE_tIME_SUPPORTED)
-#if !defined(_WIN32_WCE)
-/* "time.h" functions are not supported on WindowsCE */
+#ifdef PNG_CONVERT_tIME_SUPPORTED
void PNGAPI
-png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
+png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime)
{
- png_debug(1, "in png_convert_from_struct_tm\n");
+ png_debug(1, "in png_convert_from_struct_tm");
+
ptime->year = (png_uint_16)(1900 + ttime->tm_year);
ptime->month = (png_byte)(ttime->tm_mon + 1);
ptime->day = (png_byte)ttime->tm_mday;
@@ -413,273 +491,99 @@ png_convert_from_time_t(png_timep ptime, time_t ttime)
{
struct tm *tbuf;
- png_debug(1, "in png_convert_from_time_t\n");
+ png_debug(1, "in png_convert_from_time_t");
+
tbuf = gmtime(&ttime);
+ if (tbuf == NULL)
+ {
+ /* TODO: add a safe function which takes a png_ptr argument and raises
+ * a png_error if the ttime argument is invalid and the call to gmtime
+ * fails as a consequence.
+ */
+ memset(ptime, 0, sizeof(*ptime));
+ return;
+ }
+
png_convert_from_struct_tm(ptime, tbuf);
}
#endif
-#endif
/* Initialize png_ptr structure, and allocate any memory needed */
-png_structp PNGAPI
-png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn)
+PNG_FUNCTION(png_structp,PNGAPI
+png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
{
-#ifdef PNG_USER_MEM_SUPPORTED
- return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
- warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
+#ifndef PNG_USER_MEM_SUPPORTED
+ png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
+ error_fn, warn_fn, NULL, NULL, NULL);
+#else
+ return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL);
}
/* Alternate initialize png_ptr structure, and allocate any memory needed */
-png_structp PNGAPI
-png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
- png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
- png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+PNG_FUNCTION(png_structp,PNGAPI
+png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
{
-#endif /* PNG_USER_MEM_SUPPORTED */
- png_structp png_ptr;
-#ifdef PNG_SETJMP_SUPPORTED
-#ifdef USE_FAR_KEYWORD
- jmp_buf jmpbuf;
-#endif
-#endif
- int i;
- png_debug(1, "in png_create_write_struct\n");
-#ifdef PNG_USER_MEM_SUPPORTED
- png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
- (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
-#else
- png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
-#endif /* PNG_USER_MEM_SUPPORTED */
- if (png_ptr == NULL)
- return (NULL);
-
- /* added at libpng-1.2.6 */
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
- png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
-#else
- if (setjmp(png_ptr->jmpbuf))
-#endif
+ png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
+ error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
+#endif /* USER_MEM */
+ if (png_ptr != NULL)
{
- png_free(png_ptr, png_ptr->zbuf);
- png_ptr->zbuf=NULL;
- png_destroy_struct(png_ptr);
- return (NULL);
- }
-#ifdef USE_FAR_KEYWORD
- png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
-#endif
+ /* Set the zlib control values to defaults; they can be overridden by the
+ * application after the struct has been created.
+ */
+ png_ptr->zbuffer_size = PNG_ZBUF_SIZE;
+
+ /* The 'zlib_strategy' setting is irrelevant because png_default_claim in
+ * pngwutil.c defaults it according to whether or not filters will be
+ * used, and ignores this setting.
+ */
+ png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;
+ png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;
+ png_ptr->zlib_mem_level = 8;
+ png_ptr->zlib_window_bits = 15;
+ png_ptr->zlib_method = 8;
+
+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+ png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;
+ png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;
+ png_ptr->zlib_text_mem_level = 8;
+ png_ptr->zlib_text_window_bits = 15;
+ png_ptr->zlib_text_method = 8;
+#endif /* WRITE_COMPRESSED_TEXT */
+
+ /* This is a highly dubious configuration option; by default it is off,
+ * but it may be appropriate for private builds that are testing
+ * extensions not conformant to the current specification, or of
+ * applications that must not fail to write at all costs!
+ */
+#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
+ /* In stable builds only warn if an application error can be completely
+ * handled.
+ */
+ png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
#endif
-#ifdef PNG_USER_MEM_SUPPORTED
- png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
-#endif /* PNG_USER_MEM_SUPPORTED */
- png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
-
- i=0;
- do
- {
- if(user_png_ver[i] != png_libpng_ver[i])
- png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
- } while (png_libpng_ver[i++]);
-
- if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
- {
- /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
- * we must recompile any applications that use any older library version.
- * For versions after libpng 1.0, we will be compatible, so we need
- * only check the first digit.
- */
- if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
- (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
- (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char msg[80];
- if (user_png_ver)
- {
- png_snprintf(msg, 80,
- "Application was compiled with png.h from libpng-%.20s",
- user_png_ver);
- png_warning(png_ptr, msg);
- }
- png_snprintf(msg, 80,
- "Application is running with png.c from libpng-%.20s",
- png_libpng_ver);
- png_warning(png_ptr, msg);
+ /* App warnings are warnings in release (or release candidate) builds but
+ * are errors during development.
+ */
+#if PNG_RELEASE_BUILD
+ png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
#endif
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "Incompatible libpng version in application and library");
- }
+
+ /* TODO: delay this, it can be done in png_init_io() (if the app doesn't
+ * do it itself) avoiding setting the default function if it is not
+ * required.
+ */
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
}
- /* initialize zbuf - compression buffer */
- png_ptr->zbuf_size = PNG_ZBUF_SIZE;
- png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)png_ptr->zbuf_size);
-
- png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
- png_flush_ptr_NULL);
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
- 1, png_doublep_NULL, png_doublep_NULL);
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
-/* Applications that neglect to set up their own setjmp() and then encounter
- a png_error() will longjmp here. Since the jmpbuf is then meaningless we
- abort instead of returning. */
-#ifdef USE_FAR_KEYWORD
- if (setjmp(jmpbuf))
- PNG_ABORT();
- png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
-#else
- if (setjmp(png_ptr->jmpbuf))
- PNG_ABORT();
-#endif
-#endif
- return (png_ptr);
+ return png_ptr;
}
-/* Initialize png_ptr structure, and allocate any memory needed */
-#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
-/* Deprecated. */
-#undef png_write_init
-void PNGAPI
-png_write_init(png_structp png_ptr)
-{
- /* We only come here via pre-1.0.7-compiled applications */
- png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
-}
-
-void PNGAPI
-png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
- png_size_t png_struct_size, png_size_t png_info_size)
-{
- /* We only come here via pre-1.0.12-compiled applications */
- if(png_ptr == NULL) return;
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- if(png_sizeof(png_struct) > png_struct_size ||
- png_sizeof(png_info) > png_info_size)
- {
- char msg[80];
- png_ptr->warning_fn=NULL;
- if (user_png_ver)
- {
- png_snprintf(msg, 80,
- "Application was compiled with png.h from libpng-%.20s",
- user_png_ver);
- png_warning(png_ptr, msg);
- }
- png_snprintf(msg, 80,
- "Application is running with png.c from libpng-%.20s",
- png_libpng_ver);
- png_warning(png_ptr, msg);
- }
-#endif
- if(png_sizeof(png_struct) > png_struct_size)
- {
- png_ptr->error_fn=NULL;
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "The png struct allocated by the application for writing is too small.");
- }
- if(png_sizeof(png_info) > png_info_size)
- {
- png_ptr->error_fn=NULL;
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags=0;
-#endif
- png_error(png_ptr,
- "The info struct allocated by the application for writing is too small.");
- }
- png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
-}
-#endif /* PNG_1_0_X || PNG_1_2_X */
-
-
-void PNGAPI
-png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
- png_size_t png_struct_size)
-{
- png_structp png_ptr=*ptr_ptr;
-#ifdef PNG_SETJMP_SUPPORTED
- jmp_buf tmp_jmp; /* to save current jump buffer */
-#endif
-
- int i = 0;
-
- if (png_ptr == NULL)
- return;
-
- do
- {
- if (user_png_ver[i] != png_libpng_ver[i])
- {
-#ifdef PNG_LEGACY_SUPPORTED
- png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-#else
- png_ptr->warning_fn=NULL;
- png_warning(png_ptr,
- "Application uses deprecated png_write_init() and should be recompiled.");
- break;
-#endif
- }
- } while (png_libpng_ver[i++]);
-
- png_debug(1, "in png_write_init_3\n");
-
-#ifdef PNG_SETJMP_SUPPORTED
- /* save jump buffer and error functions */
- png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
-#endif
-
- if (png_sizeof(png_struct) > png_struct_size)
- {
- png_destroy_struct(png_ptr);
- png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
- *ptr_ptr = png_ptr;
- }
-
- /* reset all variables to 0 */
- png_memset(png_ptr, 0, png_sizeof (png_struct));
-
- /* added at libpng-1.2.6 */
-#ifdef PNG_SET_USER_LIMITS_SUPPORTED
- png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
- png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
- /* restore jump buffer */
- png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
-#endif
-
- png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
- png_flush_ptr_NULL);
-
- /* initialize zbuf - compression buffer */
- png_ptr->zbuf_size = PNG_ZBUF_SIZE;
- png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)png_ptr->zbuf_size);
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
- 1, png_doublep_NULL, png_doublep_NULL);
-#endif
-}
/* Write a few rows of image data. If the image is interlaced,
* either you will have to write the 7 sub images, or, if you
@@ -687,18 +591,18 @@ png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
* "write" the image seven times.
*/
void PNGAPI
-png_write_rows(png_structp png_ptr, png_bytepp row,
- png_uint_32 num_rows)
+png_write_rows(png_structrp png_ptr, png_bytepp row,
+ png_uint_32 num_rows)
{
png_uint_32 i; /* row counter */
png_bytepp rp; /* row pointer */
- png_debug(1, "in png_write_rows\n");
+ png_debug(1, "in png_write_rows");
if (png_ptr == NULL)
return;
- /* loop through the rows */
+ /* Loop through the rows */
for (i = 0, rp = row; i < num_rows; i++, rp++)
{
png_write_row(png_ptr, *rp);
@@ -709,7 +613,7 @@ png_write_rows(png_structp png_ptr, png_bytepp row,
* if you are writing an interlaced image.
*/
void PNGAPI
-png_write_image(png_structp png_ptr, png_bytepp image)
+png_write_image(png_structrp png_ptr, png_bytepp image)
{
png_uint_32 i; /* row index */
int pass, num_pass; /* pass variables */
@@ -718,18 +622,20 @@ png_write_image(png_structp png_ptr, png_bytepp image)
if (png_ptr == NULL)
return;
- png_debug(1, "in png_write_image\n");
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
- /* intialize interlace handling. If image is not interlaced,
- this will set pass to 1 */
+ png_debug(1, "in png_write_image");
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* Initialize interlace handling. If image is not interlaced,
+ * this will set pass to 1
+ */
num_pass = png_set_interlace_handling(png_ptr);
#else
num_pass = 1;
#endif
- /* loop through passes */
+ /* Loop through passes */
for (pass = 0; pass < num_pass; pass++)
{
- /* loop through image */
+ /* Loop through image */
for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
{
png_write_row(png_ptr, *rp);
@@ -737,76 +643,155 @@ png_write_image(png_structp png_ptr, png_bytepp image)
}
}
-/* called by user to write a row of image data */
-void PNGAPI
-png_write_row(png_structp png_ptr, png_bytep row)
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+/* Performs intrapixel differencing */
+static void
+png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
{
+ png_debug(1, "in png_do_write_intrapixel");
+
+ if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)(*rp - *(rp + 1));
+ *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1));
+ }
+ }
+
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1);
+ png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
+ png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
+ png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL);
+ png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
+ *(rp ) = (png_byte)(red >> 8);
+ *(rp + 1) = (png_byte)red;
+ *(rp + 4) = (png_byte)(blue >> 8);
+ *(rp + 5) = (png_byte)blue;
+ }
+ }
+#endif /* WRITE_16BIT */
+ }
+}
+#endif /* MNG_FEATURES */
+
+/* Called by user to write a row of image data */
+void PNGAPI
+png_write_row(png_structrp png_ptr, png_const_bytep row)
+{
+ /* 1.5.6: moved from png_struct to be a local structure: */
+ png_row_info row_info;
+
+ png_debug2(1, "in png_write_row (row %u, pass %d)",
+ png_ptr->row_number, png_ptr->pass);
+
if (png_ptr == NULL)
return;
- png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
- png_ptr->row_number, png_ptr->pass);
- /* initialize transformations and other stuff if first time */
+ /* Initialize transformations and other stuff if first time */
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{
- /* make sure we wrote the header info */
- if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
- png_error(png_ptr,
- "png_write_info was never called before png_write_row.");
+ /* Make sure we wrote the header info */
+ if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
+ png_error(png_ptr,
+ "png_write_info was never called before png_write_row");
- /* check for transforms that have been set but were defined out */
+ /* Check for transforms that have been set but were defined out */
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_MONO)
- png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
+ png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
#endif
+
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
- if (png_ptr->transformations & PNG_FILLER)
- png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_FILLER) != 0)
+ png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
#endif
-#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
+#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
+ defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ png_warning(png_ptr,
+ "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
#endif
+
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
- if (png_ptr->transformations & PNG_PACK)
- png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_PACK) != 0)
+ png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
#endif
+
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
- if (png_ptr->transformations & PNG_SHIFT)
- png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_SHIFT) != 0)
+ png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
#endif
+
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
- if (png_ptr->transformations & PNG_BGR)
- png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_BGR) != 0)
+ png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
#endif
+
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_BYTES)
- png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
+ if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
+ png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
#endif
png_write_start_row(png_ptr);
}
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
- /* if interlaced and not interested in row, return */
- if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* If interlaced and not interested in row, return */
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0)
{
switch (png_ptr->pass)
{
case 0:
- if (png_ptr->row_number & 0x07)
+ if ((png_ptr->row_number & 0x07) != 0)
{
png_write_finish_row(png_ptr);
return;
}
break;
+
case 1:
- if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
+ if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5)
{
png_write_finish_row(png_ptr);
return;
}
break;
+
case 2:
if ((png_ptr->row_number & 0x07) != 4)
{
@@ -814,13 +799,15 @@ png_write_row(png_structp png_ptr, png_bytep row)
return;
}
break;
+
case 3:
- if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
+ if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3)
{
png_write_finish_row(png_ptr);
return;
}
break;
+
case 4:
if ((png_ptr->row_number & 0x03) != 2)
{
@@ -828,55 +815,55 @@ png_write_row(png_structp png_ptr, png_bytep row)
return;
}
break;
+
case 5:
- if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
+ if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2)
{
png_write_finish_row(png_ptr);
return;
}
break;
+
case 6:
- if (!(png_ptr->row_number & 0x01))
+ if ((png_ptr->row_number & 0x01) == 0)
{
png_write_finish_row(png_ptr);
return;
}
break;
+
+ default: /* error: ignore it */
+ break;
}
}
#endif
- /* set up row info for transformations */
- png_ptr->row_info.color_type = png_ptr->color_type;
- png_ptr->row_info.width = png_ptr->usr_width;
- png_ptr->row_info.channels = png_ptr->usr_channels;
- png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
- png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
- png_ptr->row_info.channels);
+ /* Set up row info for transformations */
+ row_info.color_type = png_ptr->color_type;
+ row_info.width = png_ptr->usr_width;
+ row_info.channels = png_ptr->usr_channels;
+ row_info.bit_depth = png_ptr->usr_bit_depth;
+ row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);
+ row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
- png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
- png_ptr->row_info.width);
-
- png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
- png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
- png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
- png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
- png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
- png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
+ png_debug1(3, "row_info->color_type = %d", row_info.color_type);
+ png_debug1(3, "row_info->width = %u", row_info.width);
+ png_debug1(3, "row_info->channels = %d", row_info.channels);
+ png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth);
+ png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth);
+ png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes);
/* Copy user's row into buffer, leaving room for filter byte. */
- png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
- png_ptr->row_info.rowbytes);
+ memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
- /* handle interlacing */
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* Handle interlacing */
if (png_ptr->interlaced && png_ptr->pass < 6 &&
- (png_ptr->transformations & PNG_INTERLACE))
+ (png_ptr->transformations & PNG_INTERLACE) != 0)
{
- png_do_write_interlace(&(png_ptr->row_info),
- png_ptr->row_buf + 1, png_ptr->pass);
- /* this should always get caught above, but still ... */
- if (!(png_ptr->row_info.width))
+ png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
+ /* This should always get caught above, but still ... */
+ if (row_info.width == 0)
{
png_write_finish_row(png_ptr);
return;
@@ -884,11 +871,20 @@ png_write_row(png_structp png_ptr, png_bytep row)
}
#endif
- /* handle other transformations */
- if (png_ptr->transformations)
- png_do_write_transformations(png_ptr);
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
+ /* Handle other transformations */
+ if (png_ptr->transformations != 0)
+ png_do_write_transformations(png_ptr, &row_info);
+#endif
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ /* At this point the row_info pixel depth must match the 'transformed' depth,
+ * which is also the output depth.
+ */
+ if (row_info.pixel_depth != png_ptr->pixel_depth ||
+ row_info.pixel_depth != png_ptr->transformed_pixel_depth)
+ png_error(png_ptr, "internal write transform logic error");
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
/* Write filter_method 64 (intrapixel differencing) only if
* 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
* 2. Libpng did not write a PNG signature (this filter_method is only
@@ -898,619 +894,1525 @@ png_write_row(png_structp png_ptr, png_bytep row)
* 4. The filter_method is 64 and
* 5. The color_type is RGB or RGBA
*/
- if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
- (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+ if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
{
/* Intrapixel differencing */
- png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);
}
#endif
+/* Added at libpng-1.5.10 */
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Check for out-of-range palette index */
+ if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= 0)
+ png_do_check_palette_indexes(png_ptr, &row_info);
+#endif
+
/* Find a filter if necessary, filter the row and write it out. */
- png_write_find_filter(png_ptr, &(png_ptr->row_info));
+ png_write_find_filter(png_ptr, &row_info);
if (png_ptr->write_row_fn != NULL)
(*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
}
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
/* Set the automatic flush interval or 0 to turn flushing off */
void PNGAPI
-png_set_flush(png_structp png_ptr, int nrows)
+png_set_flush(png_structrp png_ptr, int nrows)
{
- png_debug(1, "in png_set_flush\n");
+ png_debug(1, "in png_set_flush");
+
if (png_ptr == NULL)
return;
- png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+
+ png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);
}
-/* flush the current output buffers now */
+/* Flush the current output buffers now */
void PNGAPI
-png_write_flush(png_structp png_ptr)
+png_write_flush(png_structrp png_ptr)
{
- int wrote_IDAT;
+ png_debug(1, "in png_write_flush");
- png_debug(1, "in png_write_flush\n");
if (png_ptr == NULL)
return;
+
/* We have already written out all of the data */
if (png_ptr->row_number >= png_ptr->num_rows)
- return;
+ return;
- do
- {
- int ret;
-
- /* compress the data */
- ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
- wrote_IDAT = 0;
-
- /* check for compression errors */
- if (ret != Z_OK)
- {
- if (png_ptr->zstream.msg != NULL)
- png_error(png_ptr, png_ptr->zstream.msg);
- else
- png_error(png_ptr, "zlib error");
- }
-
- if (!(png_ptr->zstream.avail_out))
- {
- /* write the IDAT and reset the zlib output buffer */
- png_write_IDAT(png_ptr, png_ptr->zbuf,
- png_ptr->zbuf_size);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- wrote_IDAT = 1;
- }
- } while(wrote_IDAT == 1);
-
- /* If there is any data left to be output, write it into a new IDAT */
- if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
- {
- /* write the IDAT and reset the zlib output buffer */
- png_write_IDAT(png_ptr, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- }
+ png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);
png_ptr->flush_rows = 0;
png_flush(png_ptr);
}
-#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+#endif /* WRITE_FLUSH */
-/* free all memory used by the write */
+/* Free any memory used in png_ptr struct without freeing the struct itself. */
+static void
+png_write_destroy(png_structrp png_ptr)
+{
+ png_debug(1, "in png_write_destroy");
+
+ /* Free any memory zlib uses */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
+ deflateEnd(&png_ptr->zstream);
+
+ /* Free our memory. png_free checks NULL for us. */
+ png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_ptr->row_buf = NULL;
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ png_free(png_ptr, png_ptr->prev_row);
+ png_free(png_ptr, png_ptr->try_row);
+ png_free(png_ptr, png_ptr->tst_row);
+ png_ptr->prev_row = NULL;
+ png_ptr->try_row = NULL;
+ png_ptr->tst_row = NULL;
+#endif
+
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list = NULL;
+#endif
+
+ /* The error handling and memory handling information is left intact at this
+ * point: the jmp_buf may still have to be freed. See png_destroy_png_struct
+ * for how this happens.
+ */
+}
+
+/* Free all memory used by the write.
+ * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for
+ * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free
+ * the passed in info_structs but it would quietly fail to free any of the data
+ * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it
+ * has no png_ptr.)
+ */
void PNGAPI
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
{
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_free_ptr free_fn = NULL;
- png_voidp mem_ptr = NULL;
-#endif
+ png_debug(1, "in png_destroy_write_struct");
- png_debug(1, "in png_destroy_write_struct\n");
if (png_ptr_ptr != NULL)
{
- png_ptr = *png_ptr_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- free_fn = png_ptr->free_fn;
- mem_ptr = png_ptr->mem_ptr;
-#endif
- }
+ png_structrp png_ptr = *png_ptr_ptr;
- if (info_ptr_ptr != NULL)
- info_ptr = *info_ptr_ptr;
-
- if (info_ptr != NULL)
- {
- png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
-
-#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
- if (png_ptr->num_chunk_list)
+ if (png_ptr != NULL) /* added in libpng 1.6.0 */
{
- png_free(png_ptr, png_ptr->chunk_list);
- png_ptr->chunk_list=NULL;
- png_ptr->num_chunk_list=0;
+ png_destroy_info_struct(png_ptr, info_ptr_ptr);
+
+ *png_ptr_ptr = NULL;
+ png_write_destroy(png_ptr);
+ png_destroy_png_struct(png_ptr);
}
-#endif
-
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
- (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)info_ptr);
-#endif
- *info_ptr_ptr = NULL;
}
-
- if (png_ptr != NULL)
- {
- png_write_destroy(png_ptr);
-#ifdef PNG_USER_MEM_SUPPORTED
- png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
- (png_voidp)mem_ptr);
-#else
- png_destroy_struct((png_voidp)png_ptr);
-#endif
- *png_ptr_ptr = NULL;
- }
-}
-
-
-/* Free any memory used in png_ptr struct (old method) */
-void /* PRIVATE */
-png_write_destroy(png_structp png_ptr)
-{
-#ifdef PNG_SETJMP_SUPPORTED
- jmp_buf tmp_jmp; /* save jump buffer */
-#endif
- png_error_ptr error_fn;
- png_error_ptr warning_fn;
- png_voidp error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_free_ptr free_fn;
-#endif
-
- png_debug(1, "in png_write_destroy\n");
- /* free any memory zlib uses */
- deflateEnd(&png_ptr->zstream);
-
- /* free our memory. png_free checks NULL for us. */
- png_free(png_ptr, png_ptr->zbuf);
- png_free(png_ptr, png_ptr->row_buf);
-#ifndef PNG_NO_WRITE_FILTERING
- png_free(png_ptr, png_ptr->prev_row);
- png_free(png_ptr, png_ptr->sub_row);
- png_free(png_ptr, png_ptr->up_row);
- png_free(png_ptr, png_ptr->avg_row);
- png_free(png_ptr, png_ptr->paeth_row);
-#endif
-
-#if defined(PNG_TIME_RFC1123_SUPPORTED)
- png_free(png_ptr, png_ptr->time_buffer);
-#endif
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- png_free(png_ptr, png_ptr->prev_filters);
- png_free(png_ptr, png_ptr->filter_weights);
- png_free(png_ptr, png_ptr->inv_filter_weights);
- png_free(png_ptr, png_ptr->filter_costs);
- png_free(png_ptr, png_ptr->inv_filter_costs);
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
- /* reset structure */
- png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
-#endif
-
- error_fn = png_ptr->error_fn;
- warning_fn = png_ptr->warning_fn;
- error_ptr = png_ptr->error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- free_fn = png_ptr->free_fn;
-#endif
-
- png_memset(png_ptr, 0, png_sizeof (png_struct));
-
- png_ptr->error_fn = error_fn;
- png_ptr->warning_fn = warning_fn;
- png_ptr->error_ptr = error_ptr;
-#ifdef PNG_USER_MEM_SUPPORTED
- png_ptr->free_fn = free_fn;
-#endif
-
-#ifdef PNG_SETJMP_SUPPORTED
- png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
-#endif
}
/* Allow the application to select one or more row filters to use. */
void PNGAPI
-png_set_filter(png_structp png_ptr, int method, int filters)
+png_set_filter(png_structrp png_ptr, int method, int filters)
{
- png_debug(1, "in png_set_filter\n");
+ png_debug(1, "in png_set_filter");
+
if (png_ptr == NULL)
return;
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
- (method == PNG_INTRAPIXEL_DIFFERENCING))
- method = PNG_FILTER_TYPE_BASE;
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
+ (method == PNG_INTRAPIXEL_DIFFERENCING))
+ method = PNG_FILTER_TYPE_BASE;
+
#endif
if (method == PNG_FILTER_TYPE_BASE)
{
switch (filters & (PNG_ALL_FILTERS | 0x07))
{
-#ifndef PNG_NO_WRITE_FILTER
+#ifdef PNG_WRITE_FILTER_SUPPORTED
case 5:
case 6:
- case 7: png_warning(png_ptr, "Unknown row filter for method 0");
-#endif /* PNG_NO_WRITE_FILTER */
+ case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
+#endif /* WRITE_FILTER */
+ /* FALLTHROUGH */
case PNG_FILTER_VALUE_NONE:
- png_ptr->do_filter=PNG_FILTER_NONE; break;
-#ifndef PNG_NO_WRITE_FILTER
+ png_ptr->do_filter = PNG_FILTER_NONE; break;
+
+#ifdef PNG_WRITE_FILTER_SUPPORTED
case PNG_FILTER_VALUE_SUB:
- png_ptr->do_filter=PNG_FILTER_SUB; break;
+ png_ptr->do_filter = PNG_FILTER_SUB; break;
+
case PNG_FILTER_VALUE_UP:
- png_ptr->do_filter=PNG_FILTER_UP; break;
+ png_ptr->do_filter = PNG_FILTER_UP; break;
+
case PNG_FILTER_VALUE_AVG:
- png_ptr->do_filter=PNG_FILTER_AVG; break;
+ png_ptr->do_filter = PNG_FILTER_AVG; break;
+
case PNG_FILTER_VALUE_PAETH:
- png_ptr->do_filter=PNG_FILTER_PAETH; break;
- default: png_ptr->do_filter = (png_byte)filters; break;
+ png_ptr->do_filter = PNG_FILTER_PAETH; break;
+
+ default:
+ png_ptr->do_filter = (png_byte)filters; break;
#else
- default: png_warning(png_ptr, "Unknown row filter for method 0");
-#endif /* PNG_NO_WRITE_FILTER */
+ default:
+ png_app_error(png_ptr, "Unknown row filter for method 0");
+#endif /* WRITE_FILTER */
}
+#ifdef PNG_WRITE_FILTER_SUPPORTED
/* If we have allocated the row_buf, this means we have already started
* with the image and we should have allocated all of the filter buffers
* that have been selected. If prev_row isn't already allocated, then
* it is too late to start using the filters that need it, since we
* will be missing the data in the previous row. If an application
* wants to start and stop using particular filters during compression,
- * it should start out with all of the filters, and then add and
- * remove them after the start of compression.
+ * it should start out with all of the filters, and then remove them
+ * or add them back after the start of compression.
+ *
+ * NOTE: this is a nasty constraint on the code, because it means that the
+ * prev_row buffer must be maintained even if there are currently no
+ * 'prev_row' requiring filters active.
*/
if (png_ptr->row_buf != NULL)
{
-#ifndef PNG_NO_WRITE_FILTER
- if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
+ int num_filters;
+ png_alloc_size_t buf_size;
+
+ /* Repeat the checks in png_write_start_row; 1 pixel high or wide
+ * images cannot benefit from certain filters. If this isn't done here
+ * the check below will fire on 1 pixel high images.
+ */
+ if (png_ptr->height == 1)
+ filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if (png_ptr->width == 1)
+ filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0
+ && png_ptr->prev_row == NULL)
{
- png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ /* This is the error case, however it is benign - the previous row
+ * is not available so the filter can't be used. Just warn here.
+ */
+ png_app_warning(png_ptr,
+ "png_set_filter: UP/AVG/PAETH cannot be added after start");
+ filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
}
- if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
- {
- if (png_ptr->prev_row == NULL)
- {
- png_warning(png_ptr, "Can't add Up filter after starting");
- png_ptr->do_filter &= ~PNG_FILTER_UP;
- }
- else
- {
- png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
- }
- }
+ num_filters = 0;
- if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
- {
- if (png_ptr->prev_row == NULL)
- {
- png_warning(png_ptr, "Can't add Average filter after starting");
- png_ptr->do_filter &= ~PNG_FILTER_AVG;
- }
- else
- {
- png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
- }
- }
+ if (filters & PNG_FILTER_SUB)
+ num_filters++;
- if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
- png_ptr->paeth_row == NULL)
- {
- if (png_ptr->prev_row == NULL)
- {
- png_warning(png_ptr, "Can't add Paeth filter after starting");
- png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
- }
- else
- {
- png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
- }
- }
+ if (filters & PNG_FILTER_UP)
+ num_filters++;
- if (png_ptr->do_filter == PNG_NO_FILTERS)
-#endif /* PNG_NO_WRITE_FILTER */
- png_ptr->do_filter = PNG_FILTER_NONE;
+ if (filters & PNG_FILTER_AVG)
+ num_filters++;
+
+ if (filters & PNG_FILTER_PAETH)
+ num_filters++;
+
+ /* Allocate needed row buffers if they have not already been
+ * allocated.
+ */
+ buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth,
+ png_ptr->width) + 1;
+
+ if (png_ptr->try_row == NULL)
+ png_ptr->try_row = png_voidcast(png_bytep,
+ png_malloc(png_ptr, buf_size));
+
+ if (num_filters > 1)
+ {
+ if (png_ptr->tst_row == NULL)
+ png_ptr->tst_row = png_voidcast(png_bytep,
+ png_malloc(png_ptr, buf_size));
+ }
}
+ png_ptr->do_filter = (png_byte)filters;
+#endif
}
else
png_error(png_ptr, "Unknown custom filter method");
}
-/* This allows us to influence the way in which libpng chooses the "best"
- * filter for the current scanline. While the "minimum-sum-of-absolute-
- * differences metric is relatively fast and effective, there is some
- * question as to whether it can be improved upon by trying to keep the
- * filtered data going to zlib more consistent, hopefully resulting in
- * better compression.
- */
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
+/* Provide floating and fixed point APIs */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
-png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
- int num_weights, png_doublep filter_weights,
- png_doublep filter_costs)
+png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,
+ int num_weights, png_const_doublep filter_weights,
+ png_const_doublep filter_costs)
{
- int i;
-
- png_debug(1, "in png_set_filter_heuristics\n");
- if (png_ptr == NULL)
- return;
- if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
- {
- png_warning(png_ptr, "Unknown filter heuristic method");
- return;
- }
-
- if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
- {
- heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
- }
-
- if (num_weights < 0 || filter_weights == NULL ||
- heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
- {
- num_weights = 0;
- }
-
- png_ptr->num_prev_filters = (png_byte)num_weights;
- png_ptr->heuristic_method = (png_byte)heuristic_method;
-
- if (num_weights > 0)
- {
- if (png_ptr->prev_filters == NULL)
- {
- png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_byte) * num_weights));
-
- /* To make sure that the weighting starts out fairly */
- for (i = 0; i < num_weights; i++)
- {
- png_ptr->prev_filters[i] = 255;
- }
- }
-
- if (png_ptr->filter_weights == NULL)
- {
- png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
-
- png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
- for (i = 0; i < num_weights; i++)
- {
- png_ptr->inv_filter_weights[i] =
- png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
- }
- }
-
- for (i = 0; i < num_weights; i++)
- {
- if (filter_weights[i] < 0.0)
- {
- png_ptr->inv_filter_weights[i] =
- png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
- }
- else
- {
- png_ptr->inv_filter_weights[i] =
- (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
- png_ptr->filter_weights[i] =
- (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
- }
- }
- }
-
- /* If, in the future, there are other filter methods, this would
- * need to be based on png_ptr->filter.
- */
- if (png_ptr->filter_costs == NULL)
- {
- png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
-
- png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
-
- for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
- {
- png_ptr->inv_filter_costs[i] =
- png_ptr->filter_costs[i] = PNG_COST_FACTOR;
- }
- }
-
- /* Here is where we set the relative costs of the different filters. We
- * should take the desired compression level into account when setting
- * the costs, so that Paeth, for instance, has a high relative cost at low
- * compression levels, while it has a lower relative cost at higher
- * compression settings. The filter types are in order of increasing
- * relative cost, so it would be possible to do this with an algorithm.
- */
- for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
- {
- if (filter_costs == NULL || filter_costs[i] < 0.0)
- {
- png_ptr->inv_filter_costs[i] =
- png_ptr->filter_costs[i] = PNG_COST_FACTOR;
- }
- else if (filter_costs[i] >= 1.0)
- {
- png_ptr->inv_filter_costs[i] =
- (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
- png_ptr->filter_costs[i] =
- (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
- }
- }
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(heuristic_method)
+ PNG_UNUSED(num_weights)
+ PNG_UNUSED(filter_weights)
+ PNG_UNUSED(filter_costs)
}
-#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+#endif /* FLOATING_POINT */
+#ifdef PNG_FIXED_POINT_SUPPORTED
void PNGAPI
-png_set_compression_level(png_structp png_ptr, int level)
+png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,
+ int num_weights, png_const_fixed_point_p filter_weights,
+ png_const_fixed_point_p filter_costs)
{
- png_debug(1, "in png_set_compression_level\n");
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(heuristic_method)
+ PNG_UNUSED(num_weights)
+ PNG_UNUSED(filter_weights)
+ PNG_UNUSED(filter_costs)
+}
+#endif /* FIXED_POINT */
+#endif /* WRITE_WEIGHTED_FILTER */
+
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+void PNGAPI
+png_set_compression_level(png_structrp png_ptr, int level)
+{
+ png_debug(1, "in png_set_compression_level");
+
if (png_ptr == NULL)
return;
- png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
+
png_ptr->zlib_level = level;
}
void PNGAPI
-png_set_compression_mem_level(png_structp png_ptr, int mem_level)
+png_set_compression_mem_level(png_structrp png_ptr, int mem_level)
{
- png_debug(1, "in png_set_compression_mem_level\n");
+ png_debug(1, "in png_set_compression_mem_level");
+
if (png_ptr == NULL)
return;
- png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
+
png_ptr->zlib_mem_level = mem_level;
}
void PNGAPI
-png_set_compression_strategy(png_structp png_ptr, int strategy)
+png_set_compression_strategy(png_structrp png_ptr, int strategy)
{
- png_debug(1, "in png_set_compression_strategy\n");
+ png_debug(1, "in png_set_compression_strategy");
+
if (png_ptr == NULL)
return;
+
+ /* The flag setting here prevents the libpng dynamic selection of strategy.
+ */
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
png_ptr->zlib_strategy = strategy;
}
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
void PNGAPI
-png_set_compression_window_bits(png_structp png_ptr, int window_bits)
+png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
{
+ png_debug(1, "in png_set_compression_window_bits");
+
if (png_ptr == NULL)
return;
+
+ /* Prior to 1.6.0 this would warn but then set the window_bits value. This
+ * meant that negative window bits values could be selected that would cause
+ * libpng to write a non-standard PNG file with raw deflate or gzip
+ * compressed IDAT or ancillary chunks. Such files can be read and there is
+ * no warning on read, so this seems like a very bad idea.
+ */
if (window_bits > 15)
+ {
png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ window_bits = 15;
+ }
+
else if (window_bits < 8)
+ {
png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
-#ifndef WBITS_8_OK
- /* avoid libpng bug with 256-byte windows */
- if (window_bits == 8)
- {
- png_warning(png_ptr, "Compression window is being reset to 512");
- window_bits=9;
- }
-#endif
- png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
+ window_bits = 8;
+ }
+
png_ptr->zlib_window_bits = window_bits;
}
void PNGAPI
-png_set_compression_method(png_structp png_ptr, int method)
+png_set_compression_method(png_structrp png_ptr, int method)
{
- png_debug(1, "in png_set_compression_method\n");
+ png_debug(1, "in png_set_compression_method");
+
if (png_ptr == NULL)
return;
+
+ /* This would produce an invalid PNG file if it worked, but it doesn't and
+ * deflate will fault it, so it is harmless to just warn here.
+ */
if (method != 8)
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
- png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
+
png_ptr->zlib_method = method;
}
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
+
+/* The following were added to libpng-1.5.4 */
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+void PNGAPI
+png_set_text_compression_level(png_structrp png_ptr, int level)
+{
+ png_debug(1, "in png_set_text_compression_level");
+
+ if (png_ptr == NULL)
+ return;
+
+ png_ptr->zlib_text_level = level;
+}
void PNGAPI
-png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
+png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)
{
+ png_debug(1, "in png_set_text_compression_mem_level");
+
if (png_ptr == NULL)
return;
+
+ png_ptr->zlib_text_mem_level = mem_level;
+}
+
+void PNGAPI
+png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
+{
+ png_debug(1, "in png_set_text_compression_strategy");
+
+ if (png_ptr == NULL)
+ return;
+
+ png_ptr->zlib_text_strategy = strategy;
+}
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+void PNGAPI
+png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
+{
+ png_debug(1, "in png_set_text_compression_window_bits");
+
+ if (png_ptr == NULL)
+ return;
+
+ if (window_bits > 15)
+ {
+ png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ window_bits = 15;
+ }
+
+ else if (window_bits < 8)
+ {
+ png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
+ window_bits = 8;
+ }
+
+ png_ptr->zlib_text_window_bits = window_bits;
+}
+
+void PNGAPI
+png_set_text_compression_method(png_structrp png_ptr, int method)
+{
+ png_debug(1, "in png_set_text_compression_method");
+
+ if (png_ptr == NULL)
+ return;
+
+ if (method != 8)
+ png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+
+ png_ptr->zlib_text_method = method;
+}
+#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
+/* end of API added to libpng-1.5.4 */
+
+void PNGAPI
+png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)
+{
+ png_debug(1, "in png_set_write_status_fn");
+
+ if (png_ptr == NULL)
+ return;
+
png_ptr->write_row_fn = write_row_fn;
}
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
void PNGAPI
-png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
- write_user_transform_fn)
+png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
+ write_user_transform_fn)
{
- png_debug(1, "in png_set_write_user_transform_fn\n");
+ png_debug(1, "in png_set_write_user_transform_fn");
+
if (png_ptr == NULL)
return;
+
png_ptr->transformations |= PNG_USER_TRANSFORM;
png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
-#if defined(PNG_INFO_IMAGE_SUPPORTED)
+#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
-png_write_png(png_structp png_ptr, png_infop info_ptr,
- int transforms, voidp params)
+png_write_png(png_structrp png_ptr, png_inforp info_ptr,
+ int transforms, voidp params)
{
+ png_debug(1, "in png_write_png");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
-#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
- /* invert the alpha channel from opacity to transparency */
- if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
- png_set_invert_alpha(png_ptr);
-#endif
+
+ if ((info_ptr->valid & PNG_INFO_IDAT) == 0)
+ {
+ png_app_error(png_ptr, "no rows for png_write_image to write");
+ return;
+ }
/* Write the file header information. */
png_write_info(png_ptr, info_ptr);
/* ------ these transformations don't touch the info structure ------- */
-#if defined(PNG_WRITE_INVERT_SUPPORTED)
- /* invert monochrome pixels */
- if (transforms & PNG_TRANSFORM_INVERT_MONO)
- png_set_invert_mono(png_ptr);
+ /* Invert monochrome pixels */
+ if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
+#ifdef PNG_WRITE_INVERT_SUPPORTED
+ png_set_invert_mono(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
#endif
-#if defined(PNG_WRITE_SHIFT_SUPPORTED)
/* Shift the pixels up to a legal bit depth and fill in
* as appropriate to correctly scale the image.
*/
- if ((transforms & PNG_TRANSFORM_SHIFT)
- && (info_ptr->valid & PNG_INFO_sBIT))
- png_set_shift(png_ptr, &info_ptr->sig_bit);
+ if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
+#ifdef PNG_WRITE_SHIFT_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
+ png_set_shift(png_ptr, &info_ptr->sig_bit);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
#endif
-#if defined(PNG_WRITE_PACK_SUPPORTED)
- /* pack pixels into bytes */
- if (transforms & PNG_TRANSFORM_PACKING)
- png_set_packing(png_ptr);
+ /* Pack pixels into bytes */
+ if ((transforms & PNG_TRANSFORM_PACKING) != 0)
+#ifdef PNG_WRITE_PACK_SUPPORTED
+ png_set_packing(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
#endif
-#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
- /* swap location of alpha bytes from ARGB to RGBA */
- if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
- png_set_swap_alpha(png_ptr);
+ /* Swap location of alpha bytes from ARGB to RGBA */
+ if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
+ png_set_swap_alpha(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
#endif
-#if defined(PNG_WRITE_FILLER_SUPPORTED)
- /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
- * RGB (4 channels -> 3 channels). The second parameter is not used.
+ /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
+ * RGB, note that the code expects the input color type to be G or RGB; no
+ * alpha channel.
*/
- if (transforms & PNG_TRANSFORM_STRIP_FILLER)
- png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+ if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|
+ PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)
+ {
+#ifdef PNG_WRITE_FILLER_SUPPORTED
+ if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)
+ {
+ if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
+ png_app_error(png_ptr,
+ "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");
+
+ /* Continue if ignored - this is the pre-1.6.10 behavior */
+ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
+ }
+
+ else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");
+#endif
+ }
+
+ /* Flip BGR pixels to RGB */
+ if ((transforms & PNG_TRANSFORM_BGR) != 0)
+#ifdef PNG_WRITE_BGR_SUPPORTED
+ png_set_bgr(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
#endif
-#if defined(PNG_WRITE_BGR_SUPPORTED)
- /* flip BGR pixels to RGB */
- if (transforms & PNG_TRANSFORM_BGR)
- png_set_bgr(png_ptr);
+ /* Swap bytes of 16-bit files to most significant byte first */
+ if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
+#ifdef PNG_WRITE_SWAP_SUPPORTED
+ png_set_swap(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
#endif
-#if defined(PNG_WRITE_SWAP_SUPPORTED)
- /* swap bytes of 16-bit files to most significant byte first */
- if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
- png_set_swap(png_ptr);
+ /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
+ if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
+#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
+ png_set_packswap(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
#endif
-#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
- /* swap bits of 1, 2, 4 bit packed pixel formats */
- if (transforms & PNG_TRANSFORM_PACKSWAP)
- png_set_packswap(png_ptr);
+ /* Invert the alpha channel from opacity to transparency */
+ if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
+ png_set_invert_alpha(png_ptr);
+#else
+ png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
#endif
/* ----------------------- end of transformations ------------------- */
- /* write the bits */
- if (info_ptr->valid & PNG_INFO_IDAT)
- png_write_image(png_ptr, info_ptr->row_pointers);
+ /* Write the bits */
+ png_write_image(png_ptr, info_ptr->row_pointers);
/* It is REQUIRED to call this to finish writing the rest of the file */
png_write_end(png_ptr, info_ptr);
- transforms = transforms; /* quiet compiler warnings */
- params = params;
+ PNG_UNUSED(params)
}
#endif
-#endif /* PNG_WRITE_SUPPORTED */
+
+
+#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+/* Initialize the write structure - general purpose utility. */
+static int
+png_image_write_init(png_imagep image)
+{
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,
+ png_safe_error, png_safe_warning);
+
+ if (png_ptr != NULL)
+ {
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+
+ if (info_ptr != NULL)
+ {
+ png_controlp control = png_voidcast(png_controlp,
+ png_malloc_warn(png_ptr, (sizeof *control)));
+
+ if (control != NULL)
+ {
+ memset(control, 0, (sizeof *control));
+
+ control->png_ptr = png_ptr;
+ control->info_ptr = info_ptr;
+ control->for_write = 1;
+
+ image->opaque = control;
+ return 1;
+ }
+
+ /* Error clean up */
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ }
+
+ png_destroy_write_struct(&png_ptr, NULL);
+ }
+
+ return png_image_error(image, "png_image_write_: out of memory");
+}
+
+/* Arguments to png_image_write_main: */
+typedef struct
+{
+ /* Arguments: */
+ png_imagep image;
+ png_const_voidp buffer;
+ png_int_32 row_stride;
+ png_const_voidp colormap;
+ int convert_to_8bit;
+ /* Local variables: */
+ png_const_voidp first_row;
+ ptrdiff_t row_bytes;
+ png_voidp local_row;
+ /* Byte count for memory writing */
+ png_bytep memory;
+ png_alloc_size_t memory_bytes; /* not used for STDIO */
+ png_alloc_size_t output_bytes; /* running total */
+} png_image_write_control;
+
+/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to
+ * do any necessary byte swapping. The component order is defined by the
+ * png_image format value.
+ */
+static int
+png_write_image_16bit(png_voidp argument)
+{
+ png_image_write_control *display = png_voidcast(png_image_write_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+
+ png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
+ display->first_row);
+ png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
+ png_uint_16p row_end;
+ unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
+ 3 : 1;
+ int aindex = 0;
+ png_uint_32 y = image->height;
+
+ if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
+ if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ {
+ aindex = -1;
+ ++input_row; /* To point to the first component */
+ ++output_row;
+ }
+ else
+ aindex = (int)channels;
+# else
+ aindex = (int)channels;
+# endif
+ }
+
+ else
+ png_error(png_ptr, "png_write_image: internal call error");
+
+ /* Work out the output row end and count over this, note that the increment
+ * above to 'row' means that row_end can actually be beyond the end of the
+ * row; this is correct.
+ */
+ row_end = output_row + image->width * (channels+1);
+
+ for (; y > 0; --y)
+ {
+ png_const_uint_16p in_ptr = input_row;
+ png_uint_16p out_ptr = output_row;
+
+ while (out_ptr < row_end)
+ {
+ png_uint_16 alpha = in_ptr[aindex];
+ png_uint_32 reciprocal = 0;
+ int c;
+
+ out_ptr[aindex] = alpha;
+
+ /* Calculate a reciprocal. The correct calculation is simply
+ * component/alpha*65535 << 15. (I.e. 15 bits of precision); this
+ * allows correct rounding by adding .5 before the shift. 'reciprocal'
+ * is only initialized when required.
+ */
+ if (alpha > 0 && alpha < 65535)
+ reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
+
+ c = (int)channels;
+ do /* always at least one channel */
+ {
+ png_uint_16 component = *in_ptr++;
+
+ /* The following gives 65535 for an alpha of 0, which is fine,
+ * otherwise if 0/0 is represented as some other value there is more
+ * likely to be a discontinuity which will probably damage
+ * compression when moving from a fully transparent area to a
+ * nearly transparent one. (The assumption here is that opaque
+ * areas tend not to be 0 intensity.)
+ */
+ if (component >= alpha)
+ component = 65535;
+
+ /* component 0 && alpha < 65535)
+ {
+ png_uint_32 calc = component * reciprocal;
+ calc += 16384; /* round to nearest */
+ component = (png_uint_16)(calc >> 15);
+ }
+
+ *out_ptr++ = component;
+ }
+ while (--c > 0);
+
+ /* Skip to next component (skip the intervening alpha channel) */
+ ++in_ptr;
+ ++out_ptr;
+ }
+
+ png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
+ input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
+ }
+
+ return 1;
+}
+
+/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel
+ * is present it must be removed from the components, the components are then
+ * written in sRGB encoding. No components are added or removed.
+ *
+ * Calculate an alpha reciprocal to reverse pre-multiplication. As above the
+ * calculation can be done to 15 bits of accuracy; however, the output needs to
+ * be scaled in the range 0..255*65535, so include that scaling here.
+ */
+# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha))
+
+static png_byte
+png_unpremultiply(png_uint_32 component, png_uint_32 alpha,
+ png_uint_32 reciprocal/*from the above macro*/)
+{
+ /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
+ * is represented as some other value there is more likely to be a
+ * discontinuity which will probably damage compression when moving from a
+ * fully transparent area to a nearly transparent one. (The assumption here
+ * is that opaque areas tend not to be 0 intensity.)
+ *
+ * There is a rounding problem here; if alpha is less than 128 it will end up
+ * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the
+ * output change for this too.
+ */
+ if (component >= alpha || alpha < 128)
+ return 255;
+
+ /* component 0)
+ {
+ /* The test is that alpha/257 (rounded) is less than 255, the first value
+ * that becomes 255 is 65407.
+ * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,
+ * be exact!) [Could also test reciprocal != 0]
+ */
+ if (alpha < 65407)
+ {
+ component *= reciprocal;
+ component += 64; /* round to nearest */
+ component >>= 7;
+ }
+
+ else
+ component *= 255;
+
+ /* Convert the component to sRGB. */
+ return (png_byte)PNG_sRGB_FROM_LINEAR(component);
+ }
+
+ else
+ return 0;
+}
+
+static int
+png_write_image_8bit(png_voidp argument)
+{
+ png_image_write_control *display = png_voidcast(png_image_write_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+
+ png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
+ display->first_row);
+ png_bytep output_row = png_voidcast(png_bytep, display->local_row);
+ png_uint_32 y = image->height;
+ unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
+ 3 : 1;
+
+ if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ {
+ png_bytep row_end;
+ int aindex;
+
+# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
+ if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ {
+ aindex = -1;
+ ++input_row; /* To point to the first component */
+ ++output_row;
+ }
+
+ else
+# endif
+ aindex = (int)channels;
+
+ /* Use row_end in place of a loop counter: */
+ row_end = output_row + image->width * (channels+1);
+
+ for (; y > 0; --y)
+ {
+ png_const_uint_16p in_ptr = input_row;
+ png_bytep out_ptr = output_row;
+
+ while (out_ptr < row_end)
+ {
+ png_uint_16 alpha = in_ptr[aindex];
+ png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
+ png_uint_32 reciprocal = 0;
+ int c;
+
+ /* Scale and write the alpha channel. */
+ out_ptr[aindex] = alphabyte;
+
+ if (alphabyte > 0 && alphabyte < 255)
+ reciprocal = UNP_RECIPROCAL(alpha);
+
+ c = (int)channels;
+ do /* always at least one channel */
+ *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
+ while (--c > 0);
+
+ /* Skip to next component (skip the intervening alpha channel) */
+ ++in_ptr;
+ ++out_ptr;
+ } /* while out_ptr < row_end */
+
+ png_write_row(png_ptr, png_voidcast(png_const_bytep,
+ display->local_row));
+ input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
+ } /* while y */
+ }
+
+ else
+ {
+ /* No alpha channel, so the row_end really is the end of the row and it
+ * is sufficient to loop over the components one by one.
+ */
+ png_bytep row_end = output_row + image->width * channels;
+
+ for (; y > 0; --y)
+ {
+ png_const_uint_16p in_ptr = input_row;
+ png_bytep out_ptr = output_row;
+
+ while (out_ptr < row_end)
+ {
+ png_uint_32 component = *in_ptr++;
+
+ component *= 255;
+ *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);
+ }
+
+ png_write_row(png_ptr, output_row);
+ input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
+ }
+ }
+
+ return 1;
+}
+
+static void
+png_image_set_PLTE(png_image_write_control *display)
+{
+ png_imagep image = display->image;
+ const void *cmap = display->colormap;
+ int entries = image->colormap_entries > 256 ? 256 :
+ (int)image->colormap_entries;
+
+ /* NOTE: the caller must check for cmap != NULL and entries != 0 */
+ png_uint_32 format = image->format;
+ unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
+
+# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
+ defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
+ int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
+ (format & PNG_FORMAT_FLAG_ALPHA) != 0;
+# else
+# define afirst 0
+# endif
+
+# ifdef PNG_FORMAT_BGR_SUPPORTED
+ int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
+# else
+# define bgr 0
+# endif
+
+ int i, num_trans;
+ png_color palette[256];
+ png_byte tRNS[256];
+
+ memset(tRNS, 255, (sizeof tRNS));
+ memset(palette, 0, (sizeof palette));
+
+ for (i=num_trans=0; i= 3) /* RGB */
+ {
+ palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
+ entry[(2 ^ bgr)]);
+ palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
+ entry[1]);
+ palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
+ entry[bgr]);
+ }
+
+ else /* Gray */
+ palette[i].blue = palette[i].red = palette[i].green =
+ (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);
+ }
+
+ else /* alpha */
+ {
+ png_uint_16 alpha = entry[afirst ? 0 : channels-1];
+ png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
+ png_uint_32 reciprocal = 0;
+
+ /* Calculate a reciprocal, as in the png_write_image_8bit code above
+ * this is designed to produce a value scaled to 255*65535 when
+ * divided by 128 (i.e. asr 7).
+ */
+ if (alphabyte > 0 && alphabyte < 255)
+ reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;
+
+ tRNS[i] = alphabyte;
+ if (alphabyte < 255)
+ num_trans = i+1;
+
+ if (channels >= 3) /* RGB */
+ {
+ palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
+ alpha, reciprocal);
+ palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
+ reciprocal);
+ palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
+ reciprocal);
+ }
+
+ else /* gray */
+ palette[i].blue = palette[i].red = palette[i].green =
+ png_unpremultiply(entry[afirst], alpha, reciprocal);
+ }
+ }
+
+ else /* Color-map has sRGB values */
+ {
+ png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
+
+ entry += (unsigned int)i * channels;
+
+ switch (channels)
+ {
+ case 4:
+ tRNS[i] = entry[afirst ? 0 : 3];
+ if (tRNS[i] < 255)
+ num_trans = i+1;
+ /* FALLTHROUGH */
+ case 3:
+ palette[i].blue = entry[afirst + (2 ^ bgr)];
+ palette[i].green = entry[afirst + 1];
+ palette[i].red = entry[afirst + bgr];
+ break;
+
+ case 2:
+ tRNS[i] = entry[1 ^ afirst];
+ if (tRNS[i] < 255)
+ num_trans = i+1;
+ /* FALLTHROUGH */
+ case 1:
+ palette[i].blue = palette[i].red = palette[i].green =
+ entry[afirst];
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+# ifdef afirst
+# undef afirst
+# endif
+# ifdef bgr
+# undef bgr
+# endif
+
+ png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
+ entries);
+
+ if (num_trans > 0)
+ png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
+ num_trans, NULL);
+
+ image->colormap_entries = (png_uint_32)entries;
+}
+
+static int
+png_image_write_main(png_voidp argument)
+{
+ png_image_write_control *display = png_voidcast(png_image_write_control*,
+ argument);
+ png_imagep image = display->image;
+ png_structrp png_ptr = image->opaque->png_ptr;
+ png_inforp info_ptr = image->opaque->info_ptr;
+ png_uint_32 format = image->format;
+
+ /* The following four ints are actually booleans */
+ int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
+ int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
+ int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
+ int write_16bit = linear && (display->convert_to_8bit == 0);
+
+# ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ /* Make sure we error out on any bad situation */
+ png_set_benign_errors(png_ptr, 0/*error*/);
+# endif
+
+ /* Default the 'row_stride' parameter if required, also check the row stride
+ * and total image size to ensure that they are within the system limits.
+ */
+ {
+ unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
+
+ if (image->width <= 0x7fffffffU/channels) /* no overflow */
+ {
+ png_uint_32 check;
+ png_uint_32 png_row_stride = image->width * channels;
+
+ if (display->row_stride == 0)
+ display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
+
+ if (display->row_stride < 0)
+ check = (png_uint_32)(-display->row_stride);
+
+ else
+ check = (png_uint_32)display->row_stride;
+
+ if (check >= png_row_stride)
+ {
+ /* Now check for overflow of the image buffer calculation; this
+ * limits the whole image size to 32 bits for API compatibility with
+ * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
+ */
+ if (image->height > 0xffffffffU/png_row_stride)
+ png_error(image->opaque->png_ptr, "memory image too large");
+ }
+
+ else
+ png_error(image->opaque->png_ptr, "supplied row stride too small");
+ }
+
+ else
+ png_error(image->opaque->png_ptr, "image row stride too large");
+ }
+
+ /* Set the required transforms then write the rows in the correct order. */
+ if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)
+ {
+ if (display->colormap != NULL && image->colormap_entries > 0)
+ {
+ png_uint_32 entries = image->colormap_entries;
+
+ png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
+ entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),
+ PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_image_set_PLTE(display);
+ }
+
+ else
+ png_error(image->opaque->png_ptr,
+ "no color-map for color-mapped image");
+ }
+
+ else
+ png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
+ write_16bit ? 16 : 8,
+ ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +
+ ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* Counter-intuitively the data transformations must be called *after*
+ * png_write_info, not before as in the read code, but the 'set' functions
+ * must still be called before. Just set the color space information, never
+ * write an interlaced image.
+ */
+
+ if (write_16bit != 0)
+ {
+ /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */
+ png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);
+
+ if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ /* color x y */
+ /* white */ 31270, 32900,
+ /* red */ 64000, 33000,
+ /* green */ 30000, 60000,
+ /* blue */ 15000, 6000
+ );
+ }
+
+ else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
+ png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
+
+ /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
+ * space must still be gamma encoded.
+ */
+ else
+ png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
+
+ /* Write the file header. */
+ png_write_info(png_ptr, info_ptr);
+
+ /* Now set up the data transformations (*after* the header is written),
+ * remove the handled transformations from the 'format' flags for checking.
+ *
+ * First check for a little endian system if writing 16-bit files.
+ */
+ if (write_16bit != 0)
+ {
+ png_uint_16 le = 0x0001;
+
+ if ((*(png_const_bytep) & le) != 0)
+ png_set_swap(png_ptr);
+ }
+
+# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
+ if ((format & PNG_FORMAT_FLAG_BGR) != 0)
+ {
+ if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)
+ png_set_bgr(png_ptr);
+ format &= ~PNG_FORMAT_FLAG_BGR;
+ }
+# endif
+
+# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
+ if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
+ {
+ if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)
+ png_set_swap_alpha(png_ptr);
+ format &= ~PNG_FORMAT_FLAG_AFIRST;
+ }
+# endif
+
+ /* If there are 16 or fewer color-map entries we wrote a lower bit depth
+ * above, but the application data is still byte packed.
+ */
+ if (colormap != 0 && image->colormap_entries <= 16)
+ png_set_packing(png_ptr);
+
+ /* That should have handled all (both) the transforms. */
+ if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
+ PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)
+ png_error(png_ptr, "png_write_image: unsupported transformation");
+
+ {
+ png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);
+ ptrdiff_t row_bytes = display->row_stride;
+
+ if (linear != 0)
+ row_bytes *= (sizeof (png_uint_16));
+
+ if (row_bytes < 0)
+ row += (image->height-1) * (-row_bytes);
+
+ display->first_row = row;
+ display->row_bytes = row_bytes;
+ }
+
+ /* Apply 'fast' options if the flag is set. */
+ if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)
+ {
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);
+ /* NOTE: determined by experiment using pngstest, this reflects some
+ * balance between the time to write the image once and the time to read
+ * it about 50 times. The speed-up in pngstest was about 10-20% of the
+ * total (user) time on a heavily loaded system.
+ */
+# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+ png_set_compression_level(png_ptr, 3);
+# endif
+ }
+
+ /* Check for the cases that currently require a pre-transform on the row
+ * before it is written. This only applies when the input is 16-bit and
+ * either there is an alpha channel or it is converted to 8-bit.
+ */
+ if ((linear != 0 && alpha != 0 ) ||
+ (colormap == 0 && display->convert_to_8bit != 0))
+ {
+ png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
+ png_get_rowbytes(png_ptr, info_ptr)));
+ int result;
+
+ display->local_row = row;
+ if (write_16bit != 0)
+ result = png_safe_execute(image, png_write_image_16bit, display);
+ else
+ result = png_safe_execute(image, png_write_image_8bit, display);
+ display->local_row = NULL;
+
+ png_free(png_ptr, row);
+
+ /* Skip the 'write_end' on error: */
+ if (result == 0)
+ return 0;
+ }
+
+ /* Otherwise this is the case where the input is in a format currently
+ * supported by the rest of the libpng write code; call it directly.
+ */
+ else
+ {
+ png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);
+ ptrdiff_t row_bytes = display->row_bytes;
+ png_uint_32 y = image->height;
+
+ for (; y > 0; --y)
+ {
+ png_write_row(png_ptr, row);
+ row += row_bytes;
+ }
+ }
+
+ png_write_end(png_ptr, info_ptr);
+ return 1;
+}
+
+
+static void (PNGCBAPI
+image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size)
+{
+ png_image_write_control *display = png_voidcast(png_image_write_control*,
+ png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);
+ png_alloc_size_t ob = display->output_bytes;
+
+ /* Check for overflow; this should never happen: */
+ if (size <= ((png_alloc_size_t)-1) - ob)
+ {
+ /* I don't think libpng ever does this, but just in case: */
+ if (size > 0)
+ {
+ if (display->memory_bytes >= ob+size) /* writing */
+ memcpy(display->memory+ob, data, size);
+
+ /* Always update the size: */
+ display->output_bytes = ob+size;
+ }
+ }
+
+ else
+ png_error(png_ptr, "png_image_write_to_memory: PNG too big");
+}
+
+static void (PNGCBAPI
+image_memory_flush)(png_structp png_ptr)
+{
+ PNG_UNUSED(png_ptr)
+}
+
+static int
+png_image_write_memory(png_voidp argument)
+{
+ png_image_write_control *display = png_voidcast(png_image_write_control*,
+ argument);
+
+ /* The rest of the memory-specific init and write_main in an error protected
+ * environment. This case needs to use callbacks for the write operations
+ * since libpng has no built in support for writing to memory.
+ */
+ png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,
+ image_memory_write, image_memory_flush);
+
+ return png_image_write_main(display);
+}
+
+int PNGAPI
+png_image_write_to_memory(png_imagep image, void *memory,
+ png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,
+ const void *buffer, png_int_32 row_stride, const void *colormap)
+{
+ /* Write the image to the given buffer, or count the bytes if it is NULL */
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (memory_bytes != NULL && buffer != NULL)
+ {
+ /* This is to give the caller an easier error detection in the NULL
+ * case and guard against uninitialized variable problems:
+ */
+ if (memory == NULL)
+ *memory_bytes = 0;
+
+ if (png_image_write_init(image) != 0)
+ {
+ png_image_write_control display;
+ int result;
+
+ memset(&display, 0, (sizeof display));
+ display.image = image;
+ display.buffer = buffer;
+ display.row_stride = row_stride;
+ display.colormap = colormap;
+ display.convert_to_8bit = convert_to_8bit;
+ display.memory = png_voidcast(png_bytep, memory);
+ display.memory_bytes = *memory_bytes;
+ display.output_bytes = 0;
+
+ result = png_safe_execute(image, png_image_write_memory, &display);
+ png_image_free(image);
+
+ /* write_memory returns true even if we ran out of buffer. */
+ if (result)
+ {
+ /* On out-of-buffer this function returns '0' but still updates
+ * memory_bytes:
+ */
+ if (memory != NULL && display.output_bytes > *memory_bytes)
+ result = 0;
+
+ *memory_bytes = display.output_bytes;
+ }
+
+ return result;
+ }
+
+ else
+ return 0;
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_write_to_memory: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION");
+
+ else
+ return 0;
+}
+
+#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
+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*). */
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (file != NULL && buffer != NULL)
+ {
+ if (png_image_write_init(image) != 0)
+ {
+ png_image_write_control display;
+ int result;
+
+ /* This is slightly evil, but png_init_io doesn't do anything other
+ * than this and we haven't changed the standard IO functions so
+ * this saves a 'safe' function.
+ */
+ image->opaque->png_ptr->io_ptr = file;
+
+ memset(&display, 0, (sizeof display));
+ display.image = image;
+ display.buffer = buffer;
+ display.row_stride = row_stride;
+ display.colormap = colormap;
+ display.convert_to_8bit = convert_to_8bit;
+
+ result = png_safe_execute(image, png_image_write_main, &display);
+ png_image_free(image);
+ return result;
+ }
+
+ else
+ return 0;
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_write_to_stdio: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
+
+ else
+ return 0;
+}
+
+int PNGAPI
+png_image_write_to_file(png_imagep image, const char *file_name,
+ int convert_to_8bit, const void *buffer, png_int_32 row_stride,
+ const void *colormap)
+{
+ /* Write the image to the named file. */
+ if (image != NULL && image->version == PNG_IMAGE_VERSION)
+ {
+ if (file_name != NULL && buffer != NULL)
+ {
+ FILE *fp = fopen(file_name, "wb");
+
+ if (fp != NULL)
+ {
+ if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
+ row_stride, colormap) != 0)
+ {
+ int error; /* from fflush/fclose */
+
+ /* Make sure the file is flushed correctly. */
+ if (fflush(fp) == 0 && ferror(fp) == 0)
+ {
+ if (fclose(fp) == 0)
+ return 1;
+
+ error = errno; /* from fclose */
+ }
+
+ else
+ {
+ error = errno; /* from fflush or ferror */
+ (void)fclose(fp);
+ }
+
+ (void)remove(file_name);
+ /* The image has already been cleaned up; this is just used to
+ * set the error (because the original write succeeded).
+ */
+ return png_image_error(image, strerror(error));
+ }
+
+ else
+ {
+ /* Clean up: just the opened file. */
+ (void)fclose(fp);
+ (void)remove(file_name);
+ return 0;
+ }
+ }
+
+ else
+ return png_image_error(image, strerror(errno));
+ }
+
+ else
+ return png_image_error(image,
+ "png_image_write_to_file: invalid argument");
+ }
+
+ else if (image != NULL)
+ return png_image_error(image,
+ "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
+
+ else
+ return 0;
+}
+#endif /* SIMPLIFIED_WRITE_STDIO */
+#endif /* SIMPLIFIED_WRITE */
+#endif /* WRITE */
diff --git a/PDF/src/pngwtran.c b/PDF/src/pngwtran.c
index 0372fe656..49a13c1e9 100644
--- a/PDF/src/pngwtran.c
+++ b/PDF/src/pngwtran.c
@@ -1,96 +1,32 @@
/* pngwtran.c - transforms the data in a row for PNG writers
*
- * Last changed in libpng 1.2.9 April 14, 2006
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2006 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
+
#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
-/* Transform the data according to the user's wishes. The order of
- * transformations is significant.
- */
-void /* PRIVATE */
-png_do_write_transformations(png_structp png_ptr)
-{
- png_debug(1, "in png_do_write_transformations\n");
-
- if (png_ptr == NULL)
- return;
-
-#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
- if (png_ptr->transformations & PNG_USER_TRANSFORM)
- if(png_ptr->write_user_transform_fn != NULL)
- (*(png_ptr->write_user_transform_fn)) /* user write transform function */
- (png_ptr, /* png_ptr */
- &(png_ptr->row_info), /* row_info: */
- /* png_uint_32 width; width of row */
- /* png_uint_32 rowbytes; number of bytes in row */
- /* png_byte color_type; color type of pixels */
- /* png_byte bit_depth; bit depth of samples */
- /* png_byte channels; number of channels (1-4) */
- /* png_byte pixel_depth; bits per pixel (depth*channels) */
- png_ptr->row_buf + 1); /* start of pixel data for row */
-#endif
-#if defined(PNG_WRITE_FILLER_SUPPORTED)
- if (png_ptr->transformations & PNG_FILLER)
- png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
- png_ptr->flags);
-#endif
-#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_PACKSWAP)
- png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-#if defined(PNG_WRITE_PACK_SUPPORTED)
- if (png_ptr->transformations & PNG_PACK)
- png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
- (png_uint_32)png_ptr->bit_depth);
-#endif
-#if defined(PNG_WRITE_SWAP_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_BYTES)
- png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-#if defined(PNG_WRITE_SHIFT_SUPPORTED)
- if (png_ptr->transformations & PNG_SHIFT)
- png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
- &(png_ptr->shift));
-#endif
-#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
- if (png_ptr->transformations & PNG_SWAP_ALPHA)
- png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_ALPHA)
- png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-#if defined(PNG_WRITE_BGR_SUPPORTED)
- if (png_ptr->transformations & PNG_BGR)
- png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-#if defined(PNG_WRITE_INVERT_SUPPORTED)
- if (png_ptr->transformations & PNG_INVERT_MONO)
- png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-}
-
-#if defined(PNG_WRITE_PACK_SUPPORTED)
+#ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
* row_info bit depth should be 8 (one pixel per byte). The channels
* should be 1 (this only happens on grayscale and paletted images).
*/
-void /* PRIVATE */
+static void
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
{
- png_debug(1, "in png_do_pack\n");
+ png_debug(1, "in png_do_pack");
+
if (row_info->bit_depth == 8 &&
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
-#endif
row_info->channels == 1)
{
switch ((int)bit_depth)
@@ -111,9 +47,12 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
{
if (*sp != 0)
v |= mask;
+
sp++;
+
if (mask > 1)
mask >>= 1;
+
else
{
mask = 0x80;
@@ -122,14 +61,18 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
v = 0;
}
}
+
if (mask != 0x80)
*dp = (png_byte)v;
+
break;
}
+
case 2:
{
png_bytep sp, dp;
- int shift, v;
+ unsigned int shift;
+ int v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -137,12 +80,14 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
dp = row;
shift = 6;
v = 0;
+
for (i = 0; i < row_width; i++)
{
png_byte value;
value = (png_byte)(*sp & 0x03);
v |= (value << shift);
+
if (shift == 0)
{
shift = 6;
@@ -150,18 +95,24 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
dp++;
v = 0;
}
+
else
shift -= 2;
+
sp++;
}
+
if (shift != 6)
*dp = (png_byte)v;
+
break;
}
+
case 4:
{
png_bytep sp, dp;
- int shift, v;
+ unsigned int shift;
+ int v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -169,6 +120,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
dp = row;
shift = 4;
v = 0;
+
for (i = 0; i < row_width; i++)
{
png_byte value;
@@ -183,25 +135,32 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
dp++;
v = 0;
}
+
else
shift -= 4;
sp++;
}
+
if (shift != 4)
*dp = (png_byte)v;
+
break;
}
+
+ default:
+ break;
}
+
row_info->bit_depth = (png_byte)bit_depth;
row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
- row_info->width);
+ row_info->width);
}
}
#endif
-#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+#ifdef PNG_WRITE_SHIFT_SUPPORTED
/* Shift pixel values to take advantage of whole range. Pass the
* true number of bits in bit_depth. The row should be packed
* according to row_info->bit_depth. Thus, if you had a row of
@@ -209,76 +168,84 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
* would pass 3 as bit_depth, and this routine would translate the
* data to 0 to 15.
*/
-void /* PRIVATE */
-png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
+static void
+png_do_shift(png_row_infop row_info, png_bytep row,
+ png_const_color_8p bit_depth)
{
- png_debug(1, "in png_do_shift\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL &&
-#else
- if (
-#endif
- row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ png_debug(1, "in png_do_shift");
+
+ if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
{
int shift_start[4], shift_dec[4];
- int channels = 0;
+ unsigned int channels = 0;
- if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
shift_start[channels] = row_info->bit_depth - bit_depth->red;
shift_dec[channels] = bit_depth->red;
channels++;
+
shift_start[channels] = row_info->bit_depth - bit_depth->green;
shift_dec[channels] = bit_depth->green;
channels++;
+
shift_start[channels] = row_info->bit_depth - bit_depth->blue;
shift_dec[channels] = bit_depth->blue;
channels++;
}
+
else
{
shift_start[channels] = row_info->bit_depth - bit_depth->gray;
shift_dec[channels] = bit_depth->gray;
channels++;
}
- if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+
+ if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
{
shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
shift_dec[channels] = bit_depth->alpha;
channels++;
}
- /* with low row depths, could only be grayscale, so one channel */
+ /* With low row depths, could only be grayscale, so one channel */
if (row_info->bit_depth < 8)
{
png_bytep bp = row;
- png_uint_32 i;
- png_byte mask;
- png_uint_32 row_bytes = row_info->rowbytes;
+ size_t i;
+ unsigned int mask;
+ size_t row_bytes = row_info->rowbytes;
if (bit_depth->gray == 1 && row_info->bit_depth == 2)
mask = 0x55;
+
else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
mask = 0x11;
+
else
mask = 0xff;
for (i = 0; i < row_bytes; i++, bp++)
{
- png_uint_16 v;
int j;
+ unsigned int v, out;
v = *bp;
- *bp = 0;
+ out = 0;
+
for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
{
if (j > 0)
- *bp |= (png_byte)((v << j) & 0xff);
+ out |= v << j;
+
else
- *bp |= (png_byte)((v >> (-j)) & mask);
+ out |= (v >> (-j)) & mask;
}
+
+ *bp = (png_byte)(out & 0xff);
}
}
+
else if (row_info->bit_depth == 8)
{
png_bytep bp = row;
@@ -287,22 +254,26 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
for (i = 0; i < istop; i++, bp++)
{
-
- png_uint_16 v;
+ unsigned int c = i%channels;
int j;
- int c = (int)(i%channels);
+ unsigned int v, out;
v = *bp;
- *bp = 0;
+ out = 0;
+
for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
{
if (j > 0)
- *bp |= (png_byte)((v << j) & 0xff);
+ out |= v << j;
+
else
- *bp |= (png_byte)((v >> (-j)) & 0xff);
+ out |= v >> (-j);
}
+
+ *bp = (png_byte)(out & 0xff);
}
}
+
else
{
png_bytep bp;
@@ -311,20 +282,22 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
for (bp = row, i = 0; i < istop; i++)
{
- int c = (int)(i%channels);
- png_uint_16 value, v;
+ unsigned int c = i%channels;
int j;
+ unsigned int value, v;
- v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
+ v = png_get_uint_16(bp);
value = 0;
+
for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
{
if (j > 0)
- value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
+ value |= v << j;
+
else
- value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
+ value |= v >> (-j);
}
- *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)((value >> 8) & 0xff);
*bp++ = (png_byte)(value & 0xff);
}
}
@@ -332,23 +305,22 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
}
#endif
-#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
-void /* PRIVATE */
+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
+static void
png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_write_swap_alpha\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_debug(1, "in png_do_write_swap_alpha");
+
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
- /* This converts from ARGB to RGBA */
if (row_info->bit_depth == 8)
{
+ /* This converts from ARGB to RGBA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
+
for (i = 0, sp = dp = row; i < row_width; i++)
{
png_byte save = *(sp++);
@@ -358,9 +330,11 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save;
}
}
- /* This converts from AARRGGBB to RRGGBBAA */
+
+#ifdef PNG_WRITE_16BIT_SUPPORTED
else
{
+ /* This converts from AARRGGBB to RRGGBBAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -380,12 +354,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save[1];
}
}
+#endif /* WRITE_16BIT */
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
- /* This converts from AG to GA */
if (row_info->bit_depth == 8)
{
+ /* This converts from AG to GA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -397,9 +373,11 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save;
}
}
- /* This converts from AAGG to GGAA */
+
+#ifdef PNG_WRITE_16BIT_SUPPORTED
else
{
+ /* This converts from AAGG to GGAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -415,49 +393,51 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save[1];
}
}
+#endif /* WRITE_16BIT */
}
}
}
#endif
-#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
-void /* PRIVATE */
+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
+static void
png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
{
- png_debug(1, "in png_do_write_invert_alpha\n");
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL)
-#endif
+ png_debug(1, "in png_do_write_invert_alpha");
+
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
- /* This inverts the alpha channel in RGBA */
if (row_info->bit_depth == 8)
{
- png_bytep sp, dp;
- png_uint_32 i;
- png_uint_32 row_width = row_info->width;
- for (i = 0, sp = dp = row; i < row_width; i++)
- {
- /* does nothing
- *(dp++) = *(sp++);
- *(dp++) = *(sp++);
- *(dp++) = *(sp++);
- */
- sp+=3; dp = sp;
- *(dp++) = (png_byte)(255 - *(sp++));
- }
- }
- /* This inverts the alpha channel in RRGGBBAA */
- else
- {
+ /* This inverts the alpha channel in RGBA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
- /* does nothing
+ /* Does nothing
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ */
+ sp+=3; dp = sp;
+ *dp = (png_byte)(255 - *(sp++));
+ }
+ }
+
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ else
+ {
+ /* This inverts the alpha channel in RRGGBBAA */
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ /* Does nothing
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
@@ -467,15 +447,17 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
*/
sp+=6; dp = sp;
*(dp++) = (png_byte)(255 - *(sp++));
- *(dp++) = (png_byte)(255 - *(sp++));
+ *dp = (png_byte)(255 - *(sp++));
}
}
+#endif /* WRITE_16BIT */
}
+
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
- /* This inverts the alpha channel in GA */
if (row_info->bit_depth == 8)
{
+ /* This inverts the alpha channel in GA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
@@ -486,87 +468,108 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = (png_byte)(255 - *(sp++));
}
}
- /* This inverts the alpha channel in GGAA */
+
+#ifdef PNG_WRITE_16BIT_SUPPORTED
else
{
+ /* This inverts the alpha channel in GGAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
- /* does nothing
+ /* Does nothing
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*/
sp+=2; dp = sp;
*(dp++) = (png_byte)(255 - *(sp++));
- *(dp++) = (png_byte)(255 - *(sp++));
+ *dp = (png_byte)(255 - *(sp++));
}
}
+#endif /* WRITE_16BIT */
}
}
}
#endif
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
-/* undoes intrapixel differencing */
+/* Transform the data according to the user's wishes. The order of
+ * transformations is significant.
+ */
void /* PRIVATE */
-png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
+png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
{
- png_debug(1, "in png_do_write_intrapixel\n");
- if (
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- row != NULL && row_info != NULL &&
+ png_debug(1, "in png_do_write_transformations");
+
+ if (png_ptr == NULL)
+ return;
+
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+ if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
+ if (png_ptr->write_user_transform_fn != NULL)
+ (*(png_ptr->write_user_transform_fn)) /* User write transform
+ function */
+ (png_ptr, /* png_ptr */
+ row_info, /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* size_t rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
- (row_info->color_type & PNG_COLOR_MASK_COLOR))
- {
- int bytes_per_pixel;
- png_uint_32 row_width = row_info->width;
- if (row_info->bit_depth == 8)
- {
- png_bytep rp;
- png_uint_32 i;
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
- bytes_per_pixel = 3;
- else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- bytes_per_pixel = 4;
- else
- return;
+#ifdef PNG_WRITE_FILLER_SUPPORTED
+ if ((png_ptr->transformations & PNG_FILLER) != 0)
+ png_do_strip_channel(row_info, png_ptr->row_buf + 1,
+ !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
+#endif
- for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
- {
- *(rp) = (png_byte)((*rp - *(rp+1))&0xff);
- *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
- }
- }
- else if (row_info->bit_depth == 16)
- {
- png_bytep rp;
- png_uint_32 i;
+#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ png_do_packswap(row_info, png_ptr->row_buf + 1);
+#endif
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
- bytes_per_pixel = 6;
- else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- bytes_per_pixel = 8;
- else
- return;
+#ifdef PNG_WRITE_PACK_SUPPORTED
+ if ((png_ptr->transformations & PNG_PACK) != 0)
+ png_do_pack(row_info, png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->bit_depth);
+#endif
- for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
- {
- png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
- png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
- png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
- png_uint_32 red = (png_uint_32)((s0-s1) & 0xffffL);
- png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL);
- *(rp ) = (png_byte)((red >> 8) & 0xff);
- *(rp+1) = (png_byte)(red & 0xff);
- *(rp+4) = (png_byte)((blue >> 8) & 0xff);
- *(rp+5) = (png_byte)(blue & 0xff);
- }
- }
- }
+#ifdef PNG_WRITE_SWAP_SUPPORTED
+# ifdef PNG_16BIT_SUPPORTED
+ if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
+ png_do_swap(row_info, png_ptr->row_buf + 1);
+# endif
+#endif
+
+#ifdef PNG_WRITE_SHIFT_SUPPORTED
+ if ((png_ptr->transformations & PNG_SHIFT) != 0)
+ png_do_shift(row_info, png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
+ png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
+ png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_WRITE_BGR_SUPPORTED
+ if ((png_ptr->transformations & PNG_BGR) != 0)
+ png_do_bgr(row_info, png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_WRITE_INVERT_SUPPORTED
+ if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
+ png_do_invert(row_info, png_ptr->row_buf + 1);
+#endif
}
-#endif /* PNG_MNG_FEATURES_SUPPORTED */
-#endif /* PNG_WRITE_SUPPORTED */
+#endif /* WRITE_TRANSFORMS */
+#endif /* WRITE */
diff --git a/PDF/src/pngwutil.c b/PDF/src/pngwutil.c
index 64331bb62..14cc4ce36 100644
--- a/PDF/src/pngwutil.c
+++ b/PDF/src/pngwutil.c
@@ -1,17 +1,21 @@
/* pngwutil.c - utilities to write a PNG file
*
- * Last changed in libpng 1.2.20 Septhember 3, 2007
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2007 Glenn Randers-Pehrson
- * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
- * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ * Copyright (c) 2018-2024 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.
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
*/
-#define PNG_INTERNAL
-#include "png.h"
+#include "pngpriv.h"
+
#ifdef PNG_WRITE_SUPPORTED
+#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
* ancillary chunk uses signed (two's complement) numbers.
@@ -19,23 +23,10 @@
void PNGAPI
png_save_uint_32(png_bytep buf, png_uint_32 i)
{
- buf[0] = (png_byte)((i >> 24) & 0xff);
- buf[1] = (png_byte)((i >> 16) & 0xff);
- buf[2] = (png_byte)((i >> 8) & 0xff);
- buf[3] = (png_byte)(i & 0xff);
-}
-
-/* The png_save_int_32 function assumes integers are stored in two's
- * complement format. If this isn't the case, then this routine needs to
- * be modified to write data in two's complement format.
- */
-void PNGAPI
-png_save_int_32(png_bytep buf, png_int_32 i)
-{
- buf[0] = (png_byte)((i >> 24) & 0xff);
- buf[1] = (png_byte)((i >> 16) & 0xff);
- buf[2] = (png_byte)((i >> 8) & 0xff);
- buf[3] = (png_byte)(i & 0xff);
+ buf[0] = (png_byte)((i >> 24) & 0xffU);
+ buf[1] = (png_byte)((i >> 16) & 0xffU);
+ buf[2] = (png_byte)((i >> 8) & 0xffU);
+ buf[3] = (png_byte)( i & 0xffU);
}
/* Place a 16-bit number into a buffer in PNG byte order.
@@ -45,8 +36,130 @@ png_save_int_32(png_bytep buf, png_int_32 i)
void PNGAPI
png_save_uint_16(png_bytep buf, unsigned int i)
{
- buf[0] = (png_byte)((i >> 8) & 0xff);
- buf[1] = (png_byte)(i & 0xff);
+ buf[0] = (png_byte)((i >> 8) & 0xffU);
+ buf[1] = (png_byte)( i & 0xffU);
+}
+#endif
+
+/* Simple function to write the signature. If we have already written
+ * the magic bytes of the signature, or more likely, the PNG stream is
+ * being embedded into another stream and doesn't need its own signature,
+ * we should call png_set_sig_bytes() to tell libpng how many of the
+ * bytes have already been written.
+ */
+void PNGAPI
+png_write_sig(png_structrp png_ptr)
+{
+ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ /* Inform the I/O callback that the signature is being written */
+ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;
+#endif
+
+ /* Write the rest of the 8 byte signature */
+ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
+ (size_t)(8 - png_ptr->sig_bytes));
+
+ if (png_ptr->sig_bytes < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+}
+
+/* Write the start of a PNG chunk. The type is the chunk type.
+ * The total_length is the sum of the lengths of all the data you will be
+ * passing in png_write_chunk_data().
+ */
+static void
+png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,
+ png_uint_32 length)
+{
+ png_byte buf[8];
+
+#if defined(PNG_DEBUG) && (PNG_DEBUG > 0)
+ PNG_CSTRING_FROM_CHUNK(buf, chunk_name);
+ png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);
+#endif
+
+ if (png_ptr == NULL)
+ return;
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ /* Inform the I/O callback that the chunk header is being written.
+ * PNG_IO_CHUNK_HDR requires a single I/O call.
+ */
+ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;
+#endif
+
+ /* Write the length and the chunk name */
+ png_save_uint_32(buf, length);
+ png_save_uint_32(buf + 4, chunk_name);
+ png_write_data(png_ptr, buf, 8);
+
+ /* Put the chunk name into png_ptr->chunk_name */
+ png_ptr->chunk_name = chunk_name;
+
+ /* Reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+
+ png_calculate_crc(png_ptr, buf + 4, 4);
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ /* Inform the I/O callback that chunk data will (possibly) be written.
+ * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
+ */
+ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;
+#endif
+}
+
+void PNGAPI
+png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,
+ png_uint_32 length)
+{
+ png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length);
+}
+
+/* Write the data of a PNG chunk started with png_write_chunk_header().
+ * Note that multiple calls to this function are allowed, and that the
+ * sum of the lengths from these calls *must* add up to the total_length
+ * given to png_write_chunk_header().
+ */
+void PNGAPI
+png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length)
+{
+ /* Write the data, and run the CRC over it */
+ if (png_ptr == NULL)
+ return;
+
+ if (data != NULL && length > 0)
+ {
+ png_write_data(png_ptr, data, length);
+
+ /* Update the CRC after writing the data,
+ * in case the user I/O routine alters it.
+ */
+ png_calculate_crc(png_ptr, data, length);
+ }
+}
+
+/* Finish a chunk started with png_write_chunk_header(). */
+void PNGAPI
+png_write_chunk_end(png_structrp png_ptr)
+{
+ png_byte buf[4];
+
+ if (png_ptr == NULL) return;
+
+#ifdef PNG_IO_STATE_SUPPORTED
+ /* Inform the I/O callback that the chunk CRC is being written.
+ * PNG_IO_CHUNK_CRC requires a single I/O function call.
+ */
+ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;
+#endif
+
+ /* Write the crc in a single operation */
+ png_save_uint_32(buf, png_ptr->crc);
+
+ png_write_data(png_ptr, buf, 4);
}
/* Write a PNG chunk all at once. The type is an array of ASCII characters
@@ -58,331 +171,513 @@ png_save_uint_16(png_bytep buf, unsigned int i)
* png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
* functions instead.
*/
-void PNGAPI
-png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
- png_bytep data, png_size_t length)
+static void
+png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
+ png_const_bytep data, size_t length)
{
- if(png_ptr == NULL) return;
- png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
+ if (png_ptr == NULL)
+ return;
+
+ /* On 64-bit architectures 'length' may not fit in a png_uint_32. */
+ if (length > PNG_UINT_31_MAX)
+ png_error(png_ptr, "length exceeds PNG maximum");
+
+ png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);
png_write_chunk_data(png_ptr, data, length);
png_write_chunk_end(png_ptr);
}
-/* Write the start of a PNG chunk. The type is the chunk type.
- * The total_length is the sum of the lengths of all the data you will be
- * passing in png_write_chunk_data().
- */
+/* This is the API that calls the internal function above. */
void PNGAPI
-png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
- png_uint_32 length)
+png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
+ png_const_bytep data, size_t length)
{
- png_byte buf[4];
- png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
- if(png_ptr == NULL) return;
-
- /* write the length */
- png_save_uint_32(buf, length);
- png_write_data(png_ptr, buf, (png_size_t)4);
-
- /* write the chunk name */
- png_write_data(png_ptr, chunk_name, (png_size_t)4);
- /* reset the crc and run it over the chunk name */
- png_reset_crc(png_ptr);
- png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
+ png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
+ length);
}
-/* Write the data of a PNG chunk started with png_write_chunk_start().
- * Note that multiple calls to this function are allowed, and that the
- * sum of the lengths from these calls *must* add up to the total_length
- * given to png_write_chunk_start().
+/* This is used below to find the size of an image to pass to png_deflate_claim,
+ * so it only needs to be accurate if the size is less than 16384 bytes (the
+ * point at which a lower LZ window size can be used.)
*/
-void PNGAPI
-png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
+static png_alloc_size_t
+png_image_size(png_structrp png_ptr)
{
- /* write the data, and run the CRC over it */
- if(png_ptr == NULL) return;
- if (data != NULL && length > 0)
+ /* Only return sizes up to the maximum of a png_uint_32; do this by limiting
+ * the width and height used to 15 bits.
+ */
+ png_uint_32 h = png_ptr->height;
+
+ if (png_ptr->rowbytes < 32768 && h < 32768)
{
- png_calculate_crc(png_ptr, data, length);
- png_write_data(png_ptr, data, length);
+ if (png_ptr->interlaced != 0)
+ {
+ /* Interlacing makes the image larger because of the replication of
+ * both the filter byte and the padding to a byte boundary.
+ */
+ png_uint_32 w = png_ptr->width;
+ unsigned int pd = png_ptr->pixel_depth;
+ png_alloc_size_t cb_base;
+ int pass;
+
+ for (cb_base=0, pass=0; pass<=6; ++pass)
+ {
+ png_uint_32 pw = PNG_PASS_COLS(w, pass);
+
+ if (pw > 0)
+ cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);
+ }
+
+ return cb_base;
+ }
+
+ else
+ return (png_ptr->rowbytes+1) * h;
+ }
+
+ else
+ return 0xffffffffU;
+}
+
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+ /* This is the code to hack the first two bytes of the deflate stream (the
+ * deflate header) to correct the windowBits value to match the actual data
+ * size. Note that the second argument is the *uncompressed* size but the
+ * first argument is the *compressed* data (and it must be deflate
+ * compressed.)
+ */
+static void
+optimize_cmf(png_bytep data, png_alloc_size_t data_size)
+{
+ /* Optimize the CMF field in the zlib stream. The resultant zlib stream is
+ * still compliant to the stream specification.
+ */
+ if (data_size <= 16384) /* else windowBits must be 15 */
+ {
+ unsigned int z_cmf = data[0]; /* zlib compression method and flags */
+
+ if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
+ {
+ unsigned int z_cinfo;
+ unsigned int half_z_window_size;
+
+ z_cinfo = z_cmf >> 4;
+ half_z_window_size = 1U << (z_cinfo + 7);
+
+ if (data_size <= half_z_window_size) /* else no change */
+ {
+ unsigned int tmp;
+
+ do
+ {
+ half_z_window_size >>= 1;
+ --z_cinfo;
+ }
+ while (z_cinfo > 0 && data_size <= half_z_window_size);
+
+ z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
+
+ data[0] = (png_byte)z_cmf;
+ tmp = data[1] & 0xe0;
+ tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;
+ data[1] = (png_byte)tmp;
+ }
+ }
+ }
+}
+#endif /* WRITE_OPTIMIZE_CMF */
+
+/* Initialize the compressor for the appropriate type of compression. */
+static int
+png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
+ png_alloc_size_t data_size)
+{
+ if (png_ptr->zowner != 0)
+ {
+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)
+ char msg[64];
+
+ PNG_STRING_FROM_CHUNK(msg, owner);
+ msg[4] = ':';
+ msg[5] = ' ';
+ PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner);
+ /* So the message that results is " using zstream"; this is an
+ * internal error, but is very useful for debugging. i18n requirements
+ * are minimal.
+ */
+ (void)png_safecat(msg, (sizeof msg), 10, " using zstream");
+#endif
+#if PNG_RELEASE_BUILD
+ png_warning(png_ptr, msg);
+
+ /* Attempt sane error recovery */
+ if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */
+ {
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT");
+ return Z_STREAM_ERROR;
+ }
+
+ png_ptr->zowner = 0;
+#else
+ png_error(png_ptr, msg);
+#endif
+ }
+
+ {
+ int level = png_ptr->zlib_level;
+ int method = png_ptr->zlib_method;
+ int windowBits = png_ptr->zlib_window_bits;
+ int memLevel = png_ptr->zlib_mem_level;
+ int strategy; /* set below */
+ int ret; /* zlib return code */
+
+ if (owner == png_IDAT)
+ {
+ if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0)
+ strategy = png_ptr->zlib_strategy;
+
+ else if (png_ptr->do_filter != PNG_FILTER_NONE)
+ strategy = PNG_Z_DEFAULT_STRATEGY;
+
+ else
+ strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY;
+ }
+
+ else
+ {
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+ level = png_ptr->zlib_text_level;
+ method = png_ptr->zlib_text_method;
+ windowBits = png_ptr->zlib_text_window_bits;
+ memLevel = png_ptr->zlib_text_mem_level;
+ strategy = png_ptr->zlib_text_strategy;
+#else
+ /* If customization is not supported the values all come from the
+ * IDAT values except for the strategy, which is fixed to the
+ * default. (This is the pre-1.6.0 behavior too, although it was
+ * implemented in a very different way.)
+ */
+ strategy = Z_DEFAULT_STRATEGY;
+#endif
+ }
+
+ /* Adjust 'windowBits' down if larger than 'data_size'; to stop this
+ * happening just pass 32768 as the data_size parameter. Notice that zlib
+ * requires an extra 262 bytes in the window in addition to the data to be
+ * able to see the whole of the data, so if data_size+262 takes us to the
+ * next windowBits size we need to fix up the value later. (Because even
+ * though deflate needs the extra window, inflate does not!)
+ */
+ if (data_size <= 16384)
+ {
+ /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to
+ * work round a Microsoft Visual C misbehavior which, contrary to C-90,
+ * widens the result of the following shift to 64-bits if (and,
+ * apparently, only if) it is used in a test.
+ */
+ unsigned int half_window_size = 1U << (windowBits-1);
+
+ while (data_size + 262 <= half_window_size)
+ {
+ half_window_size >>= 1;
+ --windowBits;
+ }
+ }
+
+ /* Check against the previous initialized values, if any. */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 &&
+ (png_ptr->zlib_set_level != level ||
+ png_ptr->zlib_set_method != method ||
+ png_ptr->zlib_set_window_bits != windowBits ||
+ png_ptr->zlib_set_mem_level != memLevel ||
+ png_ptr->zlib_set_strategy != strategy))
+ {
+ if (deflateEnd(&png_ptr->zstream) != Z_OK)
+ png_warning(png_ptr, "deflateEnd failed (ignored)");
+
+ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;
+ }
+
+ /* For safety clear out the input and output pointers (currently zlib
+ * doesn't use them on Init, but it might in the future).
+ */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->zstream.avail_out = 0;
+
+ /* Now initialize if required, setting the new parameters, otherwise just
+ * do a simple reset to the previous parameters.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
+ ret = deflateReset(&png_ptr->zstream);
+
+ else
+ {
+ ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
+ memLevel, strategy);
+
+ if (ret == Z_OK)
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
+ }
+
+ /* The return code is from either deflateReset or deflateInit2; they have
+ * pretty much the same set of error codes.
+ */
+ if (ret == Z_OK)
+ png_ptr->zowner = owner;
+
+ else
+ png_zstream_error(png_ptr, ret);
+
+ return ret;
}
}
-/* Finish a chunk started with png_write_chunk_start(). */
-void PNGAPI
-png_write_chunk_end(png_structp png_ptr)
-{
- png_byte buf[4];
-
- if(png_ptr == NULL) return;
-
- /* write the crc */
- png_save_uint_32(buf, png_ptr->crc);
-
- png_write_data(png_ptr, buf, (png_size_t)4);
-}
-
-/* Simple function to write the signature. If we have already written
- * the magic bytes of the signature, or more likely, the PNG stream is
- * being embedded into another stream and doesn't need its own signature,
- * we should call png_set_sig_bytes() to tell libpng how many of the
- * bytes have already been written.
- */
+/* Clean up (or trim) a linked list of compression buffers. */
void /* PRIVATE */
-png_write_sig(png_structp png_ptr)
+png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
{
- png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
- /* write the rest of the 8 byte signature */
- png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
- (png_size_t)8 - png_ptr->sig_bytes);
- if(png_ptr->sig_bytes < 3)
- png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+ png_compression_bufferp list = *listp;
+
+ if (list != NULL)
+ {
+ *listp = NULL;
+
+ do
+ {
+ png_compression_bufferp next = list->next;
+
+ png_free(png_ptr, list);
+ list = next;
+ }
+ while (list != NULL);
+ }
}
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
-/*
- * This pair of functions encapsulates the operation of (a) compressing a
+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+/* This pair of functions encapsulates the operation of (a) compressing a
* text string, and (b) issuing it later as a series of chunk data writes.
* The compression_state structure is shared context for these functions
- * set up by the caller in order to make the whole mess thread-safe.
+ * set up by the caller to allow access to the relevant local variables.
+ *
+ * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size
+ * temporary buffers. From 1.6.0 it is retained in png_struct so that it will
+ * be correctly freed in the event of a write error (previous implementations
+ * just leaked memory.)
*/
-
typedef struct
{
- char *input; /* the uncompressed input data */
- int input_len; /* its length */
- int num_output_ptr; /* number of output pointers used */
- int max_output_ptr; /* size of output_ptr */
- png_charpp output_ptr; /* array of pointers to output */
+ png_const_bytep input; /* The uncompressed input data */
+ png_alloc_size_t input_len; /* Its length */
+ png_uint_32 output_len; /* Final compressed length */
+ png_byte output[1024]; /* First block of output */
} compression_state;
-/* compress given text into storage in the png_ptr structure */
-static int /* PRIVATE */
-png_text_compress(png_structp png_ptr,
- png_charp text, png_size_t text_len, int compression,
- compression_state *comp)
+static void
+png_text_compress_init(compression_state *comp, png_const_bytep input,
+ png_alloc_size_t input_len)
+{
+ comp->input = input;
+ comp->input_len = input_len;
+ comp->output_len = 0;
+}
+
+/* Compress the data in the compression state input */
+static int
+png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
+ compression_state *comp, png_uint_32 prefix_len)
{
int ret;
- comp->num_output_ptr = 0;
- comp->max_output_ptr = 0;
- comp->output_ptr = NULL;
- comp->input = NULL;
- comp->input_len = 0;
-
- /* we may just want to pass the text right through */
- if (compression == PNG_TEXT_COMPRESSION_NONE)
- {
- comp->input = text;
- comp->input_len = text_len;
- return((int)text_len);
- }
-
- if (compression >= PNG_TEXT_COMPRESSION_LAST)
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char msg[50];
- png_snprintf(msg, 50, "Unknown compression type %d", compression);
- png_warning(png_ptr, msg);
-#else
- png_warning(png_ptr, "Unknown compression type");
-#endif
- }
-
- /* We can't write the chunk until we find out how much data we have,
- * which means we need to run the compressor first and save the
- * output. This shouldn't be a problem, as the vast majority of
- * comments should be reasonable, but we will set up an array of
- * malloc'd pointers to be sure.
+ /* To find the length of the output it is necessary to first compress the
+ * input. The result is buffered rather than using the two-pass algorithm
+ * that is used on the inflate side; deflate is assumed to be slower and a
+ * PNG writer is assumed to have more memory available than a PNG reader.
*
- * If we knew the application was well behaved, we could simplify this
- * greatly by assuming we can always malloc an output buffer large
- * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
- * and malloc this directly. The only time this would be a bad idea is
- * if we can't malloc more than 64K and we have 64K of random input
- * data, or if the input string is incredibly large (although this
- * wouldn't cause a failure, just a slowdown due to swapping).
+ * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an
+ * upper limit on the output size, but it is always bigger than the input
+ * size so it is likely to be more efficient to use this linked-list
+ * approach.
*/
+ ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);
- /* set up the compression buffers */
- png_ptr->zstream.avail_in = (uInt)text_len;
- png_ptr->zstream.next_in = (Bytef *)text;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
+ if (ret != Z_OK)
+ return ret;
- /* this is the same compression loop as in png_write_row() */
- do
+ /* Set up the compression buffers, we need a loop here to avoid overflowing a
+ * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited
+ * by the output buffer size, so there is no need to check that. Since this
+ * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits
+ * in size.
+ */
{
- /* compress the data */
- ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
- if (ret != Z_OK)
+ png_compression_bufferp *end = &png_ptr->zbuffer_list;
+ png_alloc_size_t input_len = comp->input_len; /* may be zero! */
+ png_uint_32 output_len;
+
+ /* zlib updates these for us: */
+ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);
+ png_ptr->zstream.avail_in = 0; /* Set below */
+ png_ptr->zstream.next_out = comp->output;
+ png_ptr->zstream.avail_out = (sizeof comp->output);
+
+ output_len = png_ptr->zstream.avail_out;
+
+ do
{
- /* error */
- if (png_ptr->zstream.msg != NULL)
- png_error(png_ptr, png_ptr->zstream.msg);
- else
- png_error(png_ptr, "zlib error");
- }
- /* check to see if we need more room */
- if (!(png_ptr->zstream.avail_out))
- {
- /* make sure the output array has room */
- if (comp->num_output_ptr >= comp->max_output_ptr)
+ uInt avail_in = ZLIB_IO_MAX;
+
+ if (avail_in > input_len)
+ avail_in = (uInt)input_len;
+
+ input_len -= avail_in;
+
+ png_ptr->zstream.avail_in = avail_in;
+
+ if (png_ptr->zstream.avail_out == 0)
{
- int old_max;
+ png_compression_buffer *next;
- old_max = comp->max_output_ptr;
- comp->max_output_ptr = comp->num_output_ptr + 4;
- if (comp->output_ptr != NULL)
+ /* Chunk data is limited to 2^31 bytes in length, so the prefix
+ * length must be counted here.
+ */
+ if (output_len + prefix_len > PNG_UINT_31_MAX)
{
- png_charpp old_ptr;
-
- old_ptr = comp->output_ptr;
- comp->output_ptr = (png_charpp)png_malloc(png_ptr,
- (png_uint_32)(comp->max_output_ptr *
- png_sizeof (png_charpp)));
- png_memcpy(comp->output_ptr, old_ptr, old_max
- * png_sizeof (png_charp));
- png_free(png_ptr, old_ptr);
+ ret = Z_MEM_ERROR;
+ break;
}
- else
- comp->output_ptr = (png_charpp)png_malloc(png_ptr,
- (png_uint_32)(comp->max_output_ptr *
- png_sizeof (png_charp)));
- }
- /* save the data */
- comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
- (png_uint_32)png_ptr->zbuf_size);
- png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
- png_ptr->zbuf_size);
- comp->num_output_ptr++;
-
- /* and reset the buffer */
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_out = png_ptr->zbuf;
- }
- /* continue until we don't have any more to compress */
- } while (png_ptr->zstream.avail_in);
-
- /* finish the compression */
- do
- {
- /* tell zlib we are finished */
- ret = deflate(&png_ptr->zstream, Z_FINISH);
-
- if (ret == Z_OK)
- {
- /* check to see if we need more room */
- if (!(png_ptr->zstream.avail_out))
- {
- /* check to make sure our output array has room */
- if (comp->num_output_ptr >= comp->max_output_ptr)
+ /* Need a new (malloc'ed) buffer, but there may be one present
+ * already.
+ */
+ next = *end;
+ if (next == NULL)
{
- int old_max;
+ next = png_voidcast(png_compression_bufferp, png_malloc_base
+ (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
- old_max = comp->max_output_ptr;
- comp->max_output_ptr = comp->num_output_ptr + 4;
- if (comp->output_ptr != NULL)
+ if (next == NULL)
{
- png_charpp old_ptr;
-
- old_ptr = comp->output_ptr;
- /* This could be optimized to realloc() */
- comp->output_ptr = (png_charpp)png_malloc(png_ptr,
- (png_uint_32)(comp->max_output_ptr *
- png_sizeof (png_charpp)));
- png_memcpy(comp->output_ptr, old_ptr,
- old_max * png_sizeof (png_charp));
- png_free(png_ptr, old_ptr);
+ ret = Z_MEM_ERROR;
+ break;
}
- else
- comp->output_ptr = (png_charpp)png_malloc(png_ptr,
- (png_uint_32)(comp->max_output_ptr *
- png_sizeof (png_charp)));
+
+ /* Link in this buffer (so that it will be freed later) */
+ next->next = NULL;
+ *end = next;
}
- /* save off the data */
- comp->output_ptr[comp->num_output_ptr] =
- (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
- png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
- png_ptr->zbuf_size);
- comp->num_output_ptr++;
+ png_ptr->zstream.next_out = next->output;
+ png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
+ output_len += png_ptr->zstream.avail_out;
- /* and reset the buffer pointers */
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_out = png_ptr->zbuf;
+ /* Move 'end' to the next buffer pointer. */
+ end = &next->next;
}
+
+ /* Compress the data */
+ ret = deflate(&png_ptr->zstream,
+ input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
+
+ /* Claw back input data that was not consumed (because avail_in is
+ * reset above every time round the loop).
+ */
+ input_len += png_ptr->zstream.avail_in;
+ png_ptr->zstream.avail_in = 0; /* safety */
}
- else if (ret != Z_STREAM_END)
+ while (ret == Z_OK);
+
+ /* There may be some space left in the last output buffer. This needs to
+ * be subtracted from output_len.
+ */
+ output_len -= png_ptr->zstream.avail_out;
+ png_ptr->zstream.avail_out = 0; /* safety */
+ comp->output_len = output_len;
+
+ /* Now double check the output length, put in a custom message if it is
+ * too long. Otherwise ensure the z_stream::msg pointer is set to
+ * something.
+ */
+ if (output_len + prefix_len >= PNG_UINT_31_MAX)
{
- /* we got an error */
- if (png_ptr->zstream.msg != NULL)
- png_error(png_ptr, png_ptr->zstream.msg);
- else
- png_error(png_ptr, "zlib error");
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long");
+ ret = Z_MEM_ERROR;
}
- } while (ret != Z_STREAM_END);
- /* text length is number of buffers plus last buffer */
- text_len = png_ptr->zbuf_size * comp->num_output_ptr;
- if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
- text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
+ else
+ png_zstream_error(png_ptr, ret);
- return((int)text_len);
-}
+ /* Reset zlib for another zTXt/iTXt or image data */
+ png_ptr->zowner = 0;
-/* ship the compressed text out via chunk writes */
-static void /* PRIVATE */
-png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
-{
- int i;
-
- /* handle the no-compression case */
- if (comp->input)
- {
- png_write_chunk_data(png_ptr, (png_bytep)comp->input,
- (png_size_t)comp->input_len);
- return;
- }
-
- /* write saved output buffers, if any */
- for (i = 0; i < comp->num_output_ptr; i++)
- {
- png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
- png_ptr->zbuf_size);
- png_free(png_ptr, comp->output_ptr[i]);
- comp->output_ptr[i]=NULL;
- }
- if (comp->max_output_ptr != 0)
- png_free(png_ptr, comp->output_ptr);
- comp->output_ptr=NULL;
- /* write anything left in zbuf */
- if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
- png_write_chunk_data(png_ptr, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-
- /* reset zlib for another zTXt/iTXt or image data */
- deflateReset(&png_ptr->zstream);
- png_ptr->zstream.data_type = Z_BINARY;
-}
+ /* The only success case is Z_STREAM_END, input_len must be 0; if not this
+ * is an internal error.
+ */
+ if (ret == Z_STREAM_END && input_len == 0)
+ {
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+ /* Fix up the deflate header, if required */
+ optimize_cmf(comp->output, comp->input_len);
#endif
+ /* But Z_OK is returned, not Z_STREAM_END; this allows the claim
+ * function above to return Z_STREAM_END on an error (though it never
+ * does in the current versions of zlib.)
+ */
+ return Z_OK;
+ }
+
+ else
+ return ret;
+ }
+}
+
+/* Ship the compressed text out via chunk writes */
+static void
+png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
+{
+ png_uint_32 output_len = comp->output_len;
+ png_const_bytep output = comp->output;
+ png_uint_32 avail = (sizeof comp->output);
+ png_compression_buffer *next = png_ptr->zbuffer_list;
+
+ for (;;)
+ {
+ if (avail > output_len)
+ avail = output_len;
+
+ png_write_chunk_data(png_ptr, output, avail);
+
+ output_len -= avail;
+
+ if (output_len == 0 || next == NULL)
+ break;
+
+ avail = png_ptr->zbuffer_size;
+ output = next->output;
+ next = next->next;
+ }
+
+ /* This is an internal error; 'next' must have been NULL! */
+ if (output_len > 0)
+ png_error(png_ptr, "error writing ancillary chunked compressed data");
+}
+#endif /* WRITE_COMPRESSED_TEXT */
/* Write the IHDR chunk, and update the png_struct with the necessary
* information. Note that the rest of this code depends upon this
* information being correct.
*/
void /* PRIVATE */
-png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
- int bit_depth, int color_type, int compression_type, int filter_type,
- int interlace_type)
+png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_IHDR;
-#endif
- png_byte buf[13]; /* buffer to store the IHDR info */
+ png_byte buf[13]; /* Buffer to store the IHDR info */
+ int is_invalid_depth;
+
+ png_debug(1, "in png_write_IHDR");
- png_debug(1, "in png_write_IHDR\n");
/* Check that we have valid input data from the application info */
switch (color_type)
{
@@ -393,35 +688,65 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
case 2:
case 4:
case 8:
- case 16: png_ptr->channels = 1; break;
- default: png_error(png_ptr,"Invalid bit depth for grayscale image");
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ case 16:
+#endif
+ png_ptr->channels = 1; break;
+
+ default:
+ png_error(png_ptr,
+ "Invalid bit depth for grayscale image");
}
break;
+
case PNG_COLOR_TYPE_RGB:
- if (bit_depth != 8 && bit_depth != 16)
+ is_invalid_depth = (bit_depth != 8);
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
+#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGB image");
+
png_ptr->channels = 3;
break;
+
case PNG_COLOR_TYPE_PALETTE:
switch (bit_depth)
{
case 1:
case 2:
case 4:
- case 8: png_ptr->channels = 1; break;
- default: png_error(png_ptr, "Invalid bit depth for paletted image");
+ case 8:
+ png_ptr->channels = 1;
+ break;
+
+ default:
+ png_error(png_ptr, "Invalid bit depth for paletted image");
}
break;
+
case PNG_COLOR_TYPE_GRAY_ALPHA:
- if (bit_depth != 8 && bit_depth != 16)
+ is_invalid_depth = (bit_depth != 8);
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
+#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
+
png_ptr->channels = 2;
break;
+
case PNG_COLOR_TYPE_RGB_ALPHA:
- if (bit_depth != 8 && bit_depth != 16)
+ is_invalid_depth = (bit_depth != 8);
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
+#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGBA image");
+
png_ptr->channels = 4;
break;
+
default:
png_error(png_ptr, "Invalid image color type specified");
}
@@ -442,14 +767,14 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
* 5. The color_type is RGB or RGBA
*/
if (
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
- ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
- (color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
- (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
+ ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
- filter_type != PNG_FILTER_TYPE_BASE)
+ filter_type != PNG_FILTER_TYPE_BASE)
{
png_warning(png_ptr, "Invalid filter type specified");
filter_type = PNG_FILTER_TYPE_BASE;
@@ -457,7 +782,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
if (interlace_type != PNG_INTERLACE_NONE &&
- interlace_type != PNG_INTERLACE_ADAM7)
+ interlace_type != PNG_INTERLACE_ADAM7)
{
png_warning(png_ptr, "Invalid interlace type specified");
interlace_type = PNG_INTERLACE_ADAM7;
@@ -466,11 +791,11 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
interlace_type=PNG_INTERLACE_NONE;
#endif
- /* save off the relevent information */
+ /* Save the relevant information */
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->color_type = (png_byte)color_type;
png_ptr->interlaced = (png_byte)interlace_type;
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
+#ifdef PNG_MNG_FEATURES_SUPPORTED
png_ptr->filter_type = (png_byte)filter_type;
#endif
png_ptr->compression_type = (png_byte)compression_type;
@@ -479,12 +804,12 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
- /* set the usr info, so any transformations can modify it */
+ /* Set the usr info, so any transformations can modify it */
png_ptr->usr_width = png_ptr->width;
png_ptr->usr_bit_depth = png_ptr->bit_depth;
png_ptr->usr_channels = png_ptr->channels;
- /* pack the header information into the buffer */
+ /* Pack the header information into the buffer */
png_save_uint_32(buf, width);
png_save_uint_32(buf + 4, height);
buf[8] = (png_byte)bit_depth;
@@ -493,411 +818,463 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
buf[11] = (png_byte)filter_type;
buf[12] = (png_byte)interlace_type;
- /* write the chunk */
- png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+ /* Write the chunk */
+ png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
- /* initialize zlib with PNG info */
- png_ptr->zstream.zalloc = png_zalloc;
- png_ptr->zstream.zfree = png_zfree;
- png_ptr->zstream.opaque = (voidpf)png_ptr;
- if (!(png_ptr->do_filter))
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
- png_ptr->bit_depth < 8)
+ png_ptr->bit_depth < 8)
png_ptr->do_filter = PNG_FILTER_NONE;
+
else
png_ptr->do_filter = PNG_ALL_FILTERS;
}
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
- {
- if (png_ptr->do_filter != PNG_FILTER_NONE)
- png_ptr->zlib_strategy = Z_FILTERED;
- else
- png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
- }
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
- png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
- png_ptr->zlib_mem_level = 8;
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
- png_ptr->zlib_window_bits = 15;
- if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
- png_ptr->zlib_method = 8;
- if (deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
- png_ptr->zlib_method, png_ptr->zlib_window_bits,
- png_ptr->zlib_mem_level, png_ptr->zlib_strategy) != Z_OK)
- png_error(png_ptr, "zlib failed to initialize compressor");
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- /* libpng is not interested in zstream.data_type */
- /* set it to a predefined value, to avoid its evaluation inside zlib */
- png_ptr->zstream.data_type = Z_BINARY;
- png_ptr->mode = PNG_HAVE_IHDR;
+ png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
}
-/* write the palette. We are careful not to trust png_color to be in the
+/* Write the palette. We are careful not to trust png_color to be in the
* correct order for PNG, so people can redefine it to any convenient
* structure.
*/
void /* PRIVATE */
-png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
+png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
+ png_uint_32 num_pal)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_PLTE;
-#endif
- png_uint_32 i;
- png_colorp pal_ptr;
+ png_uint_32 max_palette_length, i;
+ png_const_colorp pal_ptr;
png_byte buf[3];
- png_debug(1, "in png_write_PLTE\n");
+ png_debug(1, "in png_write_PLTE");
+
+ max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+ (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
if ((
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 &&
#endif
- num_pal == 0) || num_pal > 256)
+ num_pal == 0) || num_pal > max_palette_length)
{
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- {
- png_error(png_ptr, "Invalid number of colors in palette");
- }
- else
- {
- png_warning(png_ptr, "Invalid number of colors in palette");
- return;
- }
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_error(png_ptr, "Invalid number of colors in palette");
+ }
+
+ else
+ {
+ png_warning(png_ptr, "Invalid number of colors in palette");
+ return;
+ }
}
- if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
{
png_warning(png_ptr,
- "Ignoring request to write a PLTE chunk in grayscale PNG");
+ "Ignoring request to write a PLTE chunk in grayscale PNG");
+
return;
}
png_ptr->num_palette = (png_uint_16)num_pal;
- png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
+ png_debug1(3, "num_palette = %d", png_ptr->num_palette);
+
+ png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));
+#ifdef PNG_POINTER_INDEXING_SUPPORTED
- png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
-#ifndef PNG_NO_POINTER_INDEXING
for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
{
buf[0] = pal_ptr->red;
buf[1] = pal_ptr->green;
buf[2] = pal_ptr->blue;
- png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ png_write_chunk_data(png_ptr, buf, 3);
}
+
#else
- /* This is a little slower but some buggy compilers need to do this instead */
+ /* This is a little slower but some buggy compilers need to do this
+ * instead
+ */
pal_ptr=palette;
+
for (i = 0; i < num_pal; i++)
{
buf[0] = pal_ptr[i].red;
buf[1] = pal_ptr[i].green;
buf[2] = pal_ptr[i].blue;
- png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ png_write_chunk_data(png_ptr, buf, 3);
}
+
#endif
png_write_chunk_end(png_ptr);
png_ptr->mode |= PNG_HAVE_PLTE;
}
-/* write an IDAT chunk */
+/* This is similar to png_text_compress, above, except that it does not require
+ * all of the data at once and, instead of buffering the compressed result,
+ * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out
+ * because it calls the write interface. As a result it does its own error
+ * reporting and does not return an error code. In the event of error it will
+ * just call png_error. The input data length may exceed 32-bits. The 'flush'
+ * parameter is exactly the same as that to deflate, with the following
+ * meanings:
+ *
+ * Z_NO_FLUSH: normal incremental output of compressed data
+ * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush
+ * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
+ *
+ * The routine manages the acquire and release of the png_ptr->zstream by
+ * checking and (at the end) clearing png_ptr->zowner; it does some sanity
+ * checks on the 'mode' flags while doing this.
+ */
void /* PRIVATE */
-png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
+png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
+ png_alloc_size_t input_len, int flush)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_IDAT;
-#endif
- png_debug(1, "in png_write_IDAT\n");
-
- /* Optimize the CMF field in the zlib stream. */
- /* This hack of the zlib stream is compliant to the stream specification. */
- if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
- png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
+ if (png_ptr->zowner != png_IDAT)
{
- unsigned int z_cmf = data[0]; /* zlib compression method and flags */
- if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
+ /* First time. Ensure we have a temporary buffer for compression and
+ * trim the buffer list if it has more than one entry to free memory.
+ * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been
+ * created at this point, but the check here is quick and safe.
+ */
+ if (png_ptr->zbuffer_list == NULL)
{
- /* Avoid memory underflows and multiplication overflows. */
- /* The conditions below are practically always satisfied;
- however, they still must be checked. */
- if (length >= 2 &&
- png_ptr->height < 16384 && png_ptr->width < 16384)
- {
- png_uint_32 uncompressed_idat_size = png_ptr->height *
- ((png_ptr->width *
- png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
- unsigned int z_cinfo = z_cmf >> 4;
- unsigned int half_z_window_size = 1 << (z_cinfo + 7);
- while (uncompressed_idat_size <= half_z_window_size &&
- half_z_window_size >= 256)
- {
- z_cinfo--;
- half_z_window_size >>= 1;
- }
- z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
- if (data[0] != (png_byte)z_cmf)
- {
- data[0] = (png_byte)z_cmf;
- data[1] &= 0xe0;
- data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
- }
- }
+ png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
+ png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
+ png_ptr->zbuffer_list->next = NULL;
}
+
else
- png_error(png_ptr,
- "Invalid zlib compression method or flags in IDAT");
+ png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next);
+
+ /* It is a terminal error if we can't claim the zstream. */
+ if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
+
+ /* The output state is maintained in png_ptr->zstream, so it must be
+ * initialized here after the claim.
+ */
+ png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;
+ png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
}
- png_write_chunk(png_ptr, png_IDAT, data, length);
- png_ptr->mode |= PNG_HAVE_IDAT;
+ /* Now loop reading and writing until all the input is consumed or an error
+ * terminates the operation. The _out values are maintained across calls to
+ * this function, but the input must be reset each time.
+ */
+ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
+ png_ptr->zstream.avail_in = 0; /* set below */
+ for (;;)
+ {
+ int ret;
+
+ /* INPUT: from the row data */
+ uInt avail = ZLIB_IO_MAX;
+
+ if (avail > input_len)
+ avail = (uInt)input_len; /* safe because of the check */
+
+ png_ptr->zstream.avail_in = avail;
+ input_len -= avail;
+
+ ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush);
+
+ /* Include as-yet unconsumed input */
+ input_len += png_ptr->zstream.avail_in;
+ png_ptr->zstream.avail_in = 0;
+
+ /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note
+ * that these two zstream fields are preserved across the calls, therefore
+ * there is no need to set these up on entry to the loop.
+ */
+ if (png_ptr->zstream.avail_out == 0)
+ {
+ png_bytep data = png_ptr->zbuffer_list->output;
+ uInt size = png_ptr->zbuffer_size;
+
+ /* Write an IDAT containing the data then reset the buffer. The
+ * first IDAT may need deflate header optimization.
+ */
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+ if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
+ png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
+ optimize_cmf(data, png_image_size(png_ptr));
+#endif
+
+ if (size > 0)
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ png_ptr->zstream.next_out = data;
+ png_ptr->zstream.avail_out = size;
+
+ /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with
+ * the same flush parameter until it has finished output, for NO_FLUSH
+ * it doesn't matter.
+ */
+ if (ret == Z_OK && flush != Z_NO_FLUSH)
+ continue;
+ }
+
+ /* The order of these checks doesn't matter much; it just affects which
+ * possible error might be detected if multiple things go wrong at once.
+ */
+ if (ret == Z_OK) /* most likely return code! */
+ {
+ /* If all the input has been consumed then just return. If Z_FINISH
+ * was used as the flush parameter something has gone wrong if we get
+ * here.
+ */
+ if (input_len == 0)
+ {
+ if (flush == Z_FINISH)
+ png_error(png_ptr, "Z_OK on Z_FINISH with output space");
+
+ return;
+ }
+ }
+
+ else if (ret == Z_STREAM_END && flush == Z_FINISH)
+ {
+ /* This is the end of the IDAT data; any pending output must be
+ * flushed. For small PNG files we may still be at the beginning.
+ */
+ png_bytep data = png_ptr->zbuffer_list->output;
+ uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;
+
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+ if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
+ png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
+ optimize_cmf(data, png_image_size(png_ptr));
+#endif
+
+ if (size > 0)
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
+ png_ptr->zstream.avail_out = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+
+ png_ptr->zowner = 0; /* Release the stream */
+ return;
+ }
+
+ else
+ {
+ /* This is an error condition. */
+ png_zstream_error(png_ptr, ret);
+ png_error(png_ptr, png_ptr->zstream.msg);
+ }
+ }
}
-/* write an IEND chunk */
+/* Write an IEND chunk */
void /* PRIVATE */
-png_write_IEND(png_structp png_ptr)
+png_write_IEND(png_structrp png_ptr)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_IEND;
-#endif
- png_debug(1, "in png_write_IEND\n");
- png_write_chunk(png_ptr, png_IEND, png_bytep_NULL,
- (png_size_t)0);
+ png_debug(1, "in png_write_IEND");
+
+ png_write_complete_chunk(png_ptr, png_IEND, NULL, 0);
png_ptr->mode |= PNG_HAVE_IEND;
}
-#if defined(PNG_WRITE_gAMA_SUPPORTED)
-/* write a gAMA chunk */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_WRITE_gAMA_SUPPORTED
+/* Write a gAMA chunk */
void /* PRIVATE */
-png_write_gAMA(png_structp png_ptr, double file_gamma)
+png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_gAMA;
-#endif
- png_uint_32 igamma;
png_byte buf[4];
- png_debug(1, "in png_write_gAMA\n");
- /* file_gamma is saved in 1/100,000ths */
- igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
- png_save_uint_32(buf, igamma);
- png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
-}
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-void /* PRIVATE */
-png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
-{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_gAMA;
-#endif
- png_byte buf[4];
+ png_debug(1, "in png_write_gAMA");
- png_debug(1, "in png_write_gAMA\n");
/* file_gamma is saved in 1/100,000ths */
png_save_uint_32(buf, (png_uint_32)file_gamma);
- png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
+ png_write_complete_chunk(png_ptr, png_gAMA, buf, 4);
}
#endif
-#endif
-#if defined(PNG_WRITE_sRGB_SUPPORTED)
-/* write a sRGB chunk */
+#ifdef PNG_WRITE_sRGB_SUPPORTED
+/* Write a sRGB chunk */
void /* PRIVATE */
-png_write_sRGB(png_structp png_ptr, int srgb_intent)
+png_write_sRGB(png_structrp png_ptr, int srgb_intent)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_sRGB;
-#endif
png_byte buf[1];
- png_debug(1, "in png_write_sRGB\n");
- if(srgb_intent >= PNG_sRGB_INTENT_LAST)
- png_warning(png_ptr,
- "Invalid sRGB rendering intent specified");
+ png_debug(1, "in png_write_sRGB");
+
+ if (srgb_intent >= PNG_sRGB_INTENT_LAST)
+ png_warning(png_ptr,
+ "Invalid sRGB rendering intent specified");
+
buf[0]=(png_byte)srgb_intent;
- png_write_chunk(png_ptr, png_sRGB, buf, (png_size_t)1);
+ png_write_complete_chunk(png_ptr, png_sRGB, buf, 1);
}
#endif
-#if defined(PNG_WRITE_iCCP_SUPPORTED)
-/* write an iCCP chunk */
+#ifdef PNG_WRITE_iCCP_SUPPORTED
+/* Write an iCCP chunk */
void /* PRIVATE */
-png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
- png_charp profile, int profile_len)
+png_write_iCCP(png_structrp png_ptr, png_const_charp name,
+ png_const_bytep profile)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_iCCP;
-#endif
- png_size_t name_len;
- png_charp new_name;
+ png_uint_32 name_len;
+ png_uint_32 profile_len;
+ png_byte new_name[81]; /* 1 byte for the compression byte */
compression_state comp;
- int embedded_profile_len = 0;
+ png_uint_32 temp;
- png_debug(1, "in png_write_iCCP\n");
+ png_debug(1, "in png_write_iCCP");
- comp.num_output_ptr = 0;
- comp.max_output_ptr = 0;
- comp.output_ptr = NULL;
- comp.input = NULL;
- comp.input_len = 0;
+ /* These are all internal problems: the profile should have been checked
+ * before when it was stored.
+ */
+ 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");
+
+ 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)");
- if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
- &new_name)) == 0)
{
- png_warning(png_ptr, "Empty keyword in iCCP chunk");
- return;
+ png_uint_32 embedded_profile_len = png_get_uint_32(profile);
+
+ if (profile_len != embedded_profile_len)
+ png_error(png_ptr, "Profile length does not match profile");
}
- if (compression_type != PNG_COMPRESSION_TYPE_BASE)
- png_warning(png_ptr, "Unknown compression type in iCCP chunk");
+ name_len = png_check_keyword(png_ptr, name, new_name);
- if (profile == NULL)
- profile_len = 0;
+ if (name_len == 0)
+ png_error(png_ptr, "iCCP: invalid keyword");
- if (profile_len > 3)
- embedded_profile_len =
- ((*( (png_bytep)profile ))<<24) |
- ((*( (png_bytep)profile+1))<<16) |
- ((*( (png_bytep)profile+2))<< 8) |
- ((*( (png_bytep)profile+3)) );
+ new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE;
- if (profile_len < embedded_profile_len)
- {
- png_warning(png_ptr,
- "Embedded profile length too large in iCCP chunk");
- return;
- }
+ /* Make sure we include the NULL after the name and the compression type */
+ ++name_len;
- if (profile_len > embedded_profile_len)
- {
- png_warning(png_ptr,
- "Truncating profile to actual length in iCCP chunk");
- profile_len = embedded_profile_len;
- }
+ png_text_compress_init(&comp, profile, profile_len);
- if (profile_len)
- profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
- PNG_COMPRESSION_TYPE_BASE, &comp);
+ /* Allow for keyword terminator and compression byte */
+ if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
- /* make sure we include the NULL after the name and the compression type */
- png_write_chunk_start(png_ptr, png_iCCP,
- (png_uint_32)name_len+profile_len+2);
- new_name[name_len+1]=0x00;
- png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);
+ png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);
- if (profile_len)
- png_write_compressed_data_out(png_ptr, &comp);
+ png_write_chunk_data(png_ptr, new_name, name_len);
+
+ png_write_compressed_data_out(png_ptr, &comp);
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_name);
}
#endif
-#if defined(PNG_WRITE_sPLT_SUPPORTED)
-/* write a sPLT chunk */
+#ifdef PNG_WRITE_sPLT_SUPPORTED
+/* Write a sPLT chunk */
void /* PRIVATE */
-png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
+png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_sPLT;
-#endif
- png_size_t name_len;
- png_charp new_name;
+ png_uint_32 name_len;
+ png_byte new_name[80];
png_byte entrybuf[10];
- int entry_size = (spalette->depth == 8 ? 6 : 10);
- int palette_size = entry_size * spalette->nentries;
+ size_t entry_size = (spalette->depth == 8 ? 6 : 10);
+ size_t palette_size = entry_size * (size_t)spalette->nentries;
png_sPLT_entryp ep;
-#ifdef PNG_NO_POINTER_INDEXING
+#ifndef PNG_POINTER_INDEXING_SUPPORTED
int i;
#endif
- png_debug(1, "in png_write_sPLT\n");
- if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
- spalette->name, &new_name))==0)
- {
- png_warning(png_ptr, "Empty keyword in sPLT chunk");
- return;
- }
+ png_debug(1, "in png_write_sPLT");
- /* make sure we include the NULL after the name */
- png_write_chunk_start(png_ptr, png_sPLT,
- (png_uint_32)(name_len + 2 + palette_size));
- png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
- png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
+ name_len = png_check_keyword(png_ptr, spalette->name, new_name);
- /* loop through each palette entry, writing appropriately */
-#ifndef PNG_NO_POINTER_INDEXING
- for (ep = spalette->entries; epentries+spalette->nentries; ep++)
+ if (name_len == 0)
+ png_error(png_ptr, "sPLT: invalid keyword");
+
+ /* Make sure we include the NULL after the name */
+ png_write_chunk_header(png_ptr, png_sPLT,
+ (png_uint_32)(name_len + 2 + palette_size));
+
+ png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1));
+
+ png_write_chunk_data(png_ptr, &spalette->depth, 1);
+
+ /* Loop through each palette entry, writing appropriately */
+#ifdef PNG_POINTER_INDEXING_SUPPORTED
+ for (ep = spalette->entries; epentries + spalette->nentries; ep++)
{
- if (spalette->depth == 8)
- {
- entrybuf[0] = (png_byte)ep->red;
- entrybuf[1] = (png_byte)ep->green;
- entrybuf[2] = (png_byte)ep->blue;
- entrybuf[3] = (png_byte)ep->alpha;
- png_save_uint_16(entrybuf + 4, ep->frequency);
- }
- else
- {
- png_save_uint_16(entrybuf + 0, ep->red);
- png_save_uint_16(entrybuf + 2, ep->green);
- png_save_uint_16(entrybuf + 4, ep->blue);
- png_save_uint_16(entrybuf + 6, ep->alpha);
- png_save_uint_16(entrybuf + 8, ep->frequency);
- }
- png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep->red;
+ entrybuf[1] = (png_byte)ep->green;
+ entrybuf[2] = (png_byte)ep->blue;
+ entrybuf[3] = (png_byte)ep->alpha;
+ png_save_uint_16(entrybuf + 4, ep->frequency);
+ }
+
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep->red);
+ png_save_uint_16(entrybuf + 2, ep->green);
+ png_save_uint_16(entrybuf + 4, ep->blue);
+ png_save_uint_16(entrybuf + 6, ep->alpha);
+ png_save_uint_16(entrybuf + 8, ep->frequency);
+ }
+
+ png_write_chunk_data(png_ptr, entrybuf, entry_size);
}
#else
ep=spalette->entries;
- for (i=0; i>spalette->nentries; i++)
+ for (i = 0; i>spalette->nentries; i++)
{
- if (spalette->depth == 8)
- {
- entrybuf[0] = (png_byte)ep[i].red;
- entrybuf[1] = (png_byte)ep[i].green;
- entrybuf[2] = (png_byte)ep[i].blue;
- entrybuf[3] = (png_byte)ep[i].alpha;
- png_save_uint_16(entrybuf + 4, ep[i].frequency);
- }
- else
- {
- png_save_uint_16(entrybuf + 0, ep[i].red);
- png_save_uint_16(entrybuf + 2, ep[i].green);
- png_save_uint_16(entrybuf + 4, ep[i].blue);
- png_save_uint_16(entrybuf + 6, ep[i].alpha);
- png_save_uint_16(entrybuf + 8, ep[i].frequency);
- }
- png_write_chunk_data(png_ptr, entrybuf, entry_size);
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep[i].red;
+ entrybuf[1] = (png_byte)ep[i].green;
+ entrybuf[2] = (png_byte)ep[i].blue;
+ entrybuf[3] = (png_byte)ep[i].alpha;
+ png_save_uint_16(entrybuf + 4, ep[i].frequency);
+ }
+
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep[i].red);
+ png_save_uint_16(entrybuf + 2, ep[i].green);
+ png_save_uint_16(entrybuf + 4, ep[i].blue);
+ png_save_uint_16(entrybuf + 6, ep[i].alpha);
+ png_save_uint_16(entrybuf + 8, ep[i].frequency);
+ }
+
+ png_write_chunk_data(png_ptr, entrybuf, entry_size);
}
#endif
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_name);
}
#endif
-#if defined(PNG_WRITE_sBIT_SUPPORTED)
-/* write the sBIT chunk */
+#ifdef PNG_WRITE_sBIT_SUPPORTED
+/* Write the sBIT chunk */
void /* PRIVATE */
-png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
+png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_sBIT;
-#endif
png_byte buf[4];
- png_size_t size;
+ size_t size;
- png_debug(1, "in png_write_sBIT\n");
- /* make sure we don't depend upon the order of PNG_COLOR_8 */
- if (color_type & PNG_COLOR_MASK_COLOR)
+ png_debug(1, "in png_write_sBIT");
+
+ /* Make sure we don't depend upon the order of PNG_COLOR_8 */
+ if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_byte maxbits;
maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
- png_ptr->usr_bit_depth);
+ png_ptr->usr_bit_depth);
+
if (sbit->red == 0 || sbit->red > maxbits ||
sbit->green == 0 || sbit->green > maxbits ||
sbit->blue == 0 || sbit->blue > maxbits)
@@ -905,11 +1282,13 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
+
buf[0] = sbit->red;
buf[1] = sbit->green;
buf[2] = sbit->blue;
size = 3;
}
+
else
{
if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
@@ -917,611 +1296,438 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
+
buf[0] = sbit->gray;
size = 1;
}
- if (color_type & PNG_COLOR_MASK_ALPHA)
+ if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
{
if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
{
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
+
buf[size++] = sbit->alpha;
}
- png_write_chunk(png_ptr, png_sBIT, buf, size);
+ png_write_complete_chunk(png_ptr, png_sBIT, buf, size);
}
#endif
-#if defined(PNG_WRITE_cHRM_SUPPORTED)
-/* write the cHRM chunk */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#ifdef PNG_WRITE_cHRM_SUPPORTED
+/* Write the cHRM chunk */
void /* PRIVATE */
-png_write_cHRM(png_structp png_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)
+png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_cHRM;
-#endif
- png_byte buf[32];
- png_uint_32 itemp;
-
- png_debug(1, "in png_write_cHRM\n");
- /* each value is saved in 1/100,000ths */
- if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
- white_x + white_y > 1.0)
- {
- png_warning(png_ptr, "Invalid cHRM white point specified");
-#if !defined(PNG_NO_CONSOLE_IO)
- fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
-#endif
- return;
- }
- itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
- png_save_uint_32(buf, itemp);
- itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
- png_save_uint_32(buf + 4, itemp);
-
- if (red_x < 0 || red_y < 0 || red_x + red_y > 1.0)
- {
- png_warning(png_ptr, "Invalid cHRM red point specified");
- return;
- }
- itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
- png_save_uint_32(buf + 8, itemp);
- itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
- png_save_uint_32(buf + 12, itemp);
-
- if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
- {
- png_warning(png_ptr, "Invalid cHRM green point specified");
- return;
- }
- itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
- png_save_uint_32(buf + 16, itemp);
- itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
- png_save_uint_32(buf + 20, itemp);
-
- if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
- {
- png_warning(png_ptr, "Invalid cHRM blue point specified");
- return;
- }
- itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
- png_save_uint_32(buf + 24, itemp);
- itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
- png_save_uint_32(buf + 28, itemp);
-
- png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
-}
-#endif
-#ifdef PNG_FIXED_POINT_SUPPORTED
-void /* PRIVATE */
-png_write_cHRM_fixed(png_structp png_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)
-{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_cHRM;
-#endif
png_byte buf[32];
- png_debug(1, "in png_write_cHRM\n");
- /* each value is saved in 1/100,000ths */
- if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
- {
- png_warning(png_ptr, "Invalid fixed cHRM white point specified");
-#if !defined(PNG_NO_CONSOLE_IO)
- fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
-#endif
- return;
- }
- png_save_uint_32(buf, (png_uint_32)white_x);
- png_save_uint_32(buf + 4, (png_uint_32)white_y);
+ png_debug(1, "in png_write_cHRM");
- if (red_x + red_y > 100000L)
- {
- png_warning(png_ptr, "Invalid cHRM fixed red point specified");
- return;
- }
- png_save_uint_32(buf + 8, (png_uint_32)red_x);
- png_save_uint_32(buf + 12, (png_uint_32)red_y);
+ /* Each value is saved in 1/100,000ths */
+ png_save_int_32(buf, xy->whitex);
+ png_save_int_32(buf + 4, xy->whitey);
- if (green_x + green_y > 100000L)
- {
- png_warning(png_ptr, "Invalid fixed cHRM green point specified");
- return;
- }
- png_save_uint_32(buf + 16, (png_uint_32)green_x);
- png_save_uint_32(buf + 20, (png_uint_32)green_y);
+ png_save_int_32(buf + 8, xy->redx);
+ png_save_int_32(buf + 12, xy->redy);
- if (blue_x + blue_y > 100000L)
- {
- png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
- return;
- }
- png_save_uint_32(buf + 24, (png_uint_32)blue_x);
- png_save_uint_32(buf + 28, (png_uint_32)blue_y);
+ png_save_int_32(buf + 16, xy->greenx);
+ png_save_int_32(buf + 20, xy->greeny);
- png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
+ png_save_int_32(buf + 24, xy->bluex);
+ png_save_int_32(buf + 28, xy->bluey);
+
+ png_write_complete_chunk(png_ptr, png_cHRM, buf, 32);
}
#endif
-#endif
-#if defined(PNG_WRITE_tRNS_SUPPORTED)
-/* write the tRNS chunk */
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+/* Write the tRNS chunk */
void /* PRIVATE */
-png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
- int num_trans, int color_type)
+png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
+ png_const_color_16p tran, int num_trans, int color_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_tRNS;
-#endif
png_byte buf[6];
- png_debug(1, "in png_write_tRNS\n");
+ png_debug(1, "in png_write_tRNS");
+
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
{
- png_warning(png_ptr,"Invalid number of transparent colors specified");
+ png_app_warning(png_ptr,
+ "Invalid number of transparent colors specified");
return;
}
- /* write the chunk out as it is */
- png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
+
+ /* Write the chunk out as it is */
+ png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
+ (size_t)num_trans);
}
+
else if (color_type == PNG_COLOR_TYPE_GRAY)
{
- /* one 16 bit value */
- if(tran->gray >= (1 << png_ptr->bit_depth))
+ /* One 16-bit value */
+ if (tran->gray >= (1 << png_ptr->bit_depth))
{
- png_warning(png_ptr,
- "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
+ png_app_warning(png_ptr,
+ "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
+
return;
}
+
png_save_uint_16(buf, tran->gray);
- png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
+ png_write_complete_chunk(png_ptr, png_tRNS, buf, 2);
}
+
else if (color_type == PNG_COLOR_TYPE_RGB)
{
- /* three 16 bit values */
+ /* Three 16-bit values */
png_save_uint_16(buf, tran->red);
png_save_uint_16(buf + 2, tran->green);
png_save_uint_16(buf + 4, tran->blue);
- if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
- {
- png_warning(png_ptr,
- "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
- return;
- }
- png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
+#else
+ if ((buf[0] | buf[2] | buf[4]) != 0)
+#endif
+ {
+ png_app_warning(png_ptr,
+ "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
+ return;
+ }
+
+ png_write_complete_chunk(png_ptr, png_tRNS, buf, 6);
}
+
else
{
- png_warning(png_ptr, "Can't write tRNS with an alpha channel");
+ png_app_warning(png_ptr, "Can't write tRNS with an alpha channel");
}
}
#endif
-#if defined(PNG_WRITE_bKGD_SUPPORTED)
-/* write the background chunk */
+#ifdef PNG_WRITE_bKGD_SUPPORTED
+/* Write the background chunk */
void /* PRIVATE */
-png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
+png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_bKGD;
-#endif
png_byte buf[6];
- png_debug(1, "in png_write_bKGD\n");
+ png_debug(1, "in png_write_bKGD");
+
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
if (
-#if defined(PNG_MNG_FEATURES_SUPPORTED)
- (png_ptr->num_palette ||
- (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+ (png_ptr->num_palette != 0 ||
+ (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&
#endif
- back->index > png_ptr->num_palette)
+ back->index >= png_ptr->num_palette)
{
png_warning(png_ptr, "Invalid background palette index");
return;
}
+
buf[0] = back->index;
- png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
+ png_write_complete_chunk(png_ptr, png_bKGD, buf, 1);
}
- else if (color_type & PNG_COLOR_MASK_COLOR)
+
+ else if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_save_uint_16(buf, back->red);
png_save_uint_16(buf + 2, back->green);
png_save_uint_16(buf + 4, back->blue);
- if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
- {
- png_warning(png_ptr,
- "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
- return;
- }
- png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
- }
- else
- {
- if(back->gray >= (1 << png_ptr->bit_depth))
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
+#else
+ if ((buf[0] | buf[2] | buf[4]) != 0)
+#endif
{
png_warning(png_ptr,
- "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
+ "Ignoring attempt to write 16-bit bKGD chunk "
+ "when bit_depth is 8");
+
return;
}
+
+ png_write_complete_chunk(png_ptr, png_bKGD, buf, 6);
+ }
+
+ else
+ {
+ if (back->gray >= (1 << png_ptr->bit_depth))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
+
+ return;
+ }
+
png_save_uint_16(buf, back->gray);
- png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
+ png_write_complete_chunk(png_ptr, png_bKGD, buf, 2);
}
}
#endif
-#if defined(PNG_WRITE_hIST_SUPPORTED)
-/* write the histogram */
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+/* Write the Exif data */
void /* PRIVATE */
-png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
+png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_hIST;
+ int i;
+ png_byte buf[1];
+
+ png_debug(1, "in png_write_eXIf");
+
+ png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif));
+
+ for (i = 0; i < num_exif; i++)
+ {
+ buf[0] = exif[i];
+ png_write_chunk_data(png_ptr, buf, 1);
+ }
+
+ png_write_chunk_end(png_ptr);
+}
#endif
+
+#ifdef PNG_WRITE_hIST_SUPPORTED
+/* Write the histogram */
+void /* PRIVATE */
+png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
+{
int i;
png_byte buf[3];
- png_debug(1, "in png_write_hIST\n");
+ png_debug(1, "in png_write_hIST");
+
if (num_hist > (int)png_ptr->num_palette)
{
- png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
- png_ptr->num_palette);
+ png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
+ png_ptr->num_palette);
+
png_warning(png_ptr, "Invalid number of histogram entries specified");
return;
}
- png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
+ png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
+
for (i = 0; i < num_hist; i++)
{
png_save_uint_16(buf, hist[i]);
- png_write_chunk_data(png_ptr, buf, (png_size_t)2);
+ png_write_chunk_data(png_ptr, buf, 2);
}
+
png_write_chunk_end(png_ptr);
}
#endif
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
- defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
- * and if invalid, correct the keyword rather than discarding the entire
- * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
- * length, forbids leading or trailing whitespace, multiple internal spaces,
- * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
- *
- * The new_key is allocated to hold the corrected keyword and must be freed
- * by the calling routine. This avoids problems with trying to write to
- * static keywords without having to have duplicate copies of the strings.
- */
-png_size_t /* PRIVATE */
-png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
+#ifdef PNG_WRITE_tEXt_SUPPORTED
+/* Write a tEXt chunk */
+void /* PRIVATE */
+png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
+ size_t text_len)
{
- png_size_t key_len;
- png_charp kp, dp;
- int kflag;
- int kwarn=0;
+ png_uint_32 key_len;
+ png_byte new_key[80];
- png_debug(1, "in png_check_keyword\n");
- *new_key = NULL;
+ png_debug(1, "in png_write_tEXt");
- if (key == NULL || (key_len = png_strlen(key)) == 0)
- {
- png_warning(png_ptr, "zero length keyword");
- return ((png_size_t)0);
- }
-
- png_debug1(2, "Keyword to be checked is '%s'\n", key);
-
- *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
- if (*new_key == NULL)
- {
- png_warning(png_ptr, "Out of memory while procesing keyword");
- return ((png_size_t)0);
- }
-
- /* Replace non-printing characters with a blank and print a warning */
- for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
- {
- if ((png_byte)*kp < 0x20 ||
- ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
- {
-#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
- char msg[40];
-
- png_snprintf(msg, 40,
- "invalid keyword character 0x%02X", (png_byte)*kp);
- png_warning(png_ptr, msg);
-#else
- png_warning(png_ptr, "invalid character in keyword");
-#endif
- *dp = ' ';
- }
- else
- {
- *dp = *kp;
- }
- }
- *dp = '\0';
-
- /* Remove any trailing white space. */
- kp = *new_key + key_len - 1;
- if (*kp == ' ')
- {
- png_warning(png_ptr, "trailing spaces removed from keyword");
-
- while (*kp == ' ')
- {
- *(kp--) = '\0';
- key_len--;
- }
- }
-
- /* Remove any leading white space. */
- kp = *new_key;
- if (*kp == ' ')
- {
- png_warning(png_ptr, "leading spaces removed from keyword");
-
- while (*kp == ' ')
- {
- kp++;
- key_len--;
- }
- }
-
- png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
-
- /* Remove multiple internal spaces. */
- for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
- {
- if (*kp == ' ' && kflag == 0)
- {
- *(dp++) = *kp;
- kflag = 1;
- }
- else if (*kp == ' ')
- {
- key_len--;
- kwarn=1;
- }
- else
- {
- *(dp++) = *kp;
- kflag = 0;
- }
- }
- *dp = '\0';
- if(kwarn)
- png_warning(png_ptr, "extra interior spaces removed from keyword");
+ key_len = png_check_keyword(png_ptr, key, new_key);
if (key_len == 0)
- {
- png_free(png_ptr, *new_key);
- *new_key=NULL;
- png_warning(png_ptr, "Zero length keyword");
- }
-
- if (key_len > 79)
- {
- png_warning(png_ptr, "keyword length must be 1 - 79 characters");
- *new_key[79] = '\0';
- key_len = 79;
- }
-
- return (key_len);
-}
-#endif
-
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
-/* write a tEXt chunk */
-void /* PRIVATE */
-png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
- png_size_t text_len)
-{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_tEXt;
-#endif
- png_size_t key_len;
- png_charp new_key;
-
- png_debug(1, "in png_write_tEXt\n");
- if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
- {
- png_warning(png_ptr, "Empty keyword in tEXt chunk");
- return;
- }
+ png_error(png_ptr, "tEXt: invalid keyword");
if (text == NULL || *text == '\0')
text_len = 0;
- else
- text_len = png_strlen(text);
- /* make sure we include the 0 after the key */
- png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
+ else
+ text_len = strlen(text);
+
+ if (text_len > PNG_UINT_31_MAX - (key_len+1))
+ png_error(png_ptr, "tEXt: text too long");
+
+ /* Make sure we include the 0 after the key */
+ png_write_chunk_header(png_ptr, png_tEXt,
+ (png_uint_32)/*checked above*/(key_len + text_len + 1));
/*
* We leave it to the application to meet PNG-1.0 requirements on the
* contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
* any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
*/
- png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
- if (text_len)
- png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
+ png_write_chunk_data(png_ptr, new_key, key_len + 1);
+
+ if (text_len != 0)
+ png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_key);
}
#endif
-#if defined(PNG_WRITE_zTXt_SUPPORTED)
-/* write a compressed text chunk */
+#ifdef PNG_WRITE_zTXt_SUPPORTED
+/* Write a compressed text chunk */
void /* PRIVATE */
-png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
- png_size_t text_len, int compression)
+png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
+ int compression)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_zTXt;
-#endif
- png_size_t key_len;
- char buf[1];
- png_charp new_key;
+ png_uint_32 key_len;
+ png_byte new_key[81];
compression_state comp;
- png_debug(1, "in png_write_zTXt\n");
+ png_debug(1, "in png_write_zTXt");
- comp.num_output_ptr = 0;
- comp.max_output_ptr = 0;
- comp.output_ptr = NULL;
- comp.input = NULL;
- comp.input_len = 0;
-
- if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ if (compression == PNG_TEXT_COMPRESSION_NONE)
{
- png_warning(png_ptr, "Empty keyword in zTXt chunk");
+ png_write_tEXt(png_ptr, key, text, 0);
return;
}
- if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
- {
- png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
- png_free(png_ptr, new_key);
- return;
- }
+ if (compression != PNG_TEXT_COMPRESSION_zTXt)
+ png_error(png_ptr, "zTXt: invalid compression type");
- text_len = png_strlen(text);
+ key_len = png_check_keyword(png_ptr, key, new_key);
- /* compute the compressed data; do it now for the length */
- text_len = png_text_compress(png_ptr, text, text_len, compression,
- &comp);
+ if (key_len == 0)
+ png_error(png_ptr, "zTXt: invalid keyword");
- /* write start of chunk */
- png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)
- (key_len+text_len+2));
- /* write key */
- png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
- png_free(png_ptr, new_key);
+ /* Add the compression method and 1 for the keyword separator. */
+ new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
+ ++key_len;
- buf[0] = (png_byte)compression;
- /* write compression */
- png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
- /* write the compressed data */
+ /* Compute the compressed data; do it now for the length */
+ png_text_compress_init(&comp, (png_const_bytep)text,
+ text == NULL ? 0 : strlen(text));
+
+ if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
+
+ /* Write start of chunk */
+ png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);
+
+ /* Write key */
+ png_write_chunk_data(png_ptr, new_key, key_len);
+
+ /* Write the compressed data */
png_write_compressed_data_out(png_ptr, &comp);
- /* close the chunk */
+ /* Close the chunk */
png_write_chunk_end(png_ptr);
}
#endif
-#if defined(PNG_WRITE_iTXt_SUPPORTED)
-/* write an iTXt chunk */
+#ifdef PNG_WRITE_iTXt_SUPPORTED
+/* Write an iTXt chunk */
void /* PRIVATE */
-png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
- png_charp lang, png_charp lang_key, png_charp text)
+png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
+ png_const_charp lang, png_const_charp lang_key, png_const_charp text)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_iTXt;
-#endif
- png_size_t lang_len, key_len, lang_key_len, text_len;
- png_charp new_lang, new_key;
- png_byte cbuf[2];
+ png_uint_32 key_len, prefix_len;
+ size_t lang_len, lang_key_len;
+ png_byte new_key[82];
compression_state comp;
- png_debug(1, "in png_write_iTXt\n");
+ png_debug(1, "in png_write_iTXt");
- comp.num_output_ptr = 0;
- comp.max_output_ptr = 0;
- comp.output_ptr = NULL;
- comp.input = NULL;
+ key_len = png_check_keyword(png_ptr, key, new_key);
- if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ if (key_len == 0)
+ png_error(png_ptr, "iTXt: invalid keyword");
+
+ /* Set the compression flag */
+ switch (compression)
{
- png_warning(png_ptr, "Empty keyword in iTXt chunk");
- return;
- }
- if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
- {
- png_warning(png_ptr, "Empty language field in iTXt chunk");
- new_lang = NULL;
- lang_len = 0;
+ case PNG_ITXT_COMPRESSION_NONE:
+ case PNG_TEXT_COMPRESSION_NONE:
+ compression = new_key[++key_len] = 0; /* no compression */
+ break;
+
+ case PNG_TEXT_COMPRESSION_zTXt:
+ case PNG_ITXT_COMPRESSION_zTXt:
+ compression = new_key[++key_len] = 1; /* compressed */
+ break;
+
+ default:
+ png_error(png_ptr, "iTXt: invalid compression");
}
- if (lang_key == NULL)
- lang_key_len = 0;
- else
- lang_key_len = png_strlen(lang_key);
+ new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
+ ++key_len; /* for the keywod separator */
- if (text == NULL)
- text_len = 0;
- else
- text_len = png_strlen(text);
-
- /* compute the compressed data; do it now for the length */
- text_len = png_text_compress(png_ptr, text, text_len, compression-2,
- &comp);
-
-
- /* make sure we include the compression flag, the compression byte,
- * and the NULs after the key, lang, and lang_key parts */
-
- png_write_chunk_start(png_ptr, png_iTXt,
- (png_uint_32)(
- 5 /* comp byte, comp flag, terminators for key, lang and lang_key */
- + key_len
- + lang_len
- + lang_key_len
- + text_len));
-
- /*
- * We leave it to the application to meet PNG-1.0 requirements on the
+ /* We leave it to the application to meet PNG-1.0 requirements on the
* contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
- * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
+ * any non-Latin-1 characters except for NEWLINE. ISO PNG, however,
+ * specifies that the text is UTF-8 and this really doesn't require any
+ * checking.
+ *
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
+ *
+ * TODO: validate the language tag correctly (see the spec.)
*/
- png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+ if (lang == NULL) lang = ""; /* empty language is valid */
+ lang_len = strlen(lang)+1;
+ if (lang_key == NULL) lang_key = ""; /* may be empty */
+ lang_key_len = strlen(lang_key)+1;
+ if (text == NULL) text = ""; /* may be empty */
- /* set the compression flag */
- if (compression == PNG_ITXT_COMPRESSION_NONE || \
- compression == PNG_TEXT_COMPRESSION_NONE)
- cbuf[0] = 0;
- else /* compression == PNG_ITXT_COMPRESSION_zTXt */
- cbuf[0] = 1;
- /* set the compression method */
- cbuf[1] = 0;
- png_write_chunk_data(png_ptr, cbuf, 2);
+ prefix_len = key_len;
+ if (lang_len > PNG_UINT_31_MAX-prefix_len)
+ prefix_len = PNG_UINT_31_MAX;
+ else
+ prefix_len = (png_uint_32)(prefix_len + lang_len);
- cbuf[0] = 0;
- png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
- png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
- png_write_compressed_data_out(png_ptr, &comp);
+ if (lang_key_len > PNG_UINT_31_MAX-prefix_len)
+ prefix_len = PNG_UINT_31_MAX;
+ else
+ prefix_len = (png_uint_32)(prefix_len + lang_key_len);
+
+ png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));
+
+ if (compression != 0)
+ {
+ if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ }
+
+ else
+ {
+ if (comp.input_len > PNG_UINT_31_MAX-prefix_len)
+ png_error(png_ptr, "iTXt: uncompressed text too long");
+
+ /* So the string will fit in a chunk: */
+ comp.output_len = (png_uint_32)/*SAFE*/comp.input_len;
+ }
+
+ png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);
+
+ png_write_chunk_data(png_ptr, new_key, key_len);
+
+ png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len);
+
+ png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);
+
+ if (compression != 0)
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ else
+ png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len);
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_key);
- if (new_lang)
- png_free(png_ptr, new_lang);
}
#endif
-#if defined(PNG_WRITE_oFFs_SUPPORTED)
-/* write the oFFs chunk */
+#ifdef PNG_WRITE_oFFs_SUPPORTED
+/* Write the oFFs chunk */
void /* PRIVATE */
-png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
- int unit_type)
+png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
+ int unit_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_oFFs;
-#endif
png_byte buf[9];
- png_debug(1, "in png_write_oFFs\n");
+ png_debug(1, "in png_write_oFFs");
+
if (unit_type >= PNG_OFFSET_LAST)
png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
@@ -1529,62 +1735,67 @@ png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
png_save_int_32(buf + 4, y_offset);
buf[8] = (png_byte)unit_type;
- png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
+ png_write_complete_chunk(png_ptr, png_oFFs, buf, 9);
}
#endif
-#if defined(PNG_WRITE_pCAL_SUPPORTED)
-/* write the pCAL chunk (described in the PNG extensions document) */
+#ifdef PNG_WRITE_pCAL_SUPPORTED
+/* Write the pCAL chunk (described in the PNG extensions document) */
void /* PRIVATE */
-png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
- png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
+ png_int_32 X1, int type, int nparams, png_const_charp units,
+ png_charpp params)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_pCAL;
-#endif
- png_size_t purpose_len, units_len, total_len;
- png_uint_32p params_len;
+ png_uint_32 purpose_len;
+ size_t units_len, total_len;
+ size_t *params_len;
png_byte buf[10];
- png_charp new_purpose;
+ png_byte new_purpose[80];
int i;
- png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
- if (type >= PNG_EQUATION_LAST)
- png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
- purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
- png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
- units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
- png_debug1(3, "pCAL units length = %d\n", (int)units_len);
+ if (type >= PNG_EQUATION_LAST)
+ png_error(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+ purpose_len = png_check_keyword(png_ptr, purpose, new_purpose);
+
+ if (purpose_len == 0)
+ png_error(png_ptr, "pCAL: invalid keyword");
+
+ ++purpose_len; /* terminator */
+
+ png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
+ units_len = strlen(units) + (nparams == 0 ? 0 : 1);
+ png_debug1(3, "pCAL units length = %d", (int)units_len);
total_len = purpose_len + units_len + 10;
- params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
- *png_sizeof(png_uint_32)));
+ params_len = (size_t *)png_malloc(png_ptr,
+ (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t))));
/* Find the length of each parameter, making sure we don't count the
- null terminator for the last parameter. */
+ * null terminator for the last parameter.
+ */
for (i = 0; i < nparams; i++)
{
- params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
- png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
- total_len += (png_size_t)params_len[i];
+ params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+ png_debug2(3, "pCAL parameter %d length = %lu", i,
+ (unsigned long)params_len[i]);
+ total_len += params_len[i];
}
- png_debug1(3, "pCAL total length = %d\n", (int)total_len);
- png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len);
- png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
+ png_debug1(3, "pCAL total length = %d", (int)total_len);
+ png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, new_purpose, purpose_len);
png_save_int_32(buf, X0);
png_save_int_32(buf + 4, X1);
buf[8] = (png_byte)type;
buf[9] = (png_byte)nparams;
- png_write_chunk_data(png_ptr, buf, (png_size_t)10);
- png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
-
- png_free(png_ptr, new_purpose);
+ png_write_chunk_data(png_ptr, buf, 10);
+ png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len);
for (i = 0; i < nparams; i++)
{
- png_write_chunk_data(png_ptr, (png_bytep)params[i],
- (png_size_t)params_len[i]);
+ png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
}
png_free(png_ptr, params_len);
@@ -1592,63 +1803,21 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
}
#endif
-#if defined(PNG_WRITE_sCAL_SUPPORTED)
-/* write the sCAL chunk */
-#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+#ifdef PNG_WRITE_sCAL_SUPPORTED
+/* Write the sCAL chunk */
void /* PRIVATE */
-png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
+png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,
+ png_const_charp height)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_sCAL;
-#endif
- char buf[64];
- png_size_t total_len;
-
- png_debug(1, "in png_write_sCAL\n");
-
- buf[0] = (char)unit;
-#if defined(_WIN32_WCE)
-/* sprintf() function is not supported on WindowsCE */
- {
- wchar_t wc_buf[32];
- size_t wc_len;
- swprintf(wc_buf, TEXT("%12.12e"), width);
- wc_len = wcslen(wc_buf);
- WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL);
- total_len = wc_len + 2;
- swprintf(wc_buf, TEXT("%12.12e"), height);
- wc_len = wcslen(wc_buf);
- WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len,
- NULL, NULL);
- total_len += wc_len;
- }
-#else
- png_snprintf(buf + 1, 63, "%12.12e", width);
- total_len = 1 + png_strlen(buf + 1) + 1;
- png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
- total_len += png_strlen(buf + total_len);
-#endif
-
- png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
- png_write_chunk(png_ptr, png_sCAL, (png_bytep)buf, total_len);
-}
-#else
-#ifdef PNG_FIXED_POINT_SUPPORTED
-void /* PRIVATE */
-png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
- png_charp height)
-{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_sCAL;
-#endif
png_byte buf[64];
- png_size_t wlen, hlen, total_len;
+ size_t wlen, hlen, total_len;
- png_debug(1, "in png_write_sCAL_s\n");
+ png_debug(1, "in png_write_sCAL_s");
- wlen = png_strlen(width);
- hlen = png_strlen(height);
+ wlen = strlen(width);
+ hlen = strlen(height);
total_len = wlen + hlen + 2;
+
if (total_len > 64)
{
png_warning(png_ptr, "Can't write sCAL (buffer too small)");
@@ -1656,29 +1825,25 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
}
buf[0] = (png_byte)unit;
- png_memcpy(buf + 1, width, wlen + 1); /* append the '\0' here */
- png_memcpy(buf + wlen + 2, height, hlen); /* do NOT append the '\0' here */
+ memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */
+ memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */
- png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
- png_write_chunk(png_ptr, png_sCAL, buf, total_len);
+ png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
+ png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len);
}
#endif
-#endif
-#endif
-#if defined(PNG_WRITE_pHYs_SUPPORTED)
-/* write the pHYs chunk */
+#ifdef PNG_WRITE_pHYs_SUPPORTED
+/* Write the pHYs chunk */
void /* PRIVATE */
-png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
- png_uint_32 y_pixels_per_unit,
- int unit_type)
+png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_pHYs;
-#endif
png_byte buf[9];
- png_debug(1, "in png_write_pHYs\n");
+ png_debug(1, "in png_write_pHYs");
+
if (unit_type >= PNG_RESOLUTION_LAST)
png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
@@ -1686,23 +1851,21 @@ png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
png_save_uint_32(buf + 4, y_pixels_per_unit);
buf[8] = (png_byte)unit_type;
- png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
+ png_write_complete_chunk(png_ptr, png_pHYs, buf, 9);
}
#endif
-#if defined(PNG_WRITE_tIME_SUPPORTED)
+#ifdef PNG_WRITE_tIME_SUPPORTED
/* Write the tIME chunk. Use either png_convert_from_struct_tm()
* or png_convert_from_time_t(), or fill in the structure yourself.
*/
void /* PRIVATE */
-png_write_tIME(png_structp png_ptr, png_timep mod_time)
+png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- PNG_tIME;
-#endif
png_byte buf[7];
- png_debug(1, "in png_write_tIME\n");
+ png_debug(1, "in png_write_tIME");
+
if (mod_time->month > 12 || mod_time->month < 1 ||
mod_time->day > 31 || mod_time->day < 1 ||
mod_time->hour > 23 || mod_time->second > 60)
@@ -1718,221 +1881,210 @@ png_write_tIME(png_structp png_ptr, png_timep mod_time)
buf[5] = mod_time->minute;
buf[6] = mod_time->second;
- png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
+ png_write_complete_chunk(png_ptr, png_tIME, buf, 7);
}
#endif
-/* initializes the row writing capability of libpng */
+/* Initializes the row writing capability of libpng */
void /* PRIVATE */
-png_write_start_row(png_structp png_ptr)
+png_write_start_row(png_structrp png_ptr)
{
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* start of interlace block */
- int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Start of interlace block */
+ static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
- /* offset to next interlace block */
- int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+ /* 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 */
- int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 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 */
- int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
+ /* 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_size_t buf_size;
+ png_alloc_size_t buf_size;
+ int usr_pixel_depth;
- png_debug(1, "in png_write_start_row\n");
- buf_size = (png_size_t)(PNG_ROWBYTES(
- png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ png_byte filters;
+#endif
+
+ png_debug(1, "in png_write_start_row");
+
+ usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
+ buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;
+
+ /* 1.5.6: added to allow checking in the row write code. */
+ png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;
+ png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
+
+ /* Set up row buffer */
+ png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
- /* set up row buffer */
- png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
-#ifndef PNG_NO_WRITE_FILTERING
- /* set up filtering buffer, if using this filter */
- if (png_ptr->do_filter & PNG_FILTER_SUB)
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ filters = png_ptr->do_filter;
+
+ if (png_ptr->height == 1)
+ filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if (png_ptr->width == 1)
+ filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if (filters == 0)
+ filters = PNG_FILTER_NONE;
+
+ png_ptr->do_filter = filters;
+
+ if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG |
+ PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL)
{
- png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ int num_filters = 0;
+
+ png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
+
+ if (filters & PNG_FILTER_SUB)
+ num_filters++;
+
+ if (filters & PNG_FILTER_UP)
+ num_filters++;
+
+ if (filters & PNG_FILTER_AVG)
+ num_filters++;
+
+ if (filters & PNG_FILTER_PAETH)
+ num_filters++;
+
+ if (num_filters > 1)
+ png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,
+ buf_size));
}
- /* We only need to keep the previous row if we are using one of these. */
- if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
- {
- /* set up previous row buffer */
- png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
- png_memset(png_ptr->prev_row, 0, buf_size);
-
- if (png_ptr->do_filter & PNG_FILTER_UP)
- {
- png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
- }
-
- if (png_ptr->do_filter & PNG_FILTER_AVG)
- {
- png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
- }
-
- if (png_ptr->do_filter & PNG_FILTER_PAETH)
- {
- png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
- (png_ptr->rowbytes + 1));
- png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
- }
-#endif /* PNG_NO_WRITE_FILTERING */
- }
+ /* We only need to keep the previous row if we are using one of the following
+ * filters.
+ */
+ if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)
+ png_ptr->prev_row = png_voidcast(png_bytep,
+ png_calloc(png_ptr, buf_size));
+#endif /* WRITE_FILTER */
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
- /* if interlaced, we need to set up width and height of pass */
- if (png_ptr->interlaced)
+ /* If interlaced, we need to set up width and height of pass */
+ if (png_ptr->interlaced != 0)
{
- if (!(png_ptr->transformations & PNG_INTERLACE))
+ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
{
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
- png_pass_ystart[0]) / png_pass_yinc[0];
+ png_pass_ystart[0]) / png_pass_yinc[0];
+
png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
- png_pass_start[0]) / png_pass_inc[0];
+ png_pass_start[0]) / png_pass_inc[0];
}
+
else
{
png_ptr->num_rows = png_ptr->height;
png_ptr->usr_width = png_ptr->width;
}
}
+
else
#endif
{
png_ptr->num_rows = png_ptr->height;
png_ptr->usr_width = png_ptr->width;
}
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- png_ptr->zstream.next_out = png_ptr->zbuf;
}
/* Internal use only. Called when finished processing a row of data. */
void /* PRIVATE */
-png_write_finish_row(png_structp png_ptr)
+png_write_finish_row(png_structrp png_ptr)
{
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* start of interlace block */
- int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Start of interlace block */
+ static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
- /* offset to next interlace block */
- int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+ /* 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 */
- int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 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 */
- int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
+ /* 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
- int ret;
+ png_debug(1, "in png_write_finish_row");
- png_debug(1, "in png_write_finish_row\n");
- /* next row */
+ /* Next row */
png_ptr->row_number++;
- /* see if we are done */
+ /* See if we are done */
if (png_ptr->row_number < png_ptr->num_rows)
return;
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
- /* if interlaced, go to next pass */
- if (png_ptr->interlaced)
+ /* If interlaced, go to next pass */
+ if (png_ptr->interlaced != 0)
{
png_ptr->row_number = 0;
- if (png_ptr->transformations & PNG_INTERLACE)
+ if ((png_ptr->transformations & PNG_INTERLACE) != 0)
{
png_ptr->pass++;
}
+
else
{
- /* loop until we find a non-zero width or height pass */
+ /* Loop until we find a non-zero width or height pass */
do
{
png_ptr->pass++;
+
if (png_ptr->pass >= 7)
break;
+
png_ptr->usr_width = (png_ptr->width +
- png_pass_inc[png_ptr->pass] - 1 -
- png_pass_start[png_ptr->pass]) /
- png_pass_inc[png_ptr->pass];
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
png_ptr->num_rows = (png_ptr->height +
- png_pass_yinc[png_ptr->pass] - 1 -
- png_pass_ystart[png_ptr->pass]) /
- png_pass_yinc[png_ptr->pass];
- if (png_ptr->transformations & PNG_INTERLACE)
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+
+ if ((png_ptr->transformations & PNG_INTERLACE) != 0)
break;
+
} while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
}
- /* reset the row above the image for the next pass */
+ /* Reset the row above the image for the next pass */
if (png_ptr->pass < 7)
{
if (png_ptr->prev_row != NULL)
- png_memset(png_ptr->prev_row, 0,
- (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
- png_ptr->usr_bit_depth,png_ptr->width))+1);
+ memset(png_ptr->prev_row, 0,
+ PNG_ROWBYTES(png_ptr->usr_channels *
+ png_ptr->usr_bit_depth, png_ptr->width) + 1);
+
return;
}
}
#endif
- /* if we get here, we've just written the last row, so we need
+ /* If we get here, we've just written the last row, so we need
to flush the compressor */
- do
- {
- /* tell the compressor we are done */
- ret = deflate(&png_ptr->zstream, Z_FINISH);
- /* check for an error */
- if (ret == Z_OK)
- {
- /* check to see if we need more room */
- if (!(png_ptr->zstream.avail_out))
- {
- png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- }
- }
- else if (ret != Z_STREAM_END)
- {
- if (png_ptr->zstream.msg != NULL)
- png_error(png_ptr, png_ptr->zstream.msg);
- else
- png_error(png_ptr, "zlib error");
- }
- } while (ret != Z_STREAM_END);
-
- /* write any extra space */
- if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
- {
- png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
- png_ptr->zstream.avail_out);
- }
-
- deflateReset(&png_ptr->zstream);
- png_ptr->zstream.data_type = Z_BINARY;
+ png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);
}
-#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Pick out the correct pixels for the interlace pass.
* The basic idea here is to go through the row with a source
* pointer and a destination pointer (sp and dp), and copy the
@@ -1943,32 +2095,27 @@ png_write_finish_row(png_structp png_ptr)
void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{
-#ifdef PNG_USE_LOCAL_ARRAYS
- /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
- /* start of interlace block */
- int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Start of interlace block */
+ static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
- /* offset to next interlace block */
- int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
-#endif
+ /* 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\n");
- /* we don't have to do anything on the last pass (6) */
-#if defined(PNG_USELESS_TESTS_SUPPORTED)
- if (row != NULL && row_info != NULL && pass < 6)
-#else
+ png_debug(1, "in png_do_write_interlace");
+
+ /* We don't have to do anything on the last pass (6) */
if (pass < 6)
-#endif
{
- /* each pixel depth is handled separately */
+ /* Each pixel depth is handled separately */
switch (row_info->pixel_depth)
{
case 1:
{
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -1977,10 +2124,11 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
dp = row;
d = 0;
shift = 7;
+
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
- sp = row + (png_size_t)(i >> 3);
+ sp = row + (size_t)(i >> 3);
value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
d |= (value << shift);
@@ -1990,19 +2138,22 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
*dp++ = (png_byte)d;
d = 0;
}
+
else
shift--;
}
if (shift != 7)
*dp = (png_byte)d;
+
break;
}
+
case 2:
{
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -2011,10 +2162,11 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
dp = row;
shift = 6;
d = 0;
+
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
- sp = row + (png_size_t)(i >> 2);
+ sp = row + (size_t)(i >> 2);
value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
d |= (value << shift);
@@ -2024,18 +2176,21 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
*dp++ = (png_byte)d;
d = 0;
}
+
else
shift -= 2;
}
if (shift != 6)
- *dp = (png_byte)d;
+ *dp = (png_byte)d;
+
break;
}
+
case 4:
{
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -2045,9 +2200,9 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
shift = 4;
d = 0;
for (i = png_pass_start[pass]; i < row_width;
- i += png_pass_inc[pass])
+ i += png_pass_inc[pass])
{
- sp = row + (png_size_t)(i >> 1);
+ sp = row + (size_t)(i >> 1);
value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
d |= (value << shift);
@@ -2057,83 +2212,361 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
*dp++ = (png_byte)d;
d = 0;
}
+
else
shift -= 4;
}
if (shift != 4)
*dp = (png_byte)d;
+
break;
}
+
default:
{
png_bytep sp;
png_bytep dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
- png_size_t pixel_bytes;
+ size_t pixel_bytes;
- /* start at the beginning */
+ /* Start at the beginning */
dp = row;
- /* find out how many bytes each pixel takes up */
+
+ /* Find out how many bytes each pixel takes up */
pixel_bytes = (row_info->pixel_depth >> 3);
- /* loop through the row, only looking at the pixels that
- matter */
+
+ /* Loop through the row, only looking at the pixels that matter */
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
- /* find out where the original pixel is */
- sp = row + (png_size_t)i * pixel_bytes;
- /* move the pixel */
+ /* Find out where the original pixel is */
+ sp = row + (size_t)i * pixel_bytes;
+
+ /* Move the pixel */
if (dp != sp)
- png_memcpy(dp, sp, pixel_bytes);
- /* next pixel */
+ memcpy(dp, sp, pixel_bytes);
+
+ /* Next pixel */
dp += pixel_bytes;
}
break;
}
}
- /* set new row width */
+ /* Set new row width */
row_info->width = (row_info->width +
- png_pass_inc[pass] - 1 -
- png_pass_start[pass]) /
- png_pass_inc[pass];
- row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
- row_info->width);
+ png_pass_inc[pass] - 1 -
+ png_pass_start[pass]) /
+ png_pass_inc[pass];
+
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
+ row_info->width);
}
}
#endif
+
/* This filters the row, chooses which filter to use, if it has not already
* been specified by the application, and then writes the row out with the
* chosen filter.
*/
-#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
-#define PNG_HISHIFT 10
-#define PNG_LOMASK ((png_uint_32)0xffffL)
-#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
-void /* PRIVATE */
-png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
+static void /* PRIVATE */
+png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
+ size_t row_bytes);
+
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+static size_t /* PRIVATE */
+png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes, size_t lmins)
{
- png_bytep best_row;
-#ifndef PNG_NO_WRITE_FILTER
- png_bytep prev_row, row_buf;
- png_uint_32 mins, bpp;
- png_byte filter_to_do = png_ptr->do_filter;
- png_uint_32 row_bytes = row_info->rowbytes;
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- int num_p_filters = (int)png_ptr->num_prev_filters;
+ png_bytep rp, dp, lp;
+ size_t i;
+ size_t sum = 0;
+ unsigned int v;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ v = *dp = *rp;
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+ }
+
+ for (lp = png_ptr->row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
- png_debug(1, "in png_write_find_filter\n");
- /* find out how many bytes offset each pixel is */
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+ return sum;
+}
+
+static void /* PRIVATE */
+png_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes)
+{
+ png_bytep rp, dp, lp;
+ size_t i;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ *dp = *rp;
+ }
+
+ for (lp = png_ptr->row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+}
+
+static size_t /* PRIVATE */
+png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins)
+{
+ png_bytep rp, dp, pp;
+ size_t i;
+ size_t sum = 0;
+ unsigned int v;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+ return sum;
+}
+static void /* PRIVATE */
+png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes)
+{
+ png_bytep rp, dp, pp;
+ size_t i;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+}
+
+static size_t /* PRIVATE */
+png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes, size_t lmins)
+{
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+ size_t sum = 0;
+ unsigned int v;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+ }
+
+ for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+ return sum;
+}
+static void /* PRIVATE */
+png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes)
+{
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+ }
+
+ for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+ }
+}
+
+static size_t /* PRIVATE */
+png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes, size_t lmins)
+{
+ png_bytep rp, dp, pp, cp, lp;
+ size_t i;
+ size_t sum = 0;
+ unsigned int v;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+ }
+
+ for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
+ i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+ return sum;
+}
+static void /* PRIVATE */
+png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp,
+ size_t row_bytes)
+{
+ png_bytep rp, dp, pp, cp, lp;
+ size_t i;
+
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
+
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+ }
+
+ for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
+ i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+ }
+}
+#endif /* WRITE_FILTER */
+
+void /* PRIVATE */
+png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
+{
+#ifndef PNG_WRITE_FILTER_SUPPORTED
+ png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1);
+#else
+ unsigned int filter_to_do = png_ptr->do_filter;
+ png_bytep row_buf;
+ png_bytep best_row;
+ png_uint_32 bpp;
+ size_t mins;
+ size_t row_bytes = row_info->rowbytes;
+
+ png_debug(1, "in png_write_find_filter");
+
+ /* Find out how many bytes offset each pixel is */
bpp = (row_info->pixel_depth + 7) >> 3;
- prev_row = png_ptr->prev_row;
-#endif
- best_row = png_ptr->row_buf;
-#ifndef PNG_NO_WRITE_FILTER
- row_buf = best_row;
- mins = PNG_MAXSUM;
+ row_buf = png_ptr->row_buf;
+ mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
+ running sum */;
/* The prediction method we use is to find which method provides the
* smallest value when summing the absolute values of the distances
@@ -2147,11 +2580,14 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
* computationally expensive).
*
* GRR 980525: consider also
+ *
* (1) minimum sum of absolute differences from running average (i.e.,
* keep running sum of non-absolute differences & count of bytes)
* [track dispersion, too? restart average if dispersion too large?]
+ *
* (1b) minimum sum of absolute differences from sliding average, probably
* with window size <= deflate window (usually 32K)
+ *
* (2) minimum sum of squared differences from zero or running average
* (i.e., ~ root-mean-square approach)
*/
@@ -2160,613 +2596,165 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
/* We don't need to test the 'no filter' case if this is the only filter
* that has been chosen, as it doesn't actually do anything to the data.
*/
- if ((filter_to_do & PNG_FILTER_NONE) &&
- filter_to_do != PNG_FILTER_NONE)
+ best_row = png_ptr->row_buf;
+
+ if (PNG_SIZE_MAX/128 <= row_bytes)
{
+ /* Overflow can occur in the calculation, just select the lowest set
+ * filter.
+ */
+ filter_to_do &= 0U-filter_to_do;
+ }
+ else if ((filter_to_do & PNG_FILTER_NONE) != 0 &&
+ filter_to_do != PNG_FILTER_NONE)
+ {
+ /* Overflow not possible and multiple filters in the list, including the
+ * 'none' filter.
+ */
png_bytep rp;
- png_uint_32 sum = 0;
- png_uint_32 i;
- int v;
+ size_t sum = 0;
+ size_t i;
+ unsigned int v;
- for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
- v = *rp;
- sum += (v < 128) ? v : 256 - v;
- }
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- png_uint_32 sumhi, sumlo;
- int j;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
-
- /* Reduce the sum if we match any of the previous rows */
- for (j = 0; j < num_p_filters; j++)
+ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- /* Factor in the cost of this filter (this is here for completeness,
- * but it makes no sense to have a "cost" for the NONE filter, as
- * it has the minimum possible computational cost - none).
- */
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
+ v = *rp;
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
+ }
+ }
+
mins = sum;
}
- /* sub filter */
+ /* Sub filter */
if (filter_to_do == PNG_FILTER_SUB)
- /* it's the only filter so no testing is needed */
+ /* It's the only filter so no testing is needed */
{
- png_bytep rp, lp, dp;
- png_uint_32 i;
- for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
- i++, rp++, dp++)
- {
- *dp = *rp;
- }
- for (lp = row_buf + 1; i < row_bytes;
- i++, rp++, lp++, dp++)
- {
- *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
- }
- best_row = png_ptr->sub_row;
+ png_setup_sub_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
}
- else if (filter_to_do & PNG_FILTER_SUB)
+ else if ((filter_to_do & PNG_FILTER_SUB) != 0)
{
- png_bytep rp, dp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_uint_32 i;
- int v;
+ size_t sum;
+ size_t lmins = mins;
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- /* We temporarily increase the "minimum sum" by the factor we
- * would reduce the sum of this filter, so that we can do the
- * early exit comparison without scaling the sum each time.
- */
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
- i++, rp++, dp++)
- {
- v = *dp = *rp;
-
- sum += (v < 128) ? v : 256 - v;
- }
- for (lp = row_buf + 1; i < row_bytes;
- i++, rp++, lp++, dp++)
- {
- v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
- sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);
if (sum < mins)
{
mins = sum;
- best_row = png_ptr->sub_row;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
}
- /* up filter */
+ /* Up filter */
if (filter_to_do == PNG_FILTER_UP)
{
- png_bytep rp, dp, pp;
- png_uint_32 i;
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
- pp = prev_row + 1; i < row_bytes;
- i++, rp++, pp++, dp++)
- {
- *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
- }
- best_row = png_ptr->up_row;
+ png_setup_up_row_only(png_ptr, row_bytes);
+ best_row = png_ptr->try_row;
}
- else if (filter_to_do & PNG_FILTER_UP)
+ else if ((filter_to_do & PNG_FILTER_UP) != 0)
{
- png_bytep rp, dp, pp;
- png_uint_32 sum = 0, lmins = mins;
- png_uint_32 i;
- int v;
+ size_t sum;
+ size_t lmins = mins;
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
- pp = prev_row + 1; i < row_bytes; i++)
- {
- v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ sum = png_setup_up_row(png_ptr, row_bytes, lmins);
if (sum < mins)
{
mins = sum;
- best_row = png_ptr->up_row;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
}
- /* avg filter */
+ /* Avg filter */
if (filter_to_do == PNG_FILTER_AVG)
{
- png_bytep rp, dp, pp, lp;
- png_uint_32 i;
- for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
- }
- for (lp = row_buf + 1; i < row_bytes; i++)
- {
- *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
- & 0xff);
- }
- best_row = png_ptr->avg_row;
+ png_setup_avg_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
}
- else if (filter_to_do & PNG_FILTER_AVG)
+ else if ((filter_to_do & PNG_FILTER_AVG) != 0)
{
- png_bytep rp, dp, pp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_uint_32 i;
- int v;
+ size_t sum;
+ size_t lmins = mins;
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
- }
- for (lp = row_buf + 1; i < row_bytes; i++)
- {
- v = *dp++ =
- (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);
if (sum < mins)
{
mins = sum;
- best_row = png_ptr->avg_row;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
}
/* Paeth filter */
if (filter_to_do == PNG_FILTER_PAETH)
{
- png_bytep rp, dp, pp, cp, lp;
- png_uint_32 i;
- for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
- }
-
- for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
- {
- int a, b, c, pa, pb, pc, p;
-
- b = *pp++;
- c = *cp++;
- a = *lp++;
-
- p = b - c;
- pc = a - c;
-
-#ifdef PNG_USE_ABS
- pa = abs(p);
- pb = abs(pc);
- pc = abs(p + pc);
-#else
- pa = p < 0 ? -p : p;
- pb = pc < 0 ? -pc : pc;
- pc = (p + pc) < 0 ? -(p + pc) : p + pc;
-#endif
-
- p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
-
- *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
- }
- best_row = png_ptr->paeth_row;
+ png_setup_paeth_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
}
- else if (filter_to_do & PNG_FILTER_PAETH)
+ else if ((filter_to_do & PNG_FILTER_PAETH) != 0)
{
- png_bytep rp, dp, pp, cp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_uint_32 i;
- int v;
+ size_t sum;
+ size_t lmins = mins;
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
- }
-
- for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
- {
- int a, b, c, pa, pb, pc, p;
-
- b = *pp++;
- c = *cp++;
- a = *lp++;
-
-#ifndef PNG_SLOW_PAETH
- p = b - c;
- pc = a - c;
-#ifdef PNG_USE_ABS
- pa = abs(p);
- pb = abs(pc);
- pc = abs(p + pc);
-#else
- pa = p < 0 ? -p : p;
- pb = pc < 0 ? -pc : pc;
- pc = (p + pc) < 0 ? -(p + pc) : p + pc;
-#endif
- p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
-#else /* PNG_SLOW_PAETH */
- p = a + b - c;
- pa = abs(p - a);
- pb = abs(p - b);
- pc = abs(p - c);
- if (pa <= pb && pa <= pc)
- p = a;
- else if (pb <= pc)
- p = b;
- else
- p = c;
-#endif /* PNG_SLOW_PAETH */
-
- v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
-
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);
if (sum < mins)
{
- best_row = png_ptr->paeth_row;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
}
-#endif /* PNG_NO_WRITE_FILTER */
+
/* Do the actual writing of the filtered row data from the chosen filter. */
+ png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
- png_write_filtered_row(png_ptr, best_row);
-
-#ifndef PNG_NO_WRITE_FILTER
-#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
- /* Save the type of filter we picked this time for future calculations */
- if (png_ptr->num_prev_filters > 0)
- {
- int j;
- for (j = 1; j < num_p_filters; j++)
- {
- png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
- }
- png_ptr->prev_filters[j] = best_row[0];
- }
-#endif
-#endif /* PNG_NO_WRITE_FILTER */
+#endif /* WRITE_FILTER */
}
/* Do the actual writing of a previously filtered row. */
-void /* PRIVATE */
-png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
+static void
+png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
+ size_t full_row_length/*includes filter byte*/)
{
- png_debug(1, "in png_write_filtered_row\n");
- png_debug1(2, "filter = %d\n", filtered_row[0]);
- /* set up the zlib input buffer */
+ png_debug(1, "in png_write_filtered_row");
- png_ptr->zstream.next_in = filtered_row;
- png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
- /* repeat until we have compressed all the data */
- do
- {
- int ret; /* return of zlib */
+ png_debug1(2, "filter = %d", filtered_row[0]);
- /* compress the data */
- ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
- /* check for compression errors */
- if (ret != Z_OK)
- {
- if (png_ptr->zstream.msg != NULL)
- png_error(png_ptr, png_ptr->zstream.msg);
- else
- png_error(png_ptr, "zlib error");
- }
+ png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);
- /* see if it is time to write another IDAT */
- if (!(png_ptr->zstream.avail_out))
- {
- /* write the IDAT and reset the zlib output buffer */
- png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- }
- /* repeat until all data has been compressed */
- } while (png_ptr->zstream.avail_in);
-
- /* swap the current and previous rows */
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ /* Swap the current and previous rows */
if (png_ptr->prev_row != NULL)
{
png_bytep tptr;
@@ -2775,11 +2763,12 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
png_ptr->prev_row = png_ptr->row_buf;
png_ptr->row_buf = tptr;
}
+#endif /* WRITE_FILTER */
- /* finish row - updates counters and flushes zlib if last row */
+ /* Finish row - updates counters and flushes zlib if last row */
png_write_finish_row(png_ptr);
-#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->flush_rows++;
if (png_ptr->flush_dist > 0 &&
@@ -2787,6 +2776,6 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
png_write_flush(png_ptr);
}
-#endif
+#endif /* WRITE_FLUSH */
}
-#endif /* PNG_WRITE_SUPPORTED */
+#endif /* WRITE */